From 46b3ba263124a8ce2658cb4674f655da565c035c Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Thu, 29 Oct 2015 22:18:52 +0100 Subject: [PATCH 001/210] remove obsolete if --- src/audio/audio.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 84bb94e52..cc6aa51b2 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -564,19 +564,16 @@ bool Audio::tryCaptureSamples(int16_t* buf, int samples) alcCaptureSamples(Audio::alInDev, buf, samples); - if (inputVolume != 1) + for (size_t i = 0; i < samples * AUDIO_CHANNELS; ++i) { - for (size_t i = 0; i < samples * AUDIO_CHANNELS; ++i) - { - int sample = buf[i] * pow(inputVolume, 2); + int sample = buf[i] * pow(inputVolume, 2); - if (sample < std::numeric_limits::min()) - sample = std::numeric_limits::min(); - else if (sample > std::numeric_limits::max()) - sample = std::numeric_limits::max(); + if (sample < std::numeric_limits::min()) + sample = std::numeric_limits::min(); + else if (sample > std::numeric_limits::max()) + sample = std::numeric_limits::max(); - buf[i] = sample; - } + buf[i] = sample; } return true; From e2966b1457575ef6c27dd01643f533c729b093b4 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sun, 25 Oct 2015 00:56:41 +0200 Subject: [PATCH 002/210] open output device on "subscribeInput" only when not already opened --- src/audio/audio.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index cc6aa51b2..b3315fcaf 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -140,7 +140,9 @@ void Audio::subscribeInput() if (!inputSubscriptions++) { openInput(Settings::getInstance().getInDev()); - openOutput(Settings::getInstance().getOutDev()); + if (!alOutDev) + openOutput(Settings::getInstance().getOutDev()); + #if (!FIX_SND_PCM_PREPARE_BUG) if (alInDev) From 26fc424986c682b2690ec0d16005f1ac9a904a25 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sun, 8 Nov 2015 17:19:14 +0100 Subject: [PATCH 003/210] use internal cleanup methods to close in-/output devices --- src/audio/audio.cpp | 105 +++++++++++++++++++++----------------------- src/audio/audio.h | 3 ++ 2 files changed, 54 insertions(+), 54 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index b3315fcaf..8f52ea765 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -162,15 +162,13 @@ If the input device has no more subscriptions, it will be closed. void Audio::unsubscribeInput() { qDebug() << "unsubscribing input" << inputSubscriptions; + QMutexLocker locker(&audioInLock); + if (inputSubscriptions > 0) inputSubscriptions--; - else if(inputSubscriptions < 0) - inputSubscriptions = 0; if (!inputSubscriptions) { - closeOutput(); - closeInput(); - } + cleanupInput(); } /** @@ -180,14 +178,7 @@ void Audio::openInput(const QString& inDevDescr) { QMutexLocker lock(&audioInLock); - if (alInDev) { -#if (!FIX_SND_PCM_PREPARE_BUG) - qDebug() << "stopping capture"; - alcCaptureStop(alInDev); -#endif - alcCaptureCloseDevice(alInDev); - } - alInDev = nullptr; + cleanupInput(); if (inDevDescr == "none") return; @@ -251,8 +242,8 @@ bool Audio::openOutput(const QString &outDevDescr) qDebug() << "Opening audio output " + outDevDescr; QMutexLocker lock(&audioOutLock); - auto* tmp = alOutDev; - alOutDev = nullptr; + cleanupOutput(); + if (outDevDescr != "none") { @@ -285,12 +276,6 @@ bool Audio::openOutput(const QString &outDevDescr) if (alOutDev) { - if (alContext && alcMakeContextCurrent(nullptr) == ALC_TRUE) - alcDestroyContext(alContext); - - if (tmp) - alcCloseDevice(tmp); - alContext = alcCreateContext(alOutDev, nullptr); if (alcMakeContextCurrent(alContext)) { @@ -328,23 +313,7 @@ void Audio::closeInput() { qDebug() << "Closing input"; QMutexLocker locker(&audioInLock); - if (alInDev) - { -#if (!FIX_SND_PCM_PREPARE_BUG) - qDebug() << "stopping capture"; - alcCaptureStop(alInDev); -#endif - - if (alcCaptureCloseDevice(alInDev) == ALC_TRUE) - { - alInDev = nullptr; - inputSubscriptions = 0; - } - else - { - qWarning() << "Failed to close input"; - } - } + cleanupInput(); } /** @@ -354,20 +323,7 @@ void Audio::closeOutput() { qDebug() << "Closing output"; QMutexLocker locker(&audioOutLock); - - if (alContext && alcMakeContextCurrent(nullptr) == ALC_TRUE) - { - alcDestroyContext(alContext); - alContext = nullptr; - } - - if (alOutDev) - { - if (alcCloseDevice(alOutDev) == ALC_TRUE) - alOutDev = nullptr; - else - qWarning() << "Failed to close output"; - } + cleanupOutput(); } /** @@ -429,8 +385,6 @@ void Audio::playGroupAudioQueued(void*,int group, int peer, const int16_t* data, emit static_cast(core)->groupPeerAudioPlaying(group, peer); } - - /** Must be called from the audio thread, plays a group call's received audio */ @@ -503,6 +457,49 @@ void Audio::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, u alSourcePlay(alSource); } +void Audio::cleanupInput() +{ + if (alInDev) + { +#if (!FIX_SND_PCM_PREPARE_BUG) + qDebug() << "stopping capture"; + alcCaptureStop(alInDev); +#endif + + if (alcCaptureCloseDevice(alInDev)) + { + alInDev = nullptr; + inputSubscriptions = 0; + } + else + { + qWarning() << "Failed to close input"; + } + } +} + +void Audio::cleanupOutput() +{ + if (inputSubscriptions) + cleanupInput(); + + if (alOutDev) { + alSourcei(alMainSource, AL_LOOPING, AL_FALSE); + alSourceStop(alMainSource); + alDeleteSources(1, &alMainSource); + + ALCdevice* device = alcGetContextsDevice(alContext); + if (!alcMakeContextCurrent(nullptr)) + qWarning("Failed to clear current audio context."); + + alcDestroyContext(alContext); + alContext = nullptr; + + if (!alcCloseDevice(device)) + qWarning("Failed to close output."); + } +} + /** Returns true if the input device is open and suscribed to */ diff --git a/src/audio/audio.h b/src/audio/audio.h index d8f24a780..8fbbd398d 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -106,6 +106,9 @@ private: Audio(); ~Audio(); + void cleanupInput(); + void cleanupOutput(); + private: static Audio* instance; From 2ce92be94be666c8dec9be85b4ed5c6d338f8a4e Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sat, 31 Oct 2015 13:04:49 +0100 Subject: [PATCH 004/210] do not close output in unsubscribeInput and cleanup input internally instead --- src/audio/audio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 8f52ea765..52f890fa9 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -167,7 +167,7 @@ void Audio::unsubscribeInput() if (inputSubscriptions > 0) inputSubscriptions--; - if (!inputSubscriptions) { + if (!inputSubscriptions) cleanupInput(); } From bde042ba3aa4ecce34030946a1f3a1af201840dc Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Wed, 21 Oct 2015 22:18:47 +0200 Subject: [PATCH 005/210] remove unused include and forward declarations --- src/audio/audio.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/audio/audio.h b/src/audio/audio.h index 8fbbd398d..da0b6f9c3 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -22,7 +22,6 @@ #define AUDIO_H #include -#include #include #include #include @@ -36,11 +35,7 @@ #include #endif -class QString; -class QByteArray; class QTimer; -class QThread; -class QMutex; struct Tox; class AudioFilterer; From c5f4ceee6bc2183284504340ed0f32769872b34f Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sun, 8 Nov 2015 06:00:05 +0100 Subject: [PATCH 006/210] fix Audio::subscribeInput Audio input/output device will only be opened, if not initialized already. --- src/audio/audio.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 52f890fa9..8f9e3cfab 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -137,21 +137,21 @@ If the input device is not open, it will be opened before capturing. void Audio::subscribeInput() { qDebug() << "subscribing input" << inputSubscriptions; - if (!inputSubscriptions++) - { + + if (!alInDev) { openInput(Settings::getInstance().getInDev()); - if (!alOutDev) - openOutput(Settings::getInstance().getOutDev()); - - #if (!FIX_SND_PCM_PREPARE_BUG) - if (alInDev) - { + if (alInDev) { qDebug() << "starting capture"; alcCaptureStart(alInDev); } #endif } + + if (!alOutDev) + openOutput(Settings::getInstance().getOutDev()); + + inputSubscriptions++; } /** From e8a4f6511d08f9b25d5c057cd59a2b107bc82cdb Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sun, 8 Nov 2015 21:03:33 +0100 Subject: [PATCH 007/210] use internal methods to open in/out audio devices --- src/audio/audio.cpp | 76 +++++++++++++++++++++------------------------ src/audio/audio.h | 2 ++ 2 files changed, 38 insertions(+), 40 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 8f9e3cfab..e2b57b98d 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -136,22 +136,12 @@ If the input device is not open, it will be opened before capturing. */ void Audio::subscribeInput() { - qDebug() << "subscribing input" << inputSubscriptions; - - if (!alInDev) { - openInput(Settings::getInstance().getInDev()); -#if (!FIX_SND_PCM_PREPARE_BUG) - if (alInDev) { - qDebug() << "starting capture"; - alcCaptureStart(alInDev); - } -#endif - } - - if (!alOutDev) - openOutput(Settings::getInstance().getOutDev()); + QMutexLocker locker(&audioInLock); + if (!alInDev) + initInput(Settings::getInstance().getInDev()); inputSubscriptions++; + qDebug() << "Subscribed to audio input device [" << inputSubscriptions << " subscriptions ]"; } /** @@ -177,12 +167,18 @@ Open an input device, use before suscribing void Audio::openInput(const QString& inDevDescr) { QMutexLocker lock(&audioInLock); + initInput(inDevDescr); +} - cleanupInput(); +void Audio::initInput(const QString& inDevDescr) +{ + qDebug() << "Opening audio input" << inDevDescr; if (inDevDescr == "none") return; + assert(!alInDev); + /// TODO: Try to actually detect if our audio source is stereo int stereoFlag = AUDIO_CHANNELS == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16; const uint32_t sampleRate = AUDIO_SAMPLE_RATE; @@ -213,9 +209,9 @@ void Audio::openInput(const QString& inDevDescr) sampleRate, stereoFlag, bufSize); if (alInDev) - qDebug() << "Opening audio input "<getAv()->resetCallSources(); // Force to regen each group call's sources - return (bool)alOutDev; + return alOutDev; } /** @@ -335,7 +331,7 @@ void Audio::playMono16Sound(const QByteArray& data) if (!alOutDev) { - if (!openOutput(Settings::getInstance().getOutDev())) + if (!initOutput(Settings::getInstance().getOutDev())) return; } diff --git a/src/audio/audio.h b/src/audio/audio.h index da0b6f9c3..7db301a58 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -101,6 +101,8 @@ private: Audio(); ~Audio(); + void initInput(const QString& inDevDescr); + bool initOutput(const QString& outDevDescr); void cleanupInput(); void cleanupOutput(); From c540faf27171fcde42f3a293ae6a9049d3e86cc1 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sun, 8 Nov 2015 21:05:34 +0100 Subject: [PATCH 008/210] add method to un-/subscribe to audio output as well --- src/audio/audio.cpp | 24 ++++++++++++++++++++++++ src/audio/audio.h | 3 +++ 2 files changed, 27 insertions(+) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index e2b57b98d..379c6bdfb 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -59,6 +59,7 @@ Audio::Audio() , audioInLock(QMutex::Recursive) , audioOutLock(QMutex::Recursive) , inputSubscriptions(0) + , outputSubscriptions(0) , alOutDev(nullptr) , alInDev(nullptr) , outputVolume(1.0) @@ -161,6 +162,29 @@ void Audio::unsubscribeInput() cleanupInput(); } +void Audio::subscribeOutput() +{ + QMutexLocker locker(&audioOutLock); + + if (!alOutDev) + initOutput(Settings::getInstance().getOutDev()); + + outputSubscriptions++; + qDebug() << "Subscribed to audio output device [" << outputSubscriptions << " subscriptions ]"; +} + +void Audio::unsubscribeOutput() +{ + if (outputSubscriptions > 0) + { + outputSubscriptions--; + qDebug() << "Unsubscribed from audio output device [" << outputSubscriptions << " subscriptions]"; + } + + if (!outputSubscriptions) + cleanupOutput(); +} + /** Open an input device, use before suscribing */ diff --git a/src/audio/audio.h b/src/audio/audio.h index 7db301a58..e3039e42e 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -62,6 +62,8 @@ public: void subscribeInput(); void unsubscribeInput(); + void subscribeOutput(); + void unsubscribeOutput(); void openInput(const QString& inDevDescr); bool openOutput(const QString& outDevDescr); @@ -114,6 +116,7 @@ private: QMutex audioInLock; QMutex audioOutLock; std::atomic inputSubscriptions; + std::atomic outputSubscriptions; ALCdevice* alOutDev; ALCdevice* alInDev; qreal outputVolume; From efda47a22653c3b293c78b326974cbff5bec4647 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sun, 8 Nov 2015 21:06:44 +0100 Subject: [PATCH 009/210] close audio output in destructor --- src/audio/audio.cpp | 2 ++ src/core/core.cpp | 4 ---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 379c6bdfb..eab8e65fb 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -73,6 +73,8 @@ Audio::Audio() Audio::~Audio() { + closeInput(); + closeOutput(); audioThread->exit(); audioThread->wait(); if (audioThread->isRunning()) diff --git a/src/core/core.cpp b/src/core/core.cpp index 0f18b63f5..2aabd8eaa 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -106,10 +106,6 @@ Core::~Core() } deadifyTox(); - - Audio& audio = Audio::getInstance(); - audio.closeInput(); - audio.closeOutput(); } Core* Core::getInstance() From 7b98f2a4a0aa75cacd9e33a79210f9295418aadf Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sun, 8 Nov 2015 21:08:55 +0100 Subject: [PATCH 010/210] cleanup close audio device --- src/audio/audio.cpp | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index eab8e65fb..ae205adf4 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -154,11 +154,13 @@ If the input device has no more subscriptions, it will be closed. */ void Audio::unsubscribeInput() { - qDebug() << "unsubscribing input" << inputSubscriptions; QMutexLocker locker(&audioInLock); if (inputSubscriptions > 0) + { inputSubscriptions--; + qDebug() << "Unsubscribed from audio input device [" << inputSubscriptions << " subscriptions]"; + } if (!inputSubscriptions) cleanupInput(); @@ -333,7 +335,6 @@ Close an input device, please don't use unless everyone's unsuscribed */ void Audio::closeInput() { - qDebug() << "Closing input"; QMutexLocker locker(&audioInLock); cleanupInput(); } @@ -343,7 +344,6 @@ Close an output device */ void Audio::closeOutput() { - qDebug() << "Closing output"; QMutexLocker locker(&audioOutLock); cleanupOutput(); } @@ -484,28 +484,22 @@ void Audio::cleanupInput() if (alInDev) { #if (!FIX_SND_PCM_PREPARE_BUG) - qDebug() << "stopping capture"; + qDebug() << "stopping audio capture"; alcCaptureStop(alInDev); #endif - if (alcCaptureCloseDevice(alInDev)) - { + qDebug() << "Closing audio input"; + if (alcCaptureCloseDevice(alInDev) == ALC_TRUE) alInDev = nullptr; - inputSubscriptions = 0; - } else - { qWarning() << "Failed to close input"; - } } } void Audio::cleanupOutput() { - if (inputSubscriptions) - cleanupInput(); - if (alOutDev) { + qDebug() << "Closing audio output"; alSourcei(alMainSource, AL_LOOPING, AL_FALSE); alSourceStop(alMainSource); alDeleteSources(1, &alMainSource); @@ -517,7 +511,9 @@ void Audio::cleanupOutput() alcDestroyContext(alContext); alContext = nullptr; - if (!alcCloseDevice(device)) + if (alcCloseDevice(device)) + alOutDev = nullptr; + else qWarning("Failed to close output."); } } @@ -528,7 +524,7 @@ Returns true if the input device is open and suscribed to bool Audio::isInputReady() { QMutexLocker locker(&audioInLock); - return alInDev && inputSubscriptions; + return alInDev; } bool Audio::isInputSubscribed() From ad6e0a85f5008f138cfab3e49bba8c029da42ca4 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sun, 8 Nov 2015 21:09:38 +0100 Subject: [PATCH 011/210] add method to reinit audio in/out --- src/audio/audio.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/audio/audio.h b/src/audio/audio.h index e3039e42e..e4e3b538b 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -67,6 +67,19 @@ public: void openInput(const QString& inDevDescr); bool openOutput(const QString& outDevDescr); + inline void reinitInput(const QString& inDevDesc) + { + QMutexLocker locker(&audioInLock); + cleanupInput(); + initInput(inDevDesc); + } + inline bool reinitOutput(const QString& outDevDesc) + { + QMutexLocker locker(&audioOutLock); + cleanupOutput(); + return initOutput(outDevDesc); + } + bool isInputReady(); bool isInputSubscribed(); bool isOutputReady(); From 32bc99fb383f87340e08ee08db886c2d1043b20a Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sun, 8 Nov 2015 21:11:03 +0100 Subject: [PATCH 012/210] cleanup reinitialization of changed audio in/out --- src/audio/audio.cpp | 6 ------ src/audio/audio.h | 1 - src/widget/form/settings/avform.cpp | 11 ++++------- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index ae205adf4..9c701bfb4 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -527,12 +527,6 @@ bool Audio::isInputReady() return alInDev; } -bool Audio::isInputSubscribed() -{ - // No lock, inputSubscriptions is atomic! - return inputSubscriptions; -} - /** Returns true if the output device is open */ diff --git a/src/audio/audio.h b/src/audio/audio.h index e4e3b538b..48bf10c3b 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -81,7 +81,6 @@ public: } bool isInputReady(); - bool isInputSubscribed(); bool isOutputReady(); static void createSource(ALuint* source); diff --git a/src/widget/form/settings/avform.cpp b/src/widget/form/settings/avform.cpp index cb67e4e95..01663e111 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -335,21 +335,18 @@ void AVForm::onInDevChanged(QString deviceDescriptor) { if (!bodyUI->inDevCombobox->currentIndex()) deviceDescriptor = "none"; - Settings::getInstance().setInDev(deviceDescriptor); - Audio& audio = Audio::getInstance(); - if (audio.isInputSubscribed()) - audio.openInput(deviceDescriptor); + Settings::getInstance().setInDev(deviceDescriptor); + Audio::getInstance().reinitInput(deviceDescriptor); } void AVForm::onOutDevChanged(QString deviceDescriptor) { if (!bodyUI->outDevCombobox->currentIndex()) deviceDescriptor = "none"; - Settings::getInstance().setOutDev(deviceDescriptor); - Audio& audio = Audio::getInstance(); - audio.openOutput(deviceDescriptor); + Settings::getInstance().setOutDev(deviceDescriptor); + Audio::getInstance().reinitOutput(deviceDescriptor); } void AVForm::onFilterAudioToggled(bool filterAudio) From e7f666be7738309a43b6a133cc6cae70cc63f527 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sun, 8 Nov 2015 21:13:01 +0100 Subject: [PATCH 013/210] un-/subscribe audio in/out in tox-call --- src/core/toxcall.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/core/toxcall.cpp b/src/core/toxcall.cpp index e892f11f0..604ea1e26 100644 --- a/src/core/toxcall.cpp +++ b/src/core/toxcall.cpp @@ -20,7 +20,9 @@ ToxCall::ToxCall(uint32_t CallId) sendAudioTimer->setInterval(5); sendAudioTimer->setSingleShot(true); - Audio::getInstance().subscribeInput(); + Audio& audio = Audio::getInstance(); + audio.subscribeInput(); + audio.subscribeOutput(); #ifdef QTOX_FILTER_AUDIO if (Settings::getInstance().getFilterAudio()) @@ -56,7 +58,9 @@ ToxCall::~ToxCall() { QObject::disconnect(sendAudioTimer, nullptr, nullptr, nullptr); sendAudioTimer->stop(); - Audio::getInstance().unsubscribeInput(); + Audio& audio = Audio::getInstance(); + audio.unsubscribeInput(); + audio.unsubscribeOutput(); } if (alSource) From 872be362250ca87e24084d422487169f8ae859c2 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sun, 8 Nov 2015 21:13:46 +0100 Subject: [PATCH 014/210] un-/subscribe audio in/out in AV-Settings form --- src/widget/form/settings/avform.cpp | 8 ++++++-- src/widget/tool/micfeedbackwidget.cpp | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/widget/form/settings/avform.cpp b/src/widget/form/settings/avform.cpp index 01663e111..46b9a26ca 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -104,7 +104,9 @@ void AVForm::showEvent(QShowEvent*) getAudioInDevices(); createVideoSurface(); getVideoDevices(); - Audio::getInstance().subscribeInput(); + Audio& audio = Audio::getInstance(); + audio.subscribeInput(); + audio.subscribeOutput(); } void AVForm::onVideoModesIndexChanged(int index) @@ -241,7 +243,9 @@ void AVForm::hideEvent(QHideEvent *) killVideoSurface(); } videoDeviceList.clear(); - Audio::getInstance().unsubscribeInput(); + Audio& audio = Audio::getInstance(); + audio.unsubscribeInput(); + audio.unsubscribeOutput(); } void AVForm::getVideoDevices() diff --git a/src/widget/tool/micfeedbackwidget.cpp b/src/widget/tool/micfeedbackwidget.cpp index 3b6a82c39..95b2d6f8e 100644 --- a/src/widget/tool/micfeedbackwidget.cpp +++ b/src/widget/tool/micfeedbackwidget.cpp @@ -85,13 +85,17 @@ void MicFeedbackWidget::timerEvent(QTimerEvent*) void MicFeedbackWidget::showEvent(QShowEvent*) { - Audio::getInstance().subscribeInput(); + Audio& audio = Audio::getInstance(); + audio.subscribeInput(); + audio.subscribeOutput(); timerId = startTimer(60); } void MicFeedbackWidget::hideEvent(QHideEvent*) { - Audio::getInstance().unsubscribeInput(); + Audio& audio = Audio::getInstance(); + audio.unsubscribeInput(); + audio.unsubscribeOutput(); if (timerId != 0) { From d631ddbc86e2635de367826dc7229932d7fac704 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sun, 8 Nov 2015 22:23:01 +0100 Subject: [PATCH 015/210] cleanup close audio out device --- src/audio/audio.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 9c701bfb4..535d3feda 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -504,14 +504,13 @@ void Audio::cleanupOutput() alSourceStop(alMainSource); alDeleteSources(1, &alMainSource); - ALCdevice* device = alcGetContextsDevice(alContext); if (!alcMakeContextCurrent(nullptr)) qWarning("Failed to clear current audio context."); alcDestroyContext(alContext); alContext = nullptr; - if (alcCloseDevice(device)) + if (alcCloseDevice(alOutDev)) alOutDev = nullptr; else qWarning("Failed to close output."); From d233c6f6993e6d35aac2c1ca5283805719c0980b Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sun, 8 Nov 2015 22:23:36 +0100 Subject: [PATCH 016/210] cleanup audio out device on error after open --- src/audio/audio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 535d3feda..508a29274 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -313,7 +313,7 @@ bool Audio::initOutput(const QString& outDevDescr) else { qWarning() << "Cannot create output audio context"; - alcCloseDevice(alOutDev); + cleanupOutput(); return false; } } From f6c09104e40a45e3b2306cf411edb2e30554891f Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Thu, 12 Nov 2015 23:08:17 +0100 Subject: [PATCH 017/210] fix noise (clipping) while (re-)initializing in/out audio device --- src/audio/audio.cpp | 40 ++++++++++++++++++++++++++-------------- src/audio/audio.h | 2 ++ 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 508a29274..44028ae11 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -62,6 +62,8 @@ Audio::Audio() , outputSubscriptions(0) , alOutDev(nullptr) , alInDev(nullptr) + , mInputInitialized(false) + , mOutputInitialized(false) , outputVolume(1.0) , inputVolume(1.0) , alMainSource(0) @@ -202,6 +204,7 @@ void Audio::initInput(const QString& inDevDescr) { qDebug() << "Opening audio input" << inDevDescr; + mInputInitialized = false; if (inDevDescr == "none") return; @@ -256,6 +259,8 @@ void Audio::initInput(const QString& inDevDescr) alcCaptureStart(alInDev); #endif } + + mInputInitialized = true; } /** @@ -271,6 +276,7 @@ bool Audio::initOutput(const QString& outDevDescr) { qDebug() << "Opening audio output" << outDevDescr; + mOutputInitialized = false; if (outDevDescr == "none") return true; @@ -316,18 +322,17 @@ bool Audio::initOutput(const QString& outDevDescr) cleanupOutput(); return false; } - } - else - { - qWarning() << "Cannot open output audio device" << outDevDescr; - return false; + + Core* core = Core::getInstance(); + if (core) + core->getAv()->resetCallSources(); // Force to regen each group call's sources + + mOutputInitialized = true; + return true; } - Core* core = Core::getInstance(); - if (core) - core->getAv()->resetCallSources(); // Force to regen each group call's sources - - return alOutDev; + qWarning() << "Cannot open output audio device" << outDevDescr; + return false; } /** @@ -481,6 +486,8 @@ void Audio::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, u void Audio::cleanupInput() { + mInputInitialized = false; + if (alInDev) { #if (!FIX_SND_PCM_PREPARE_BUG) @@ -498,6 +505,8 @@ void Audio::cleanupInput() void Audio::cleanupOutput() { + mOutputInitialized = false; + if (alOutDev) { qDebug() << "Closing audio output"; alSourcei(alMainSource, AL_LOOPING, AL_FALSE); @@ -523,7 +532,7 @@ Returns true if the input device is open and suscribed to bool Audio::isInputReady() { QMutexLocker locker(&audioInLock); - return alInDev; + return alInDev && mInputInitialized; } /** @@ -532,7 +541,7 @@ Returns true if the output device is open bool Audio::isOutputReady() { QMutexLocker locker(&audioOutLock); - return alOutDev; + return alOutDev && mOutputInitialized; } void Audio::createSource(ALuint* source) @@ -567,12 +576,15 @@ bool Audio::tryCaptureSamples(int16_t* buf, int samples) { QMutexLocker lock(&audioInLock); + if (!(alInDev && mInputInitialized)) + return false; + ALint curSamples=0; - alcGetIntegerv(Audio::alInDev, ALC_CAPTURE_SAMPLES, sizeof(curSamples), &curSamples); + alcGetIntegerv(alInDev, ALC_CAPTURE_SAMPLES, sizeof(curSamples), &curSamples); if (curSamples < samples) return false; - alcCaptureSamples(Audio::alInDev, buf, samples); + alcCaptureSamples(alInDev, buf, samples); for (size_t i = 0; i < samples * AUDIO_CHANNELS; ++i) { diff --git a/src/audio/audio.h b/src/audio/audio.h index 48bf10c3b..295ee3545 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -131,6 +131,8 @@ private: std::atomic outputSubscriptions; ALCdevice* alOutDev; ALCdevice* alInDev; + bool mInputInitialized; + bool mOutputInitialized; qreal outputVolume; qreal inputVolume; ALuint alMainSource; From 68e7aef916e74bbf09843a085bed15ecd8bb4313 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Wed, 11 Nov 2015 01:30:41 +0100 Subject: [PATCH 018/210] privatized open/close audio devices --- src/audio/audio.cpp | 61 +++++++++++++++------------------------------ src/audio/audio.h | 15 +++++------ 2 files changed, 26 insertions(+), 50 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 44028ae11..23177ee12 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -75,12 +75,12 @@ Audio::Audio() Audio::~Audio() { - closeInput(); - closeOutput(); audioThread->exit(); audioThread->wait(); if (audioThread->isRunning()) audioThread->terminate(); + cleanupInput(); + cleanupOutput(); } /** @@ -171,7 +171,11 @@ void Audio::unsubscribeInput() void Audio::subscribeOutput() { QMutexLocker locker(&audioOutLock); + internalSubscribeOutput(); +} +void Audio::internalSubscribeOutput() +{ if (!alOutDev) initOutput(Settings::getInstance().getOutDev()); @@ -191,15 +195,6 @@ void Audio::unsubscribeOutput() cleanupOutput(); } -/** -Open an input device, use before suscribing -*/ -void Audio::openInput(const QString& inDevDescr) -{ - QMutexLocker lock(&audioInLock); - initInput(inDevDescr); -} - void Audio::initInput(const QString& inDevDescr) { qDebug() << "Opening audio input" << inDevDescr; @@ -264,14 +259,10 @@ void Audio::initInput(const QString& inDevDescr) } /** -Open an output device -*/ -bool Audio::openOutput(const QString &outDevDescr) -{ - QMutexLocker lock(&audioOutLock); - return initOutput(outDevDescr); -} +@internal +Open an audio output device +*/ bool Audio::initOutput(const QString& outDevDescr) { qDebug() << "Opening audio output" << outDevDescr; @@ -335,24 +326,6 @@ bool Audio::initOutput(const QString& outDevDescr) return false; } -/** -Close an input device, please don't use unless everyone's unsuscribed -*/ -void Audio::closeInput() -{ - QMutexLocker locker(&audioInLock); - cleanupInput(); -} - -/** -Close an output device -*/ -void Audio::closeOutput() -{ - QMutexLocker locker(&audioOutLock); - cleanupOutput(); -} - /** Play a 44100Hz mono 16bit PCM sound */ @@ -360,11 +333,7 @@ void Audio::playMono16Sound(const QByteArray& data) { QMutexLocker lock(&audioOutLock); - if (!alOutDev) - { - if (!initOutput(Settings::getInstance().getOutDev())) - return; - } + internalSubscribeOutput(); ALuint buffer; alGenBuffers(1, &buffer); @@ -484,6 +453,11 @@ void Audio::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, u alSourcePlay(alSource); } +/** +@internal + +Close active audio input device. +*/ void Audio::cleanupInput() { mInputInitialized = false; @@ -503,6 +477,11 @@ void Audio::cleanupInput() } } +/** +@internal + +Close active audio output device +*/ void Audio::cleanupOutput() { mOutputInitialized = false; diff --git a/src/audio/audio.h b/src/audio/audio.h index 295ee3545..9d4c7d5ce 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -60,13 +60,6 @@ public: void setInputVolume(qreal volume); - void subscribeInput(); - void unsubscribeInput(); - void subscribeOutput(); - void unsubscribeOutput(); - void openInput(const QString& inDevDescr); - bool openOutput(const QString& outDevDescr); - inline void reinitInput(const QString& inDevDesc) { QMutexLocker locker(&audioInLock); @@ -103,8 +96,10 @@ public: #endif public slots: - void closeInput(); - void closeOutput(); + void subscribeInput(); + void subscribeOutput(); + void unsubscribeInput(); + void unsubscribeOutput(); void playGroupAudio(int group, int peer, const int16_t* data, unsigned samples, uint8_t channels, unsigned sample_rate); @@ -115,6 +110,8 @@ private: Audio(); ~Audio(); + void internalSubscribeOutput(); + void initInput(const QString& inDevDescr); bool initOutput(const QString& outDevDescr); void cleanupInput(); From 9627f45014402c6a20d1d896a84c1ea3512d61da Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Wed, 11 Nov 2015 01:32:05 +0100 Subject: [PATCH 019/210] don't extra-subscribe audio gain metering widget --- src/widget/tool/micfeedbackwidget.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/widget/tool/micfeedbackwidget.cpp b/src/widget/tool/micfeedbackwidget.cpp index 95b2d6f8e..9fa8b6ec6 100644 --- a/src/widget/tool/micfeedbackwidget.cpp +++ b/src/widget/tool/micfeedbackwidget.cpp @@ -85,18 +85,11 @@ void MicFeedbackWidget::timerEvent(QTimerEvent*) void MicFeedbackWidget::showEvent(QShowEvent*) { - Audio& audio = Audio::getInstance(); - audio.subscribeInput(); - audio.subscribeOutput(); timerId = startTimer(60); } void MicFeedbackWidget::hideEvent(QHideEvent*) { - Audio& audio = Audio::getInstance(); - audio.unsubscribeInput(); - audio.unsubscribeOutput(); - if (timerId != 0) { killTimer(timerId); From 137eca86d625f34b7bd36d456e050a7391e2398a Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sat, 14 Nov 2015 10:08:58 +0100 Subject: [PATCH 020/210] use single mutex for audio resource locking --- src/audio/audio.cpp | 30 ++++++++++++++++-------------- src/audio/audio.h | 7 +++---- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 23177ee12..a921ad55d 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -56,8 +56,6 @@ Audio& Audio::getInstance() Audio::Audio() : audioThread(new QThread()) - , audioInLock(QMutex::Recursive) - , audioOutLock(QMutex::Recursive) , inputSubscriptions(0) , outputSubscriptions(0) , alOutDev(nullptr) @@ -101,7 +99,7 @@ Returns the current output volume, between 0 and 1 */ qreal Audio::getOutputVolume() { - QMutexLocker locker(&audioOutLock); + QMutexLocker locker(&mAudioLock); return outputVolume; } @@ -110,7 +108,8 @@ The volume must be between 0 and 1 */ void Audio::setOutputVolume(qreal volume) { - QMutexLocker locker(&audioOutLock); + QMutexLocker locker(&mAudioLock); + outputVolume = volume; alSourcef(alMainSource, AL_GAIN, outputVolume); @@ -130,7 +129,7 @@ The volume must be between 0 and 2 */ void Audio::setInputVolume(qreal volume) { - QMutexLocker locker(&audioInLock); + QMutexLocker locker(&mAudioLock); inputVolume = volume; } @@ -141,7 +140,8 @@ If the input device is not open, it will be opened before capturing. */ void Audio::subscribeInput() { - QMutexLocker locker(&audioInLock); + QMutexLocker locker(&mAudioLock); + if (!alInDev) initInput(Settings::getInstance().getInDev()); @@ -156,7 +156,7 @@ If the input device has no more subscriptions, it will be closed. */ void Audio::unsubscribeInput() { - QMutexLocker locker(&audioInLock); + QMutexLocker locker(&mAudioLock); if (inputSubscriptions > 0) { @@ -170,7 +170,7 @@ void Audio::unsubscribeInput() void Audio::subscribeOutput() { - QMutexLocker locker(&audioOutLock); + QMutexLocker locker(&mAudioLock); internalSubscribeOutput(); } @@ -185,6 +185,8 @@ void Audio::internalSubscribeOutput() void Audio::unsubscribeOutput() { + QMutexLocker locker(&mAudioLock); + if (outputSubscriptions > 0) { outputSubscriptions--; @@ -331,7 +333,7 @@ Play a 44100Hz mono 16bit PCM sound */ void Audio::playMono16Sound(const QByteArray& data) { - QMutexLocker lock(&audioOutLock); + QMutexLocker locker(&mAudioLock); internalSubscribeOutput(); @@ -388,7 +390,7 @@ void Audio::playGroupAudio(int group, int peer, const int16_t* data, unsigned samples, uint8_t channels, unsigned sample_rate) { assert(QThread::currentThread() == audioThread); - QMutexLocker lock(&audioOutLock); + QMutexLocker locker(&mAudioLock); if (!CoreAV::groupCalls.contains(group)) return; @@ -418,7 +420,7 @@ void Audio::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, u { assert(channels == 1 || channels == 2); - QMutexLocker lock(&getInstance().audioOutLock); + QMutexLocker locker(&getInstance().mAudioLock); ALuint bufid; ALint processed = 0, queued = 16; @@ -510,7 +512,7 @@ Returns true if the input device is open and suscribed to */ bool Audio::isInputReady() { - QMutexLocker locker(&audioInLock); + QMutexLocker locker(&mAudioLock); return alInDev && mInputInitialized; } @@ -519,7 +521,7 @@ Returns true if the output device is open */ bool Audio::isOutputReady() { - QMutexLocker locker(&audioOutLock); + QMutexLocker locker(&mAudioLock); return alOutDev && mOutputInitialized; } @@ -553,7 +555,7 @@ Does nothing and return false on failure */ bool Audio::tryCaptureSamples(int16_t* buf, int samples) { - QMutexLocker lock(&audioInLock); + QMutexLocker lock(&mAudioLock); if (!(alInDev && mInputInitialized)) return false; diff --git a/src/audio/audio.h b/src/audio/audio.h index 9d4c7d5ce..b8ba2f069 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -62,13 +62,13 @@ public: inline void reinitInput(const QString& inDevDesc) { - QMutexLocker locker(&audioInLock); + QMutexLocker locker(&mAudioLock); cleanupInput(); initInput(inDevDesc); } inline bool reinitOutput(const QString& outDevDesc) { - QMutexLocker locker(&audioOutLock); + QMutexLocker locker(&mAudioLock); cleanupOutput(); return initOutput(outDevDesc); } @@ -122,10 +122,9 @@ private: private: QThread* audioThread; - QMutex audioInLock; - QMutex audioOutLock; std::atomic inputSubscriptions; std::atomic outputSubscriptions; + QMutex mAudioLock; ALCdevice* alOutDev; ALCdevice* alInDev; bool mInputInitialized; From c23cb0043fe3fafa7575f592dbf29d18d8917ea6 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sat, 14 Nov 2015 21:02:29 +0100 Subject: [PATCH 021/210] implement actual audio in/out subscription management --- src/audio/audio.cpp | 50 ++++++++++++++--------------- src/audio/audio.h | 18 +++++------ src/core/toxcall.cpp | 8 ++--- src/widget/form/settings/avform.cpp | 8 ++--- 4 files changed, 41 insertions(+), 43 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index a921ad55d..592556606 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -32,7 +32,6 @@ #include "src/core/coreav.h" #include -#include #include #include #include @@ -56,8 +55,6 @@ Audio& Audio::getInstance() Audio::Audio() : audioThread(new QThread()) - , inputSubscriptions(0) - , outputSubscriptions(0) , alOutDev(nullptr) , alInDev(nullptr) , mInputInitialized(false) @@ -138,15 +135,17 @@ void Audio::setInputVolume(qreal volume) If the input device is not open, it will be opened before capturing. */ -void Audio::subscribeInput() +void Audio::subscribeInput(const void* inListener) { QMutexLocker locker(&mAudioLock); if (!alInDev) initInput(Settings::getInstance().getInDev()); - inputSubscriptions++; - qDebug() << "Subscribed to audio input device [" << inputSubscriptions << " subscriptions ]"; + if (!inputSubscriptions.contains(inListener)) { + inputSubscriptions << inListener; + qDebug() << "Subscribed to audio input device [" << inputSubscriptions.size() << "subscriptions ]"; + } } /** @@ -154,46 +153,44 @@ void Audio::subscribeInput() If the input device has no more subscriptions, it will be closed. */ -void Audio::unsubscribeInput() +void Audio::unsubscribeInput(const void* inListener) { QMutexLocker locker(&mAudioLock); - if (inputSubscriptions > 0) + if (inListener && inputSubscriptions.size()) { - inputSubscriptions--; - qDebug() << "Unsubscribed from audio input device [" << inputSubscriptions << " subscriptions]"; + inputSubscriptions.removeOne(inListener); + qDebug() << "Unsubscribed from audio input device [" << inputSubscriptions.size() << "subscriptions left ]"; } - if (!inputSubscriptions) + if (inputSubscriptions.isEmpty()) cleanupInput(); } -void Audio::subscribeOutput() +void Audio::subscribeOutput(const void* outListener) { QMutexLocker locker(&mAudioLock); - internalSubscribeOutput(); -} -void Audio::internalSubscribeOutput() -{ if (!alOutDev) initOutput(Settings::getInstance().getOutDev()); - outputSubscriptions++; - qDebug() << "Subscribed to audio output device [" << outputSubscriptions << " subscriptions ]"; + if (!outputSubscriptions.contains(outListener)) { + outputSubscriptions << outListener; + qDebug() << "Subscribed to audio output device [" << outputSubscriptions.size() << "subscriptions ]"; + } } -void Audio::unsubscribeOutput() +void Audio::unsubscribeOutput(const void* outListener) { QMutexLocker locker(&mAudioLock); - if (outputSubscriptions > 0) + if (outListener && outputSubscriptions.size()) { - outputSubscriptions--; - qDebug() << "Unsubscribed from audio output device [" << outputSubscriptions << " subscriptions]"; + outputSubscriptions.removeOne(outListener); + qDebug() << "Unsubscribed from audio output device [" << outputSubscriptions.size() << " subscriptions left ]"; } - if (!outputSubscriptions) + if (outputSubscriptions.isEmpty()) cleanupOutput(); } @@ -335,7 +332,8 @@ void Audio::playMono16Sound(const QByteArray& data) { QMutexLocker locker(&mAudioLock); - internalSubscribeOutput(); + if (!alOutDev) + initOutput(Settings::getInstance().getOutDev()); ALuint buffer; alGenBuffers(1, &buffer); @@ -351,12 +349,14 @@ void Audio::playMono16Sound(const QByteArray& data) alGetBufferi(buffer, AL_SIZE, &sizeInBytes); alGetBufferi(buffer, AL_CHANNELS, &channels); alGetBufferi(buffer, AL_BITS, &bits); - int lengthInSamples = sizeInBytes * 8 / (channels * bits); ALint frequency; alGetBufferi(buffer, AL_FREQUENCY, &frequency); alDeleteBuffers(1, &buffer); + + if (outputSubscriptions.isEmpty()) + cleanupOutput(); } /** diff --git a/src/audio/audio.h b/src/audio/audio.h index b8ba2f069..7b38594ad 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -35,7 +35,6 @@ #include #endif -class QTimer; struct Tox; class AudioFilterer; @@ -49,6 +48,8 @@ class Audio : public QObject { Q_OBJECT + typedef QList PtrList; + public: static Audio& getInstance(); @@ -96,10 +97,10 @@ public: #endif public slots: - void subscribeInput(); - void subscribeOutput(); - void unsubscribeInput(); - void unsubscribeOutput(); + void subscribeInput(const void* inListener); + void subscribeOutput(const void* outListener); + void unsubscribeInput(const void* inListener); + void unsubscribeOutput(const void* outListener); void playGroupAudio(int group, int peer, const int16_t* data, unsigned samples, uint8_t channels, unsigned sample_rate); @@ -110,8 +111,6 @@ private: Audio(); ~Audio(); - void internalSubscribeOutput(); - void initInput(const QString& inDevDescr); bool initOutput(const QString& outDevDescr); void cleanupInput(); @@ -122,9 +121,9 @@ private: private: QThread* audioThread; - std::atomic inputSubscriptions; - std::atomic outputSubscriptions; QMutex mAudioLock; + PtrList inputSubscriptions; + PtrList outputSubscriptions; ALCdevice* alOutDev; ALCdevice* alInDev; bool mInputInitialized; @@ -133,7 +132,6 @@ private: qreal inputVolume; ALuint alMainSource; ALCcontext* alContext; - QTimer* timer; }; #endif // AUDIO_H diff --git a/src/core/toxcall.cpp b/src/core/toxcall.cpp index 604ea1e26..00b634a94 100644 --- a/src/core/toxcall.cpp +++ b/src/core/toxcall.cpp @@ -21,8 +21,8 @@ ToxCall::ToxCall(uint32_t CallId) sendAudioTimer->setSingleShot(true); Audio& audio = Audio::getInstance(); - audio.subscribeInput(); - audio.subscribeOutput(); + audio.subscribeInput(this); + audio.subscribeOutput(this); #ifdef QTOX_FILTER_AUDIO if (Settings::getInstance().getFilterAudio()) @@ -59,8 +59,8 @@ ToxCall::~ToxCall() QObject::disconnect(sendAudioTimer, nullptr, nullptr, nullptr); sendAudioTimer->stop(); Audio& audio = Audio::getInstance(); - audio.unsubscribeInput(); - audio.unsubscribeOutput(); + audio.unsubscribeInput(this); + audio.unsubscribeOutput(this); } if (alSource) diff --git a/src/widget/form/settings/avform.cpp b/src/widget/form/settings/avform.cpp index 46b9a26ca..2ca8142f6 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -105,8 +105,8 @@ void AVForm::showEvent(QShowEvent*) createVideoSurface(); getVideoDevices(); Audio& audio = Audio::getInstance(); - audio.subscribeInput(); - audio.subscribeOutput(); + audio.subscribeInput(this); + audio.subscribeOutput(this); } void AVForm::onVideoModesIndexChanged(int index) @@ -244,8 +244,8 @@ void AVForm::hideEvent(QHideEvent *) } videoDeviceList.clear(); Audio& audio = Audio::getInstance(); - audio.unsubscribeInput(); - audio.unsubscribeOutput(); + audio.unsubscribeInput(this); + audio.unsubscribeOutput(this); } void AVForm::getVideoDevices() From bb7d2a72b725cd2d3fd14661f94fb633ca272612 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Fri, 11 Dec 2015 00:16:21 +0100 Subject: [PATCH 022/210] privatized audio interface --- src/audio/audio.cpp | 206 +++++++++++++++++----------- src/audio/audio.h | 30 ++-- src/core/coreav.cpp | 12 +- src/core/coreav.h | 11 +- src/core/toxcall.cpp | 6 +- src/core/toxcall.h | 11 +- src/widget/form/settings/avform.cpp | 18 +-- 7 files changed, 152 insertions(+), 142 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 592556606..b44bd58c1 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -38,6 +38,36 @@ #include +#if defined(__APPLE__) && defined(__MACH__) + #include + #include +#else + #include + #include +#endif + +class AudioPrivate +{ +public: + AudioPrivate() + : alInDev(nullptr) + , alOutDev(nullptr) + , alContext(nullptr) + , inputVolume(1.f) + , outputVolume(1.f) + { + } + +public: + ALCdevice* alInDev; + ALCdevice* alOutDev; + ALCcontext* alContext; + + ALuint alMainSource; + qreal inputVolume; + qreal outputVolume; +}; + Audio* Audio::instance{nullptr}; /** @@ -54,15 +84,10 @@ Audio& Audio::getInstance() } Audio::Audio() - : audioThread(new QThread()) - , alOutDev(nullptr) - , alInDev(nullptr) + : d(new AudioPrivate) + , audioThread(new QThread()) , mInputInitialized(false) , mOutputInitialized(false) - , outputVolume(1.0) - , inputVolume(1.0) - , alMainSource(0) - , alContext(nullptr) { audioThread->setObjectName("qTox Audio"); connect(audioThread, &QThread::finished, audioThread, &QThread::deleteLater); @@ -94,10 +119,10 @@ void Audio::startAudioThread() /** Returns the current output volume, between 0 and 1 */ -qreal Audio::getOutputVolume() +qreal Audio::outputVolume() { QMutexLocker locker(&mAudioLock); - return outputVolume; + return d->outputVolume; } /** @@ -107,27 +132,31 @@ void Audio::setOutputVolume(qreal volume) { QMutexLocker locker(&mAudioLock); - outputVolume = volume; - alSourcef(alMainSource, AL_GAIN, outputVolume); + d->outputVolume = volume; + alSourcef(d->alMainSource, AL_GAIN, volume); for (const ToxGroupCall& call : CoreAV::groupCalls) { - alSourcef(call.alSource, AL_GAIN, outputVolume); + alSourcef(call.alSource, AL_GAIN, volume); } for (const ToxFriendCall& call : CoreAV::calls) { - alSourcef(call.alSource, AL_GAIN, outputVolume); + alSourcef(call.alSource, AL_GAIN, volume); } } -/** -The volume must be between 0 and 2 -*/ +qreal Audio::inputVolume() +{ + QMutexLocker locker(&mAudioLock); + + return d->inputVolume; +} + void Audio::setInputVolume(qreal volume) { QMutexLocker locker(&mAudioLock); - inputVolume = volume; + d->inputVolume = volume; } /** @@ -139,7 +168,7 @@ void Audio::subscribeInput(const void* inListener) { QMutexLocker locker(&mAudioLock); - if (!alInDev) + if (!d->alInDev) initInput(Settings::getInstance().getInDev()); if (!inputSubscriptions.contains(inListener)) { @@ -171,7 +200,7 @@ void Audio::subscribeOutput(const void* outListener) { QMutexLocker locker(&mAudioLock); - if (!alOutDev) + if (!d->alOutDev) initOutput(Settings::getInstance().getOutDev()); if (!outputSubscriptions.contains(outListener)) { @@ -202,7 +231,7 @@ void Audio::initInput(const QString& inDevDescr) if (inDevDescr == "none") return; - assert(!alInDev); + assert(!d->alInDev); /// TODO: Try to actually detect if our audio source is stereo int stereoFlag = AUDIO_CHANNELS == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16; @@ -230,10 +259,10 @@ void Audio::initInput(const QString& inDevDescr) } } else - alInDev = alcCaptureOpenDevice(inDevDescr.toStdString().c_str(), + d->alInDev = alcCaptureOpenDevice(inDevDescr.toStdString().c_str(), sampleRate, stereoFlag, bufSize); - if (alInDev) + if (d->alInDev) qDebug() << "Opened audio input" << inDevDescr; else qWarning() << "Cannot open input audio device" << inDevDescr; @@ -243,9 +272,9 @@ void Audio::initInput(const QString& inDevDescr) core->getAv()->resetCallSources(); // Force to regen each group call's sources // Restart the capture if necessary - if (alInDev) + if (d->alInDev) { - alcCaptureStart(alInDev); + alcCaptureStart(d->alInDev); } else { @@ -270,7 +299,7 @@ bool Audio::initOutput(const QString& outDevDescr) if (outDevDescr == "none") return true; - assert(!alOutDev); + assert(!d->alOutDev); if (outDevDescr.isEmpty()) { @@ -297,14 +326,15 @@ bool Audio::initOutput(const QString& outDevDescr) } } else - alOutDev = alcOpenDevice(outDevDescr.toStdString().c_str()); + d->alOutDev = alcOpenDevice(outDevDescr.toStdString().c_str()); - if (alOutDev) + if (d->alOutDev) { - alContext = alcCreateContext(alOutDev, nullptr); - if (alcMakeContextCurrent(alContext)) + d->alContext = alcCreateContext(d->alOutDev, nullptr); + if (alcMakeContextCurrent(d->alContext)) { - alGenSources(1, &alMainSource); + alGenSources(1, &d->alMainSource); + alSourcef(d->alMainSource, AL_GAIN, d->outputVolume); } else { @@ -332,26 +362,28 @@ void Audio::playMono16Sound(const QByteArray& data) { QMutexLocker locker(&mAudioLock); - if (!alOutDev) + if (!d->alOutDev) initOutput(Settings::getInstance().getOutDev()); + alSourcei(d->alMainSource, AL_LOOPING, false); + alSourcef(d->alMainSource, AL_GAIN, d->outputVolume); + alSource3f(d->alMainSource, AL_POSITION, 0, 0, 0); + alSource3f(d->alMainSource, AL_VELOCITY, 0, 0, 0); + ALuint buffer; alGenBuffers(1, &buffer); - alBufferData(buffer, AL_FORMAT_MONO16, data.data(), data.size(), 44100); - alSourcef(alMainSource, AL_GAIN, outputVolume); - alSourcei(alMainSource, AL_BUFFER, buffer); - alSourcePlay(alMainSource); + alBufferData(buffer, AL_FORMAT_MONO16, data.constData(), data.size(), 44100); - ALint sizeInBytes; - ALint channels; - ALint bits; + alSourcei(d->alMainSource, AL_BUFFER, buffer); - alGetBufferi(buffer, AL_SIZE, &sizeInBytes); - alGetBufferi(buffer, AL_CHANNELS, &channels); - alGetBufferi(buffer, AL_BITS, &bits); + alSourceRewind(d->alMainSource); + alSourcePlay(d->alMainSource); - ALint frequency; - alGetBufferi(buffer, AL_FREQUENCY, &frequency); + ALint state; + alGetSourcei(d->alMainSource, AL_SOURCE_STATE, &state); + while (state == AL_PLAYING) { + alGetSourcei(d->alMainSource, AL_SOURCE_STATE, &state); + } alDeleteBuffers(1, &buffer); @@ -403,7 +435,7 @@ void Audio::playGroupAudio(int group, int peer, const int16_t* data, if (!call.alSource) { alGenSources(1, &call.alSource); - alSourcef(call.alSource, AL_GAIN, outputVolume); + alSourcef(call.alSource, AL_GAIN, d->outputVolume); } qreal volume = 0.; @@ -416,11 +448,10 @@ void Audio::playGroupAudio(int group, int peer, const int16_t* data, playAudioBuffer(call.alSource, data, samples, channels, sample_rate); } -void Audio::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, unsigned channels, int sampleRate) +void Audio::playAudioBuffer(quint32 alSource, const int16_t *data, int samples, unsigned channels, int sampleRate) { assert(channels == 1 || channels == 2); - - QMutexLocker locker(&getInstance().mAudioLock); + QMutexLocker locker(&mAudioLock); ALuint bufid; ALint processed = 0, queued = 16; @@ -450,7 +481,7 @@ void Audio::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, u ALint state; alGetSourcei(alSource, AL_SOURCE_STATE, &state); - alSourcef(alSource, AL_GAIN, getInstance().outputVolume); + alSourcef(alSource, AL_GAIN, d->outputVolume); if (state != AL_PLAYING) alSourcePlay(alSource); } @@ -464,16 +495,16 @@ void Audio::cleanupInput() { mInputInitialized = false; - if (alInDev) + if (d->alInDev) { #if (!FIX_SND_PCM_PREPARE_BUG) qDebug() << "stopping audio capture"; - alcCaptureStop(alInDev); + alcCaptureStop(d->alInDev); #endif qDebug() << "Closing audio input"; - if (alcCaptureCloseDevice(alInDev) == ALC_TRUE) - alInDev = nullptr; + if (alcCaptureCloseDevice(d->alInDev) == ALC_TRUE) + d->alInDev = nullptr; else qWarning() << "Failed to close input"; } @@ -488,20 +519,20 @@ void Audio::cleanupOutput() { mOutputInitialized = false; - if (alOutDev) { + if (d->alOutDev) { qDebug() << "Closing audio output"; - alSourcei(alMainSource, AL_LOOPING, AL_FALSE); - alSourceStop(alMainSource); - alDeleteSources(1, &alMainSource); + alSourcei(d->alMainSource, AL_LOOPING, AL_FALSE); + alSourceStop(d->alMainSource); + alDeleteSources(1, &d->alMainSource); if (!alcMakeContextCurrent(nullptr)) qWarning("Failed to clear current audio context."); - alcDestroyContext(alContext); - alContext = nullptr; + alcDestroyContext(d->alContext); + d->alContext = nullptr; - if (alcCloseDevice(alOutDev)) - alOutDev = nullptr; + if (alcCloseDevice(d->alOutDev)) + d->alOutDev = nullptr; else qWarning("Failed to close output."); } @@ -513,7 +544,7 @@ Returns true if the input device is open and suscribed to bool Audio::isInputReady() { QMutexLocker locker(&mAudioLock); - return alInDev && mInputInitialized; + return d->alInDev && mInputInitialized; } /** @@ -522,32 +553,49 @@ Returns true if the output device is open bool Audio::isOutputReady() { QMutexLocker locker(&mAudioLock); - return alOutDev && mOutputInitialized; + return d->alOutDev && mOutputInitialized; } -void Audio::createSource(ALuint* source) +const char* Audio::outDeviceNames() { - alGenSources(1, source); - alSourcef(*source, AL_GAIN, getInstance().outputVolume); -} - -void Audio::deleteSource(ALuint* source) -{ - if (alIsSource(*source)) - alDeleteSources(1, source); + const char* pDeviceList; + if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE) + pDeviceList = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); else - qWarning() << "Trying to delete invalid audio source"<<*source; + pDeviceList = alcGetString(NULL, ALC_DEVICE_SPECIFIER); + + return pDeviceList; +} + +const char* Audio::inDeviceNames() +{ + return alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); +} + +void Audio::createSource(quint32* sid) +{ + alGenSources(1, sid); + alSourcef(*sid, AL_GAIN, 1.f); +} + +void Audio::deleteSource(quint32 sid) +{ + if (alIsSource(sid)) { + alDeleteSources(1, &sid); + } else { + qWarning() << "Trying to delete invalid audio source" << sid; + } } void Audio::startLoop() { - alSourcei(alMainSource, AL_LOOPING, AL_TRUE); + alSourcei(d->alMainSource, AL_LOOPING, AL_TRUE); } void Audio::stopLoop() { - alSourcei(alMainSource, AL_LOOPING, AL_FALSE); - alSourceStop(alMainSource); + alSourcei(d->alMainSource, AL_LOOPING, AL_FALSE); + alSourceStop(d->alMainSource); } /** @@ -557,19 +605,19 @@ bool Audio::tryCaptureSamples(int16_t* buf, int samples) { QMutexLocker lock(&mAudioLock); - if (!(alInDev && mInputInitialized)) + if (!(d->alInDev && mInputInitialized)) return false; ALint curSamples=0; - alcGetIntegerv(alInDev, ALC_CAPTURE_SAMPLES, sizeof(curSamples), &curSamples); + alcGetIntegerv(d->alInDev, ALC_CAPTURE_SAMPLES, sizeof(curSamples), &curSamples); if (curSamples < samples) return false; - alcCaptureSamples(alInDev, buf, samples); + alcCaptureSamples(d->alInDev, buf, samples); for (size_t i = 0; i < samples * AUDIO_CHANNELS; ++i) { - int sample = buf[i] * pow(inputVolume, 2); + int sample = buf[i] * pow(d->inputVolume, 2); if (sample < std::numeric_limits::min()) sample = std::numeric_limits::min(); diff --git a/src/audio/audio.h b/src/audio/audio.h index 7b38594ad..ef5df9d46 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -26,17 +26,9 @@ #include #include -#if defined(__APPLE__) && defined(__MACH__) - #include - #include -#else - #include - #include - #include -#endif - struct Tox; class AudioFilterer; +class AudioPrivate; // Public default audio settings static constexpr uint32_t AUDIO_SAMPLE_RATE = 48000; ///< The next best Opus would take is 24k @@ -56,9 +48,10 @@ public: public: void startAudioThread(); - qreal getOutputVolume(); + qreal outputVolume(); void setOutputVolume(qreal volume); + qreal inputVolume(); void setInputVolume(qreal volume); inline void reinitInput(const QString& inDevDesc) @@ -77,8 +70,10 @@ public: bool isInputReady(); bool isOutputReady(); - static void createSource(ALuint* source); - static void deleteSource(ALuint* source); + static const char* outDeviceNames(); + static const char* inDeviceNames(); + void createSource(quint32* sid); + void deleteSource(quint32 sid); void startLoop(); void stopLoop(); @@ -86,10 +81,11 @@ public: void playMono16Sound(const char* path); bool tryCaptureSamples(int16_t *buf, int samples); - static void playAudioBuffer(ALuint alSource, const int16_t *data, int samples, unsigned channels, int sampleRate); + void playAudioBuffer(quint32 alSource, const int16_t *data, int samples, + unsigned channels, int sampleRate); static void playGroupAudioQueued(void *, int group, int peer, const int16_t* data, - unsigned samples, uint8_t channels, unsigned sample_rate, void*); + unsigned samples, uint8_t channels, unsigned sample_rate, void*); #ifdef QTOX_FILTER_AUDIO static void getEchoesToFilter(AudioFilterer* filter, int framesize); @@ -124,14 +120,8 @@ private: QMutex mAudioLock; PtrList inputSubscriptions; PtrList outputSubscriptions; - ALCdevice* alOutDev; - ALCdevice* alInDev; bool mInputInitialized; bool mOutputInitialized; - qreal outputVolume; - qreal inputVolume; - ALuint alMainSource; - ALCcontext* alContext; }; #endif // AUDIO_H diff --git a/src/core/coreav.cpp b/src/core/coreav.cpp index d61b587ec..9d4911aeb 100644 --- a/src/core/coreav.cpp +++ b/src/core/coreav.cpp @@ -474,8 +474,8 @@ void CoreAV::resetCallSources() { if (call.alSource) { - Audio::deleteSource(&call.alSource); - Audio::createSource(&call.alSource); + Audio::getInstance().deleteSource(call.alSource); + Audio::getInstance().createSource(&call.alSource); } } @@ -483,8 +483,8 @@ void CoreAV::resetCallSources() { if (call.alSource) { - Audio::deleteSource(&call.alSource); - Audio::createSource(&call.alSource); + Audio::getInstance().deleteSource(call.alSource); + Audio::getInstance().createSource(&call.alSource); } } } @@ -645,9 +645,9 @@ void CoreAV::audioFrameCallback(ToxAV *, uint32_t friendNum, const int16_t *pcm, return; if (!call.alSource) - alGenSources(1, &call.alSource); + Audio::getInstance().createSource(&call.alSource); - Audio::playAudioBuffer(call.alSource, pcm, sampleCount, channels, samplingRate); + Audio::getInstance().playAudioBuffer(call.alSource, pcm, sampleCount, channels, samplingRate); } void CoreAV::videoFrameCallback(ToxAV *, uint32_t friendNum, uint16_t w, uint16_t h, diff --git a/src/core/coreav.h b/src/core/coreav.h index 27ddef073..dc5c9efc3 100644 --- a/src/core/coreav.h +++ b/src/core/coreav.h @@ -24,17 +24,8 @@ #include #include #include -#include - -#if defined(__APPLE__) && defined(__MACH__) - #include - #include -#else - #include - #include -#endif - #include "src/core/toxcall.h" +#include #ifdef QTOX_FILTER_AUDIO class AudioFilterer; diff --git a/src/core/toxcall.cpp b/src/core/toxcall.cpp index 00b634a94..099456206 100644 --- a/src/core/toxcall.cpp +++ b/src/core/toxcall.cpp @@ -54,6 +54,9 @@ ToxCall::ToxCall(ToxCall&& other) noexcept ToxCall::~ToxCall() { + if (alSource) + Audio::getInstance().deleteSource(alSource); + if (sendAudioTimer) { QObject::disconnect(sendAudioTimer, nullptr, nullptr, nullptr); @@ -63,9 +66,6 @@ ToxCall::~ToxCall() audio.unsubscribeOutput(this); } - if (alSource) - Audio::deleteSource(&alSource); - #ifdef QTOX_FILTER_AUDIO if (filterer) delete filterer; diff --git a/src/core/toxcall.h b/src/core/toxcall.h index cc55b1f41..d6dddbbbb 100644 --- a/src/core/toxcall.h +++ b/src/core/toxcall.h @@ -2,16 +2,9 @@ #define TOXCALL_H #include +#include "src/audio/audio.h" #include "src/core/indexedlist.h" -#if defined(__APPLE__) && defined(__MACH__) - #include - #include -#else - #include - #include -#endif - #include class QTimer; @@ -41,7 +34,7 @@ public: bool inactive; ///< True while we're not participating. (stopped group call, ringing but hasn't started yet, ...) bool muteMic; bool muteVol; - ALuint alSource; + quint32 alSource; #ifdef QTOX_FILTER_AUDIO AudioFilterer* filterer; diff --git a/src/widget/form/settings/avform.cpp b/src/widget/form/settings/avform.cpp index 2ca8142f6..15cfba86c 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -19,8 +19,8 @@ #include "avform.h" #include "ui_avsettings.h" -#include "src/persistence/settings.h" #include "src/audio/audio.h" +#include "src/persistence/settings.h" #include "src/video/camerasource.h" #include "src/video/cameradevice.h" #include "src/video/videosurface.h" @@ -28,14 +28,6 @@ #include "src/core/core.h" #include "src/core/coreav.h" -#if defined(__APPLE__) && defined(__MACH__) - #include - #include -#else - #include - #include -#endif - #include #ifndef ALC_ALL_DEVICES_SPECIFIER @@ -274,7 +266,7 @@ void AVForm::getAudioInDevices() bodyUI->inDevCombobox->blockSignals(true); bodyUI->inDevCombobox->clear(); bodyUI->inDevCombobox->addItem(tr("None")); - const ALchar *pDeviceList = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); + const char* pDeviceList = Audio::inDeviceNames(); if (pDeviceList) { //prevent currentIndexChanged to be fired while adding items @@ -305,11 +297,7 @@ void AVForm::getAudioOutDevices() bodyUI->outDevCombobox->blockSignals(true); bodyUI->outDevCombobox->clear(); bodyUI->outDevCombobox->addItem(tr("None")); - const ALchar *pDeviceList; - if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE) - pDeviceList = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); - else - pDeviceList = alcGetString(NULL, ALC_DEVICE_SPECIFIER); + const char* pDeviceList = Audio::outDeviceNames(); if (pDeviceList) { //prevent currentIndexChanged to be fired while adding items From 1fb9bce78c973cc582296daf6c0335b94540cf07 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sat, 14 Nov 2015 21:50:32 +0100 Subject: [PATCH 023/210] move audio class to thread before starting --- src/audio/audio.cpp | 3 ++- src/audio/audio.h | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index b44bd58c1..802aca180 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -108,12 +108,13 @@ Start the audio thread for capture and playback. */ void Audio::startAudioThread() { + moveToThread(audioThread); + if (!audioThread->isRunning()) audioThread->start(); else qWarning("Audio thread already started -> ignored."); - moveToThread(audioThread); } /** diff --git a/src/audio/audio.h b/src/audio/audio.h index ef5df9d46..b00ec2e20 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -115,6 +115,9 @@ private: private: static Audio* instance; +private: + AudioPrivate* d; + private: QThread* audioThread; QMutex mAudioLock; From b44ef6c5967b32c51e480e30289f7c83a6782102 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sat, 21 Nov 2015 12:40:24 +0100 Subject: [PATCH 024/210] introduce a non-blocking AudioPlayer Also moved private stuff to private class. --- src/audio/audio.cpp | 278 +++++++++++++++++++++++++++----------------- src/audio/audio.h | 28 +---- 2 files changed, 172 insertions(+), 134 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 802aca180..33c6ab50a 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -32,9 +32,10 @@ #include "src/core/coreav.h" #include -#include -#include #include +#include +#include +#include #include @@ -55,17 +56,88 @@ public: , alContext(nullptr) , inputVolume(1.f) , outputVolume(1.f) + , audioThread(new QThread()) + , inputInitialized(false) + , outputInitialized(false) { + audioThread->setObjectName("qTox Audio"); + QObject::connect(audioThread, &QThread::finished, audioThread, &QThread::deleteLater); } + void initInput(const QString& inDevDescr); + bool initOutput(const QString& outDevDescr); + void cleanupInput(); + void cleanupOutput(); + public: ALCdevice* alInDev; ALCdevice* alOutDev; ALCcontext* alContext; + // predefined sources ALuint alMainSource; + qreal inputVolume; qreal outputVolume; + + QThread* audioThread; + QMutex audioLock; + Audio::PtrList inputSubscriptions; + Audio::PtrList outputSubscriptions; + bool inputInitialized; + bool outputInitialized; +}; + +/** +@class AudioPlayer + +@brief Non-blocking audio player. + +The audio data is played from start to finish (no streaming). +*/ +class AudioPlayer : public QThread +{ +public: + AudioPlayer(AudioPrivate* _q, const QByteArray& data) + : q(_q) + { + assert(q); + alGenBuffers(1, &buffer); + alBufferData(buffer, AL_FORMAT_MONO16, data.constData(), data.size(), 44100); + alSourcei(q->alMainSource, AL_BUFFER, buffer); + } + + ~AudioPlayer() + { + QMutexLocker(&q->audioLock); + + alDeleteBuffers(1, &buffer); + if (q->outputSubscriptions.isEmpty()) + q->cleanupOutput(); + else + qDebug("Audio output not closed -> there are pending subscriptions."); + } + + void run() + { + alSourceRewind(q->alMainSource); + alSourcePlay(q->alMainSource); + + QMutexLocker locker(&playLock); + ALint state = AL_PLAYING; + while (state == AL_PLAYING) { + alGetSourcei(q->alMainSource, AL_SOURCE_STATE, &state); + waitPlaying.wait(&playLock, 2000); + } + } + +public: + QMutex playLock; + QWaitCondition waitPlaying; + ALuint buffer; + +private: + AudioPrivate* q; }; Audio* Audio::instance{nullptr}; @@ -85,22 +157,15 @@ Audio& Audio::getInstance() Audio::Audio() : d(new AudioPrivate) - , audioThread(new QThread()) - , mInputInitialized(false) - , mOutputInitialized(false) { - audioThread->setObjectName("qTox Audio"); - connect(audioThread, &QThread::finished, audioThread, &QThread::deleteLater); } Audio::~Audio() { - audioThread->exit(); - audioThread->wait(); - if (audioThread->isRunning()) - audioThread->terminate(); - cleanupInput(); - cleanupOutput(); + d->audioThread->exit(); + d->audioThread->wait(); + d->cleanupInput(); + d->cleanupOutput(); } /** @@ -108,10 +173,10 @@ Start the audio thread for capture and playback. */ void Audio::startAudioThread() { - moveToThread(audioThread); + moveToThread(d->audioThread); - if (!audioThread->isRunning()) - audioThread->start(); + if (!d->audioThread->isRunning()) + d->audioThread->start(); else qWarning("Audio thread already started -> ignored."); @@ -122,7 +187,7 @@ Returns the current output volume, between 0 and 1 */ qreal Audio::outputVolume() { - QMutexLocker locker(&mAudioLock); + QMutexLocker locker(&d->audioLock); return d->outputVolume; } @@ -131,7 +196,7 @@ The volume must be between 0 and 1 */ void Audio::setOutputVolume(qreal volume) { - QMutexLocker locker(&mAudioLock); + QMutexLocker locker(&d->audioLock); d->outputVolume = volume; alSourcef(d->alMainSource, AL_GAIN, volume); @@ -149,17 +214,31 @@ void Audio::setOutputVolume(qreal volume) qreal Audio::inputVolume() { - QMutexLocker locker(&mAudioLock); + QMutexLocker locker(&d->audioLock); return d->inputVolume; } void Audio::setInputVolume(qreal volume) { - QMutexLocker locker(&mAudioLock); + QMutexLocker locker(&d->audioLock); d->inputVolume = volume; } +void Audio::reinitInput(const QString& inDevDesc) +{ + QMutexLocker locker(&d->audioLock); + d->cleanupInput(); + d->initInput(inDevDesc); +} + +bool Audio::reinitOutput(const QString& outDevDesc) +{ + QMutexLocker locker(&d->audioLock); + d->cleanupOutput(); + return d->initOutput(outDevDesc); +} + /** @brief Subscribe to capture sound from the opened input device. @@ -167,14 +246,14 @@ If the input device is not open, it will be opened before capturing. */ void Audio::subscribeInput(const void* inListener) { - QMutexLocker locker(&mAudioLock); + QMutexLocker locker(&d->audioLock); if (!d->alInDev) - initInput(Settings::getInstance().getInDev()); + d->initInput(Settings::getInstance().getInDev()); - if (!inputSubscriptions.contains(inListener)) { - inputSubscriptions << inListener; - qDebug() << "Subscribed to audio input device [" << inputSubscriptions.size() << "subscriptions ]"; + if (!d->inputSubscriptions.contains(inListener)) { + d->inputSubscriptions << inListener; + qDebug() << "Subscribed to audio input device [" << d->inputSubscriptions.size() << "subscriptions ]"; } } @@ -185,54 +264,54 @@ If the input device has no more subscriptions, it will be closed. */ void Audio::unsubscribeInput(const void* inListener) { - QMutexLocker locker(&mAudioLock); + QMutexLocker locker(&d->audioLock); - if (inListener && inputSubscriptions.size()) + if (inListener && d->inputSubscriptions.size()) { - inputSubscriptions.removeOne(inListener); - qDebug() << "Unsubscribed from audio input device [" << inputSubscriptions.size() << "subscriptions left ]"; + d->inputSubscriptions.removeOne(inListener); + qDebug() << "Unsubscribed from audio input device [" << d->inputSubscriptions.size() << "subscriptions left ]"; } - if (inputSubscriptions.isEmpty()) - cleanupInput(); + if (d->inputSubscriptions.isEmpty()) + d->cleanupInput(); } void Audio::subscribeOutput(const void* outListener) { - QMutexLocker locker(&mAudioLock); + QMutexLocker locker(&d->audioLock); if (!d->alOutDev) - initOutput(Settings::getInstance().getOutDev()); + d->initOutput(Settings::getInstance().getOutDev()); - if (!outputSubscriptions.contains(outListener)) { - outputSubscriptions << outListener; - qDebug() << "Subscribed to audio output device [" << outputSubscriptions.size() << "subscriptions ]"; + if (!d->outputSubscriptions.contains(outListener)) { + d->outputSubscriptions << outListener; + qDebug() << "Subscribed to audio output device [" << d->outputSubscriptions.size() << "subscriptions ]"; } } void Audio::unsubscribeOutput(const void* outListener) { - QMutexLocker locker(&mAudioLock); + QMutexLocker locker(&d->audioLock); - if (outListener && outputSubscriptions.size()) + if (outListener && d->outputSubscriptions.size()) { - outputSubscriptions.removeOne(outListener); - qDebug() << "Unsubscribed from audio output device [" << outputSubscriptions.size() << " subscriptions left ]"; + d->outputSubscriptions.removeOne(outListener); + qDebug() << "Unsubscribed from audio output device [" << d->outputSubscriptions.size() << " subscriptions left ]"; } - if (outputSubscriptions.isEmpty()) - cleanupOutput(); + if (d->outputSubscriptions.isEmpty()) + d->cleanupOutput(); } -void Audio::initInput(const QString& inDevDescr) +void AudioPrivate::initInput(const QString& inDevDescr) { qDebug() << "Opening audio input" << inDevDescr; - mInputInitialized = false; + inputInitialized = false; if (inDevDescr == "none") return; - assert(!d->alInDev); + assert(!alInDev); /// TODO: Try to actually detect if our audio source is stereo int stereoFlag = AUDIO_CHANNELS == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16; @@ -260,10 +339,10 @@ void Audio::initInput(const QString& inDevDescr) } } else - d->alInDev = alcCaptureOpenDevice(inDevDescr.toStdString().c_str(), + alInDev = alcCaptureOpenDevice(inDevDescr.toStdString().c_str(), sampleRate, stereoFlag, bufSize); - if (d->alInDev) + if (alInDev) qDebug() << "Opened audio input" << inDevDescr; else qWarning() << "Cannot open input audio device" << inDevDescr; @@ -273,9 +352,9 @@ void Audio::initInput(const QString& inDevDescr) core->getAv()->resetCallSources(); // Force to regen each group call's sources // Restart the capture if necessary - if (d->alInDev) + if (alInDev) { - alcCaptureStart(d->alInDev); + alcCaptureStart(alInDev); } else { @@ -284,7 +363,7 @@ void Audio::initInput(const QString& inDevDescr) #endif } - mInputInitialized = true; + inputInitialized = true; } /** @@ -292,15 +371,15 @@ void Audio::initInput(const QString& inDevDescr) Open an audio output device */ -bool Audio::initOutput(const QString& outDevDescr) +bool AudioPrivate::initOutput(const QString& outDevDescr) { qDebug() << "Opening audio output" << outDevDescr; - mOutputInitialized = false; + outputInitialized = false; if (outDevDescr == "none") return true; - assert(!d->alOutDev); + assert(!alOutDev); if (outDevDescr.isEmpty()) { @@ -327,15 +406,15 @@ bool Audio::initOutput(const QString& outDevDescr) } } else - d->alOutDev = alcOpenDevice(outDevDescr.toStdString().c_str()); + alOutDev = alcOpenDevice(outDevDescr.toStdString().c_str()); - if (d->alOutDev) + if (alOutDev) { - d->alContext = alcCreateContext(d->alOutDev, nullptr); - if (alcMakeContextCurrent(d->alContext)) + alContext = alcCreateContext(alOutDev, nullptr); + if (alcMakeContextCurrent(alContext)) { - alGenSources(1, &d->alMainSource); - alSourcef(d->alMainSource, AL_GAIN, d->outputVolume); + alGenSources(1, &alMainSource); + alSourcef(alMainSource, AL_GAIN, outputVolume); } else { @@ -348,7 +427,7 @@ bool Audio::initOutput(const QString& outDevDescr) if (core) core->getAv()->resetCallSources(); // Force to regen each group call's sources - mOutputInitialized = true; + outputInitialized = true; return true; } @@ -361,35 +440,16 @@ Play a 44100Hz mono 16bit PCM sound */ void Audio::playMono16Sound(const QByteArray& data) { - QMutexLocker locker(&mAudioLock); + QMutexLocker locker(&d->audioLock); if (!d->alOutDev) - initOutput(Settings::getInstance().getOutDev()); + d->initOutput(Settings::getInstance().getOutDev()); - alSourcei(d->alMainSource, AL_LOOPING, false); alSourcef(d->alMainSource, AL_GAIN, d->outputVolume); - alSource3f(d->alMainSource, AL_POSITION, 0, 0, 0); - alSource3f(d->alMainSource, AL_VELOCITY, 0, 0, 0); - ALuint buffer; - alGenBuffers(1, &buffer); - alBufferData(buffer, AL_FORMAT_MONO16, data.constData(), data.size(), 44100); - - alSourcei(d->alMainSource, AL_BUFFER, buffer); - - alSourceRewind(d->alMainSource); - alSourcePlay(d->alMainSource); - - ALint state; - alGetSourcei(d->alMainSource, AL_SOURCE_STATE, &state); - while (state == AL_PLAYING) { - alGetSourcei(d->alMainSource, AL_SOURCE_STATE, &state); - } - - alDeleteBuffers(1, &buffer); - - if (outputSubscriptions.isEmpty()) - cleanupOutput(); + AudioPlayer *player = new AudioPlayer(d, data); + connect(player, &AudioPlayer::finished, player, &AudioPlayer::deleteLater); + player->start(); } /** @@ -422,8 +482,8 @@ Must be called from the audio thread, plays a group call's received audio void Audio::playGroupAudio(int group, int peer, const int16_t* data, unsigned samples, uint8_t channels, unsigned sample_rate) { - assert(QThread::currentThread() == audioThread); - QMutexLocker locker(&mAudioLock); + assert(QThread::currentThread() == d->audioThread); + QMutexLocker locker(&d->audioLock); if (!CoreAV::groupCalls.contains(group)) return; @@ -452,7 +512,7 @@ void Audio::playGroupAudio(int group, int peer, const int16_t* data, void Audio::playAudioBuffer(quint32 alSource, const int16_t *data, int samples, unsigned channels, int sampleRate) { assert(channels == 1 || channels == 2); - QMutexLocker locker(&mAudioLock); + QMutexLocker locker(&d->audioLock); ALuint bufid; ALint processed = 0, queued = 16; @@ -492,20 +552,20 @@ void Audio::playAudioBuffer(quint32 alSource, const int16_t *data, int samples, Close active audio input device. */ -void Audio::cleanupInput() +void AudioPrivate::cleanupInput() { - mInputInitialized = false; + inputInitialized = false; - if (d->alInDev) + if (alInDev) { #if (!FIX_SND_PCM_PREPARE_BUG) qDebug() << "stopping audio capture"; - alcCaptureStop(d->alInDev); + alcCaptureStop(alInDev); #endif qDebug() << "Closing audio input"; - if (alcCaptureCloseDevice(d->alInDev) == ALC_TRUE) - d->alInDev = nullptr; + if (alcCaptureCloseDevice(alInDev) == ALC_TRUE) + alInDev = nullptr; else qWarning() << "Failed to close input"; } @@ -516,24 +576,24 @@ void Audio::cleanupInput() Close active audio output device */ -void Audio::cleanupOutput() +void AudioPrivate::cleanupOutput() { - mOutputInitialized = false; + outputInitialized = false; - if (d->alOutDev) { + if (alOutDev) { qDebug() << "Closing audio output"; - alSourcei(d->alMainSource, AL_LOOPING, AL_FALSE); - alSourceStop(d->alMainSource); - alDeleteSources(1, &d->alMainSource); + alSourcei(alMainSource, AL_LOOPING, AL_FALSE); + alSourceStop(alMainSource); + alDeleteSources(1, &alMainSource); if (!alcMakeContextCurrent(nullptr)) qWarning("Failed to clear current audio context."); - alcDestroyContext(d->alContext); - d->alContext = nullptr; + alcDestroyContext(alContext); + alContext = nullptr; - if (alcCloseDevice(d->alOutDev)) - d->alOutDev = nullptr; + if (alcCloseDevice(alOutDev)) + alOutDev = nullptr; else qWarning("Failed to close output."); } @@ -544,8 +604,8 @@ Returns true if the input device is open and suscribed to */ bool Audio::isInputReady() { - QMutexLocker locker(&mAudioLock); - return d->alInDev && mInputInitialized; + QMutexLocker locker(&d->audioLock); + return d->alInDev && d->inputInitialized; } /** @@ -553,8 +613,8 @@ Returns true if the output device is open */ bool Audio::isOutputReady() { - QMutexLocker locker(&mAudioLock); - return d->alOutDev && mOutputInitialized; + QMutexLocker locker(&d->audioLock); + return d->alOutDev && d->outputInitialized; } const char* Audio::outDeviceNames() @@ -604,9 +664,9 @@ Does nothing and return false on failure */ bool Audio::tryCaptureSamples(int16_t* buf, int samples) { - QMutexLocker lock(&mAudioLock); + QMutexLocker lock(&d->audioLock); - if (!(d->alInDev && mInputInitialized)) + if (!(d->alInDev && d->inputInitialized)) return false; ALint curSamples=0; diff --git a/src/audio/audio.h b/src/audio/audio.h index b00ec2e20..293e000fd 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -40,6 +40,7 @@ class Audio : public QObject { Q_OBJECT +public: typedef QList PtrList; public: @@ -54,18 +55,8 @@ public: qreal inputVolume(); void setInputVolume(qreal volume); - inline void reinitInput(const QString& inDevDesc) - { - QMutexLocker locker(&mAudioLock); - cleanupInput(); - initInput(inDevDesc); - } - inline bool reinitOutput(const QString& outDevDesc) - { - QMutexLocker locker(&mAudioLock); - cleanupOutput(); - return initOutput(outDevDesc); - } + void reinitInput(const QString& inDevDesc); + bool reinitOutput(const QString& outDevDesc); bool isInputReady(); bool isOutputReady(); @@ -107,24 +98,11 @@ private: Audio(); ~Audio(); - void initInput(const QString& inDevDescr); - bool initOutput(const QString& outDevDescr); - void cleanupInput(); - void cleanupOutput(); - private: static Audio* instance; private: AudioPrivate* d; - -private: - QThread* audioThread; - QMutex mAudioLock; - PtrList inputSubscriptions; - PtrList outputSubscriptions; - bool mInputInitialized; - bool mOutputInitialized; }; #endif // AUDIO_H From 67fbee88683c16949c507f05abd73e5535a757e8 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sun, 15 Nov 2015 02:38:16 +0100 Subject: [PATCH 025/210] use qstring for path when playing audio file --- src/audio/audio.cpp | 4 ++-- src/audio/audio.h | 2 +- src/widget/form/chatform.cpp | 2 +- src/widget/widget.cpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 33c6ab50a..6f7e7c7b4 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -455,11 +455,11 @@ void Audio::playMono16Sound(const QByteArray& data) /** Play a 44100Hz mono 16bit PCM sound from a file */ -void Audio::playMono16Sound(const char *path) +void Audio::playMono16Sound(const QString& path) { QFile sndFile(path); sndFile.open(QIODevice::ReadOnly); - playMono16Sound(sndFile.readAll()); + playMono16Sound(QByteArray(sndFile.readAll())); } /** diff --git a/src/audio/audio.h b/src/audio/audio.h index 293e000fd..52a8f4245 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -69,7 +69,7 @@ public: void startLoop(); void stopLoop(); void playMono16Sound(const QByteArray& data); - void playMono16Sound(const char* path); + void playMono16Sound(const QString& path); bool tryCaptureSamples(int16_t *buf, int samples); void playAudioBuffer(quint32 alSource, const int16_t *data, int samples, diff --git a/src/widget/form/chatform.cpp b/src/widget/form/chatform.cpp index 5a482863b..d90507e26 100644 --- a/src/widget/form/chatform.cpp +++ b/src/widget/form/chatform.cpp @@ -294,7 +294,7 @@ void ChatForm::onAvInvite(uint32_t FriendId, bool video) Widget::getInstance()->newFriendMessageAlert(FriendId, false); Audio& audio = Audio::getInstance(); audio.startLoop(); - audio.playMono16Sound(":audio/ToxicIncomingCall.pcm"); + audio.playMono16Sound(QStringLiteral(":/audio/ToxicIncomingCall.pcm")); } void ChatForm::onAvStart(uint32_t FriendId, bool video) diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index 4c4ba6c51..6aaff7966 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -1243,7 +1243,7 @@ bool Widget::newMessageAlert(QWidget* currentWindow, bool isActive, bool sound, } if (Settings::getInstance().getNotifySound() && sound) - Audio::getInstance().playMono16Sound(":/audio/notification.pcm"); + Audio::getInstance().playMono16Sound(QStringLiteral(":/audio/notification.pcm")); } return true; From 5805c8c2bf544c061ef51eedd143cf2b07b79404 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sun, 15 Nov 2015 13:11:00 +0100 Subject: [PATCH 026/210] improved code for non-blocking audio player Instead relying on hardcoded "d->alMainSource", we bind to the given OpenAL source instead. --- src/audio/audio.cpp | 52 +++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 6f7e7c7b4..abf0964f6 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -98,46 +98,40 @@ The audio data is played from start to finish (no streaming). class AudioPlayer : public QThread { public: - AudioPlayer(AudioPrivate* _q, const QByteArray& data) - : q(_q) + AudioPlayer(ALuint source, const QByteArray& data) + : mSource(source) { - assert(q); - alGenBuffers(1, &buffer); - alBufferData(buffer, AL_FORMAT_MONO16, data.constData(), data.size(), 44100); - alSourcei(q->alMainSource, AL_BUFFER, buffer); + alGenBuffers(1, &mBuffer); + alBufferData(mBuffer, AL_FORMAT_MONO16, data.constData(), data.size(), 44100); + alSourcei(mSource, AL_BUFFER, mBuffer); + + connect(this, &AudioPlayer::finished, this, &AudioPlayer::deleteLater); } - ~AudioPlayer() +private: + void run() override final { - QMutexLocker(&q->audioLock); - - alDeleteBuffers(1, &buffer); - if (q->outputSubscriptions.isEmpty()) - q->cleanupOutput(); - else - qDebug("Audio output not closed -> there are pending subscriptions."); - } - - void run() - { - alSourceRewind(q->alMainSource); - alSourcePlay(q->alMainSource); + alSourceRewind(mSource); + alSourcePlay(mSource); QMutexLocker locker(&playLock); ALint state = AL_PLAYING; while (state == AL_PLAYING) { - alGetSourcei(q->alMainSource, AL_SOURCE_STATE, &state); + alGetSourcei(mSource, AL_SOURCE_STATE, &state); waitPlaying.wait(&playLock, 2000); } + + alSourceStop(mSource); + alDeleteBuffers(1, &mBuffer); } public: QMutex playLock; QWaitCondition waitPlaying; - ALuint buffer; private: - AudioPrivate* q; + ALuint mBuffer; + ALuint mSource; }; Audio* Audio::instance{nullptr}; @@ -447,8 +441,16 @@ void Audio::playMono16Sound(const QByteArray& data) alSourcef(d->alMainSource, AL_GAIN, d->outputVolume); - AudioPlayer *player = new AudioPlayer(d, data); - connect(player, &AudioPlayer::finished, player, &AudioPlayer::deleteLater); + AudioPlayer *player = new AudioPlayer(d->alMainSource, data); + connect(player, &AudioPlayer::finished, [=]() { + QMutexLocker locker(&d->audioLock); + + if (d->outputSubscriptions.isEmpty()) + d->cleanupOutput(); + else + qDebug("Audio output not closed -> there are pending subscriptions."); + }); + player->start(); } From cbf0f2e7e0f7dad9725f899a16f5739f19ad3daf Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Mon, 16 Nov 2015 23:57:57 +0100 Subject: [PATCH 027/210] draw the audio gain level with love --- src/widget/tool/micfeedbackwidget.cpp | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/widget/tool/micfeedbackwidget.cpp b/src/widget/tool/micfeedbackwidget.cpp index 9fa8b6ec6..3295ec69f 100644 --- a/src/widget/tool/micfeedbackwidget.cpp +++ b/src/widget/tool/micfeedbackwidget.cpp @@ -31,30 +31,31 @@ MicFeedbackWidget::MicFeedbackWidget(QWidget *parent) void MicFeedbackWidget::paintEvent(QPaintEvent*) { + const int w = width(); + const int h = height(); QPainter painter(this); - painter.setPen(QPen(Qt::black)); - painter.drawRect(QRect(0, 0, width() - 1, height() - 1)); + painter.setPen(QPen(Qt::gray)); + painter.drawRoundedRect(QRect(0, 0, w - 1, h - 1), 3., 3.); - int gradientWidth = round(width() * current) - 4; + int gradientWidth = qMax(0, qRound(w * current) - 4); - if (gradientWidth < 0) - gradientWidth = 0; + QRect gradientRect(2, 2, gradientWidth, h - 4); - QRect gradientRect(2, 2, gradientWidth, height() - 4); - - QLinearGradient gradient(0, 0, width(), 0); - gradient.setColorAt(0, Qt::green); + QPainterPath path; + QLinearGradient gradient(0, 0, w, 0); + gradient.setColorAt(0.0, Qt::green); gradient.setColorAt(0.5, Qt::yellow); - gradient.setColorAt(1, Qt::red); - painter.fillRect(gradientRect, gradient); + gradient.setColorAt(1.0, Qt::red); + path.addRoundedRect(gradientRect, 2.0, 2.0); + painter.fillPath(path, gradient); - float slice = width() / 5; + float slice = w / 5.f; int padding = slice / 2; for (int i = 0; i < 5; ++i) { float pos = slice * i + padding; - painter.drawLine(pos, 2, pos, height() - 4); + painter.drawLine(pos, 2, pos, h - 4); } } From 44d1c6fe74a56fb6b6f365751e1c0e680d320cea Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Tue, 17 Nov 2015 00:14:50 +0100 Subject: [PATCH 028/210] [WIP] implement threaded level meter for input level Issues: 1. Using 100% processor. 2. Temporary silences an active call -> reactivate after widget hide. Still greatly improves metering audio data, removing "read buffer" errors. --- src/audio/audio.cpp | 123 +++++++++++++++++++++++++- src/audio/audio.h | 25 ++++++ src/widget/tool/micfeedbackwidget.cpp | 43 +++------ src/widget/tool/micfeedbackwidget.h | 10 ++- 4 files changed, 165 insertions(+), 36 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index abf0964f6..44ac4ad2e 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -47,6 +48,8 @@ #include #endif +Audio* Audio::instance{nullptr}; + class AudioPrivate { public: @@ -86,6 +89,8 @@ public: Audio::PtrList outputSubscriptions; bool inputInitialized; bool outputInitialized; + + QPointer mAudioMeter; }; /** @@ -134,7 +139,115 @@ private: ALuint mSource; }; -Audio* Audio::instance{nullptr}; +class AudioMeter : public QThread +{ +public: + AudioMeter() + : mActive(false) + { + connect(this, &AudioMeter::finished, this, &AudioMeter::deleteLater); + } + + void waitForData(QMutex* condition) + { + mCheckGainChanged.wait(condition); + } + + void monitorFrame() + { + mDoMonitoring.wakeAll(); + } + +private: + void run() override final + { + static const int framesize = AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS; + + Audio& audio = Audio::getInstance(); + + mNewMaxGain = 0.f; + mActive = true; + + while (mActive) { + int16_t buff[framesize] = {0}; + if (audio.tryCaptureSamples(buff, AUDIO_FRAME_SAMPLE_COUNT)) { + mMeterLock.lock(); + mNewMaxGain = 0.f; + for (int i = 0; i < framesize; ++i) { + mNewMaxGain = qMax(mNewMaxGain, qAbs(buff[i]) / 32767.0); + } + mMeterLock.unlock(); + } else if (mNewMaxGain > 0.f) { + mNewMaxGain -= 0.01f; + } + + mMeterLock.lock(); + mCheckGainChanged.wakeAll(); + mDoMonitoring.wait(&mMeterLock); + mMeterLock.unlock(); + } + } + +public: + QMutex mMeterLock; + QWaitCondition mDoMonitoring; + QWaitCondition mCheckGainChanged; + bool mActive; + qreal mNewMaxGain; +}; + +AudioMeterListener::AudioMeterListener(AudioMeter* measureThread) + : mActive(false) + , mAudioMeter(measureThread) +{ + assert(mAudioMeter); +} + +void AudioMeterListener::start() +{ + QThread* listener = new QThread; + connect(listener, &QThread::started, this, &AudioMeterListener::doListen); + connect(listener, &QThread::finished, listener, &QThread::deleteLater); + moveToThread(listener); + + listener->start(); + mAudioMeter->start(); +} + +void AudioMeterListener::stop() +{ + mActive = false; +} + +void AudioMeterListener::doListen() +{ + mMaxGain = 0.f; + mActive = true; + + QMutexLocker locker(&mAudioMeter->mMeterLock); + while (mActive) { + mAudioMeter->waitForData(locker.mutex()); + + locker.unlock(); + //qDebug() << "GAIN:" << mAudioMeter->mNewMaxGain << "/" << mMaxGain; + if (mAudioMeter->mNewMaxGain != mMaxGain) { + if (mAudioMeter->mNewMaxGain > mMaxGain) + { + mMaxGain = mAudioMeter->mNewMaxGain; + emit gainChanged(mMaxGain); + } else if (mMaxGain > 0.02f) { + mMaxGain -= 0.0005f; + emit gainChanged(mMaxGain); + } + } + locker.relock(); + + mAudioMeter->monitorFrame(); + } + + mAudioMeter->mActive = false; +} + /** Returns the singleton's instance. Will construct on first call. @@ -149,6 +262,14 @@ Audio& Audio::getInstance() return *instance; } +AudioMeterListener* Audio::createAudioMeterListener() const +{ + if (!d->mAudioMeter) + d->mAudioMeter = new AudioMeter; + + return new AudioMeterListener(d->mAudioMeter); +} + Audio::Audio() : d(new AudioPrivate) { diff --git a/src/audio/audio.h b/src/audio/audio.h index 52a8f4245..c981b9564 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -28,6 +28,8 @@ struct Tox; class AudioFilterer; +class AudioMeter; +class AudioMeterListener; class AudioPrivate; // Public default audio settings @@ -49,6 +51,8 @@ public: public: void startAudioThread(); + AudioMeterListener* createAudioMeterListener() const; + qreal outputVolume(); void setOutputVolume(qreal volume); @@ -105,4 +109,25 @@ private: AudioPrivate* d; }; +class AudioMeterListener : public QObject +{ + Q_OBJECT +public: + explicit AudioMeterListener(AudioMeter* measureThread); + + void start(); + void stop(); + +signals: + void gainChanged(qreal newMaxGain); + +private slots: + void doListen(); + +private: + bool mActive; + AudioMeter* mAudioMeter; + qreal mMaxGain; +}; + #endif // AUDIO_H diff --git a/src/widget/tool/micfeedbackwidget.cpp b/src/widget/tool/micfeedbackwidget.cpp index 3295ec69f..f18c59219 100644 --- a/src/widget/tool/micfeedbackwidget.cpp +++ b/src/widget/tool/micfeedbackwidget.cpp @@ -24,7 +24,6 @@ MicFeedbackWidget::MicFeedbackWidget(QWidget *parent) : QWidget(parent) - , timerId(0) { setFixedHeight(20); } @@ -59,41 +58,21 @@ void MicFeedbackWidget::paintEvent(QPaintEvent*) } } -void MicFeedbackWidget::timerEvent(QTimerEvent*) -{ - const int framesize = AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS; - int16_t buff[framesize] = {0}; - - if (Audio::getInstance().tryCaptureSamples(buff, AUDIO_FRAME_SAMPLE_COUNT)) - { - double max = 0; - - for (int i = 0; i < framesize; ++i) - max = std::max(max, fabs(buff[i] / 32767.0)); - - if (max > current) - current = max; - else - current -= 0.05; - - update(); - } - else if (current > 0) - { - current -= 0.01; - } -} - void MicFeedbackWidget::showEvent(QShowEvent*) { - timerId = startTimer(60); + mMeterListener = Audio::getInstance().createAudioMeterListener(); + connect(mMeterListener, &AudioMeterListener::gainChanged, this, &MicFeedbackWidget::onGainMetered); + mMeterListener->start(); } void MicFeedbackWidget::hideEvent(QHideEvent*) { - if (timerId != 0) - { - killTimer(timerId); - timerId = 0; - } + mMeterListener->stop(); +} + +void MicFeedbackWidget::onGainMetered(qreal value) +{ + current = value; + //qDebug("Gain metered at %.3f", current); + update(); } diff --git a/src/widget/tool/micfeedbackwidget.h b/src/widget/tool/micfeedbackwidget.h index 188c7f27d..7c900b456 100644 --- a/src/widget/tool/micfeedbackwidget.h +++ b/src/widget/tool/micfeedbackwidget.h @@ -22,6 +22,8 @@ #include +class AudioMeterListener; + class MicFeedbackWidget : public QWidget { Q_OBJECT @@ -30,13 +32,15 @@ public: protected: void paintEvent(QPaintEvent* event) override; - void timerEvent(QTimerEvent* event) override; void showEvent(QShowEvent* event) override; void hideEvent(QHideEvent* event) override; +private slots: + void onGainMetered(qreal value); + private: - double current; - int timerId; + qreal current; + AudioMeterListener* mMeterListener; }; #endif // MICFEEDBACKWIDGET_H From a1b87194b8eebee0ee291443aaae28a075918d02 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sat, 21 Nov 2015 11:44:59 +0100 Subject: [PATCH 029/210] fix #2504 We need to filter samples * channels; also cleaned up data types --- src/audio/audiofilterer.cpp | 6 +++--- src/audio/audiofilterer.h | 4 ++-- src/core/coreav.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/audio/audiofilterer.cpp b/src/audio/audiofilterer.cpp index 7607c1f4c..456872259 100644 --- a/src/audio/audiofilterer.cpp +++ b/src/audio/audiofilterer.cpp @@ -25,7 +25,7 @@ extern "C"{ #include } -void AudioFilterer::startFilter(unsigned int fs) +void AudioFilterer::startFilter(uint32_t fs) { closeFilter(); filter = new_filter_audio(fs); @@ -38,9 +38,9 @@ void AudioFilterer::closeFilter() filter = nullptr; } -bool AudioFilterer::filterAudio(int16_t* data, int framesize) +bool AudioFilterer::filterAudio(int16_t* data, unsigned int samples) { - return filter && 0 == filter_audio(filter, (int16_t*) data, framesize); + return filter && 0 == filter_audio(filter, data, samples); } /* Enable/disable filters. 1 to enable, 0 to disable. */ diff --git a/src/audio/audiofilterer.h b/src/audio/audiofilterer.h index 73c63f826..5a94384e7 100644 --- a/src/audio/audiofilterer.h +++ b/src/audio/audiofilterer.h @@ -33,13 +33,13 @@ public: explicit AudioFilterer(const AudioFilterer&) = delete; ~AudioFilterer(); AudioFilterer operator=(const AudioFilterer) = delete; - void startFilter(unsigned int fs); + void startFilter(uint32_t fs); void closeFilter(); /* Enable/disable filters. 1 to enable, 0 to disable. */ bool enableDisableFilters(int echo, int noise, int gain, int vad); - bool filterAudio(int16_t* data, int samples); + bool filterAudio(int16_t* data, unsigned int samples); /* Give the audio output from your software to this function so it knows what echo to cancel from the frame */ bool passAudioOutput(const int16_t *data, int samples); diff --git a/src/core/coreav.cpp b/src/core/coreav.cpp index 9d4911aeb..ffe45729a 100644 --- a/src/core/coreav.cpp +++ b/src/core/coreav.cpp @@ -416,7 +416,7 @@ bool CoreAV::sendGroupCallAudio(int groupId) // is a null op #ifndef ALC_LOOPBACK_CAPTURE_SAMPLES Audio::getEchoesToFilter(call.filterer, AUDIO_FRAME_SAMPLE_COUNT); - call.filterer->filterAudio(buf, AUDIO_FRAME_SAMPLE_COUNT); + call.filterer->filterAudio(buf, AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS); } else if (call.filterer) { From 08c43d0b8355636611010174d1b971dd3e629f61 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Tue, 8 Dec 2015 04:52:19 +0100 Subject: [PATCH 030/210] cleanup OpenAL compatibility code in audio class --- src/audio/audio.cpp | 40 +++++++++++++++++++--------------------- src/audio/audio.h | 5 ++--- src/core/coreav.cpp | 12 +++++++----- 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 44ac4ad2e..62dfdb203 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -48,6 +48,15 @@ #include #endif +#ifndef ALC_ALL_DEVICES_SPECIFIER +// compatibility with older versions of OpenAL +#include +#endif + +#ifdef QTOX_FILTER_AUDIO +#include "audiofilterer.h" +#endif + Audio* Audio::instance{nullptr}; class AudioPrivate @@ -77,7 +86,6 @@ public: ALCdevice* alOutDev; ALCcontext* alContext; - // predefined sources ALuint alMainSource; qreal inputVolume; @@ -792,7 +800,7 @@ bool Audio::tryCaptureSamples(int16_t* buf, int samples) if (!(d->alInDev && d->inputInitialized)) return false; - ALint curSamples=0; + ALint curSamples = 0; alcGetIntegerv(d->alInDev, ALC_CAPTURE_SAMPLES, sizeof(curSamples), &curSamples); if (curSamples < samples) return false; @@ -814,29 +822,19 @@ bool Audio::tryCaptureSamples(int16_t* buf, int samples) return true; } -#ifdef QTOX_FILTER_AUDIO -#include "audiofilterer.h" - -/* include for compatibility with older versions of OpenAL */ -#ifndef ALC_ALL_DEVICES_SPECIFIER -#include -#endif - -void Audio::getEchoesToFilter(AudioFilterer* filterer, int framesize) +#if defined(QTOX_FILTER_AUDIO) && defined(ALC_LOOPBACK_CAPTURE_SAMPLES) +void Audio::getEchoesToFilter(AudioFilterer* filterer, int samples) { -#ifdef ALC_LOOPBACK_CAPTURE_SAMPLES + QMutexLocker locker(&d->audioLock); + ALint samples; - alcGetIntegerv(Audio::getInstance().alOutDev, ALC_LOOPBACK_CAPTURE_SAMPLES, sizeof(samples), &samples); - if (samples >= framesize) + alcGetIntegerv(&d->alOutDev, ALC_LOOPBACK_CAPTURE_SAMPLES, sizeof(samples), &samples); + if (samples >= samples) { - int16_t buf[framesize]; - alcCaptureSamplesLoopback(Audio::getInstance().alOutDev, buf, framesize); - filterer->passAudioOutput(buf, framesize); + int16_t buf[samples]; + alcCaptureSamplesLoopback(&d->alOutDev, buf, samples); + filterer->passAudioOutput(buf, samples); filterer->setEchoDelayMs(5); // This 5ms is configurable I believe } -#else - Q_UNUSED(filterer); - Q_UNUSED(framesize); -#endif } #endif diff --git a/src/audio/audio.h b/src/audio/audio.h index c981b9564..7aa397ed3 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -82,9 +82,8 @@ public: static void playGroupAudioQueued(void *, int group, int peer, const int16_t* data, unsigned samples, uint8_t channels, unsigned sample_rate, void*); -#ifdef QTOX_FILTER_AUDIO - static void getEchoesToFilter(AudioFilterer* filter, int framesize); - // is a null op #ifndef ALC_LOOPBACK_CAPTURE_SAMPLES +#if defined(QTOX_FILTER_AUDIO) && defined(ALC_LOOPBACK_CAPTURE_SAMPLES) + void getEchoesToFilter(AudioFilterer* filter, int samples); #endif public slots: diff --git a/src/core/coreav.cpp b/src/core/coreav.cpp index ffe45729a..6c3a15ef8 100644 --- a/src/core/coreav.cpp +++ b/src/core/coreav.cpp @@ -263,9 +263,11 @@ bool CoreAV::sendCallAudio(uint32_t callId) call.filterer = new AudioFilterer(); call.filterer->startFilter(AUDIO_SAMPLE_RATE); } - // is a null op #ifndef ALC_LOOPBACK_CAPTURE_SAMPLES - Audio::getEchoesToFilter(call.filterer, AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS); +#ifdef ALC_LOOPBACK_CAPTURE_SAMPLES + // compatibility with older versions of OpenAL + Audio::getInstance().getEchoesToFilter(call.filterer, AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS); +#endif call.filterer->filterAudio(buf, AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS); } else if (call.filterer) @@ -413,10 +415,10 @@ bool CoreAV::sendGroupCallAudio(int groupId) call.filterer = new AudioFilterer(); call.filterer->startFilter(AUDIO_SAMPLE_RATE); } - // is a null op #ifndef ALC_LOOPBACK_CAPTURE_SAMPLES - Audio::getEchoesToFilter(call.filterer, AUDIO_FRAME_SAMPLE_COUNT); - call.filterer->filterAudio(buf, AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS); +#ifdef ALC_LOOPBACK_CAPTURE_SAMPLES + Audio::getInstance().getEchoesToFilter(call.filterer, AUDIO_FRAME_SAMPLE_COUNT); +#endif } else if (call.filterer) { From c39138a65dc02230ca3e8deb8cc49c0a887b1027 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sat, 21 Nov 2015 12:06:22 +0100 Subject: [PATCH 031/210] lock mutex also on start/stop audio loop playback --- src/audio/audio.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 62dfdb203..d063951c0 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -781,11 +781,13 @@ void Audio::deleteSource(quint32 sid) void Audio::startLoop() { + QMutexLocker locker(&d->audioLock); alSourcei(d->alMainSource, AL_LOOPING, AL_TRUE); } void Audio::stopLoop() { + QMutexLocker locker(&d->audioLock); alSourcei(d->alMainSource, AL_LOOPING, AL_FALSE); alSourceStop(d->alMainSource); } From 02f5f0a391c16604ba3c6a48a55e912e4a616f44 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sun, 29 Nov 2015 12:12:02 +0100 Subject: [PATCH 032/210] remove obsolete include of audio.h --- src/core/toxcall.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/toxcall.h b/src/core/toxcall.h index d6dddbbbb..b0b35cc91 100644 --- a/src/core/toxcall.h +++ b/src/core/toxcall.h @@ -2,7 +2,8 @@ #define TOXCALL_H #include -#include "src/audio/audio.h" +#include + #include "src/core/indexedlist.h" #include From 535bb212f51905e7f0e4941e87a46fa5117fe876 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sun, 29 Nov 2015 23:37:42 +0100 Subject: [PATCH 033/210] make use of QThread::requestInterruption --- src/audio/audio.cpp | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index d063951c0..38e9516b9 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -151,19 +151,13 @@ class AudioMeter : public QThread { public: AudioMeter() - : mActive(false) { connect(this, &AudioMeter::finished, this, &AudioMeter::deleteLater); } - void waitForData(QMutex* condition) + inline void stop() { - mCheckGainChanged.wait(condition); - } - - void monitorFrame() - { - mDoMonitoring.wakeAll(); + requestInterruption(); } private: @@ -174,9 +168,8 @@ private: Audio& audio = Audio::getInstance(); mNewMaxGain = 0.f; - mActive = true; - while (mActive) { + while (!isInterruptionRequested()) { int16_t buff[framesize] = {0}; if (audio.tryCaptureSamples(buff, AUDIO_FRAME_SAMPLE_COUNT)) { mMeterLock.lock(); @@ -200,7 +193,6 @@ public: QMutex mMeterLock; QWaitCondition mDoMonitoring; QWaitCondition mCheckGainChanged; - bool mActive; qreal mNewMaxGain; }; @@ -253,7 +245,7 @@ void AudioMeterListener::doListen() mAudioMeter->monitorFrame(); } - mAudioMeter->mActive = false; + mAudioMeter->requestInterruption(); } @@ -285,6 +277,8 @@ Audio::Audio() Audio::~Audio() { + if (d->mAudioMeter) + d->mAudioMeter->stop(); d->audioThread->exit(); d->audioThread->wait(); d->cleanupInput(); From ace366275756fe95f7005cf7545a2e1fdeecc90b Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sun, 29 Nov 2015 23:45:52 +0100 Subject: [PATCH 034/210] further improved audio metering Give qTox time to do more important things -> do not measure with 100%. --- src/audio/audio.cpp | 60 ++++++++++++++------------- src/audio/audio.h | 4 ++ src/widget/tool/micfeedbackwidget.cpp | 5 ++- 3 files changed, 39 insertions(+), 30 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 38e9516b9..b7ab14274 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -36,7 +36,6 @@ #include #include #include -#include #include @@ -169,30 +168,27 @@ private: mNewMaxGain = 0.f; + QMutexLocker locker(&mMeterLock); while (!isInterruptionRequested()) { + mListenerReady.wait(locker.mutex()); + locker.relock(); + int16_t buff[framesize] = {0}; if (audio.tryCaptureSamples(buff, AUDIO_FRAME_SAMPLE_COUNT)) { - mMeterLock.lock(); mNewMaxGain = 0.f; for (int i = 0; i < framesize; ++i) { mNewMaxGain = qMax(mNewMaxGain, qAbs(buff[i]) / 32767.0); } - mMeterLock.unlock(); - } else if (mNewMaxGain > 0.f) { - mNewMaxGain -= 0.01f; } - mMeterLock.lock(); - mCheckGainChanged.wakeAll(); - mDoMonitoring.wait(&mMeterLock); - mMeterLock.unlock(); + mGainMeasured.wakeAll(); } } public: QMutex mMeterLock; - QWaitCondition mDoMonitoring; - QWaitCondition mCheckGainChanged; + QWaitCondition mListenerReady; + QWaitCondition mGainMeasured; qreal mNewMaxGain; }; @@ -205,13 +201,20 @@ AudioMeterListener::AudioMeterListener(AudioMeter* measureThread) void AudioMeterListener::start() { + if (!mAudioMeter->isRunning()) { + mAudioMeter->start(); + // TODO: ensure that audiometer is running + // -> Start listeners from AudioMeter::started signal + while (!mAudioMeter->isRunning()) + QThread::msleep(10); + } + QThread* listener = new QThread; connect(listener, &QThread::started, this, &AudioMeterListener::doListen); connect(listener, &QThread::finished, listener, &QThread::deleteLater); moveToThread(listener); listener->start(); - mAudioMeter->start(); } void AudioMeterListener::stop() @@ -219,6 +222,11 @@ void AudioMeterListener::stop() mActive = false; } +void AudioMeterListener::processed() +{ + mGainProcessed.wakeAll(); +} + void AudioMeterListener::doListen() { mMaxGain = 0.f; @@ -226,29 +234,25 @@ void AudioMeterListener::doListen() QMutexLocker locker(&mAudioMeter->mMeterLock); while (mActive) { - mAudioMeter->waitForData(locker.mutex()); - - locker.unlock(); - //qDebug() << "GAIN:" << mAudioMeter->mNewMaxGain << "/" << mMaxGain; - if (mAudioMeter->mNewMaxGain != mMaxGain) { - if (mAudioMeter->mNewMaxGain > mMaxGain) - { - mMaxGain = mAudioMeter->mNewMaxGain; - emit gainChanged(mMaxGain); - } else if (mMaxGain > 0.02f) { - mMaxGain -= 0.0005f; - emit gainChanged(mMaxGain); - } - } + mAudioMeter->mListenerReady.wakeAll(); + mAudioMeter->mGainMeasured.wait(&mAudioMeter->mMeterLock); locker.relock(); - mAudioMeter->monitorFrame(); + if (mAudioMeter->mNewMaxGain > mMaxGain) { + mMaxGain = mAudioMeter->mNewMaxGain; + emit gainChanged(mMaxGain); + } else if (mMaxGain > 0.02f) { + mMaxGain -= 0.008f; + emit gainChanged(mMaxGain); + } + + mGainProcessed.wait(locker.mutex(), 10); + locker.relock(); } mAudioMeter->requestInterruption(); } - /** Returns the singleton's instance. Will construct on first call. */ diff --git a/src/audio/audio.h b/src/audio/audio.h index 7aa397ed3..8a70382f7 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -25,6 +25,7 @@ #include #include #include +#include struct Tox; class AudioFilterer; @@ -117,6 +118,8 @@ public: void start(); void stop(); + void processed(); + signals: void gainChanged(qreal newMaxGain); @@ -127,6 +130,7 @@ private: bool mActive; AudioMeter* mAudioMeter; qreal mMaxGain; + QWaitCondition mGainProcessed; }; #endif // AUDIO_H diff --git a/src/widget/tool/micfeedbackwidget.cpp b/src/widget/tool/micfeedbackwidget.cpp index f18c59219..60766653e 100644 --- a/src/widget/tool/micfeedbackwidget.cpp +++ b/src/widget/tool/micfeedbackwidget.cpp @@ -61,7 +61,8 @@ void MicFeedbackWidget::paintEvent(QPaintEvent*) void MicFeedbackWidget::showEvent(QShowEvent*) { mMeterListener = Audio::getInstance().createAudioMeterListener(); - connect(mMeterListener, &AudioMeterListener::gainChanged, this, &MicFeedbackWidget::onGainMetered); + connect(mMeterListener, &AudioMeterListener::gainChanged, + this, &MicFeedbackWidget::onGainMetered); mMeterListener->start(); } @@ -73,6 +74,6 @@ void MicFeedbackWidget::hideEvent(QHideEvent*) void MicFeedbackWidget::onGainMetered(qreal value) { current = value; - //qDebug("Gain metered at %.3f", current); update(); + mMeterListener->processed(); } From d8607324ce5e46e0344b69e0d4a1a7404d7346c0 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sat, 5 Dec 2015 15:04:32 +0100 Subject: [PATCH 035/210] cleanup AudioPrivate * rename mAudioMeter -> audioMeter * move class declaration below other classes --- src/audio/audio.cpp | 107 +++++++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 51 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index b7ab14274..9462f766a 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -58,48 +58,6 @@ Audio* Audio::instance{nullptr}; -class AudioPrivate -{ -public: - AudioPrivate() - : alInDev(nullptr) - , alOutDev(nullptr) - , alContext(nullptr) - , inputVolume(1.f) - , outputVolume(1.f) - , audioThread(new QThread()) - , inputInitialized(false) - , outputInitialized(false) - { - audioThread->setObjectName("qTox Audio"); - QObject::connect(audioThread, &QThread::finished, audioThread, &QThread::deleteLater); - } - - void initInput(const QString& inDevDescr); - bool initOutput(const QString& outDevDescr); - void cleanupInput(); - void cleanupOutput(); - -public: - ALCdevice* alInDev; - ALCdevice* alOutDev; - ALCcontext* alContext; - - ALuint alMainSource; - - qreal inputVolume; - qreal outputVolume; - - QThread* audioThread; - QMutex audioLock; - Audio::PtrList inputSubscriptions; - Audio::PtrList outputSubscriptions; - bool inputInitialized; - bool outputInitialized; - - QPointer mAudioMeter; -}; - /** @class AudioPlayer @@ -192,6 +150,58 @@ public: qreal mNewMaxGain; }; +class AudioPrivate +{ +public: + AudioPrivate() + : audioThread(new QThread) + , alInDev(nullptr) + , alOutDev(nullptr) + , alContext(nullptr) + , inputVolume(1.f) + , outputVolume(1.f) + , inputInitialized(false) + , outputInitialized(false) + { + audioThread->setObjectName("qTox Audio"); + QObject::connect(audioThread, &QThread::finished, audioThread, &QThread::deleteLater); + } + + ~AudioPrivate() + { + if (audioMeter) + audioMeter->stop(); + + audioThread->exit(); + audioThread->wait(); + cleanupInput(); + cleanupOutput(); + } + + void initInput(const QString& inDevDescr); + bool initOutput(const QString& outDevDescr); + void cleanupInput(); + void cleanupOutput(); + +public: + QThread* audioThread; + QMutex audioLock; + + ALCdevice* alInDev; + ALCdevice* alOutDev; + ALCcontext* alContext; + ALuint alMainSource; + qreal inputVolume; + qreal outputVolume; + bool inputInitialized; + bool outputInitialized; + + Audio::PtrList inputSubscriptions; + Audio::PtrList outputSubscriptions; + + QPointer audioMeter; +}; + AudioMeterListener::AudioMeterListener(AudioMeter* measureThread) : mActive(false) , mAudioMeter(measureThread) @@ -268,10 +278,10 @@ Audio& Audio::getInstance() AudioMeterListener* Audio::createAudioMeterListener() const { - if (!d->mAudioMeter) - d->mAudioMeter = new AudioMeter; + if (!d->audioMeter) + d->audioMeter = new AudioMeter; - return new AudioMeterListener(d->mAudioMeter); + return new AudioMeterListener(d->audioMeter); } Audio::Audio() @@ -281,12 +291,7 @@ Audio::Audio() Audio::~Audio() { - if (d->mAudioMeter) - d->mAudioMeter->stop(); - d->audioThread->exit(); - d->audioThread->wait(); - d->cleanupInput(); - d->cleanupOutput(); + delete d; } /** From 27bfade9e15fa5045b2e549bbab0a7d266fad557 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sat, 5 Dec 2015 15:11:06 +0100 Subject: [PATCH 036/210] unsubscribe invalid ToxCall from audio when copied --- src/core/toxcall.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/core/toxcall.cpp b/src/core/toxcall.cpp index 099456206..542e7baed 100644 --- a/src/core/toxcall.cpp +++ b/src/core/toxcall.cpp @@ -46,6 +46,12 @@ ToxCall::ToxCall(ToxCall&& other) noexcept other.callId = numeric_limits::max(); other.alSource = 0; + Audio& audio = Audio::getInstance(); + audio.subscribeInput(this); + audio.unsubscribeInput(&other); + audio.subscribeOutput(this); + audio.unsubscribeOutput(&other); + #ifdef QTOX_FILTER_AUDIO filterer = other.filterer; other.filterer = nullptr; @@ -54,18 +60,20 @@ ToxCall::ToxCall(ToxCall&& other) noexcept ToxCall::~ToxCall() { - if (alSource) - Audio::getInstance().deleteSource(alSource); + Audio& audio = Audio::getInstance(); if (sendAudioTimer) { QObject::disconnect(sendAudioTimer, nullptr, nullptr, nullptr); sendAudioTimer->stop(); - Audio& audio = Audio::getInstance(); - audio.unsubscribeInput(this); - audio.unsubscribeOutput(this); } + if (alSource) + audio.deleteSource(alSource); + + audio.unsubscribeInput(this); + audio.unsubscribeOutput(this); + #ifdef QTOX_FILTER_AUDIO if (filterer) delete filterer; From 0615c7c3c6c059f05a466314f8d72c3c883df609 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Thu, 10 Dec 2015 06:48:28 +0100 Subject: [PATCH 037/210] reimplement audio in/out subscription concept --- src/audio/audio.cpp | 145 ++++++++++++++-------------- src/audio/audio.h | 16 ++- src/core/coreav.cpp | 19 ++-- src/core/coreav.h | 2 +- src/core/toxcall.cpp | 22 ++--- src/widget/form/settings/avform.cpp | 51 ++++++---- src/widget/form/settings/avform.h | 13 ++- 7 files changed, 135 insertions(+), 133 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 9462f766a..c219c48e6 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -152,6 +152,8 @@ public: class AudioPrivate { + typedef QList ALSources; + public: AudioPrivate() : audioThread(new QThread) @@ -162,6 +164,7 @@ public: , outputVolume(1.f) , inputInitialized(false) , outputInitialized(false) + , inSubscriptions(0) { audioThread->setObjectName("qTox Audio"); QObject::connect(audioThread, &QThread::finished, audioThread, &QThread::deleteLater); @@ -196,8 +199,8 @@ public: bool inputInitialized; bool outputInitialized; - Audio::PtrList inputSubscriptions; - Audio::PtrList outputSubscriptions; + quint32 inSubscriptions; + ALSources outSources; QPointer audioMeter; }; @@ -370,17 +373,15 @@ bool Audio::reinitOutput(const QString& outDevDesc) If the input device is not open, it will be opened before capturing. */ -void Audio::subscribeInput(const void* inListener) +void Audio::subscribeInput() { QMutexLocker locker(&d->audioLock); if (!d->alInDev) d->initInput(Settings::getInstance().getInDev()); - if (!d->inputSubscriptions.contains(inListener)) { - d->inputSubscriptions << inListener; - qDebug() << "Subscribed to audio input device [" << d->inputSubscriptions.size() << "subscriptions ]"; - } + d->inSubscriptions++; + qDebug() << "Subscribed to audio input device [" << d->inSubscriptions << "subscriptions ]"; } /** @@ -388,47 +389,19 @@ void Audio::subscribeInput(const void* inListener) If the input device has no more subscriptions, it will be closed. */ -void Audio::unsubscribeInput(const void* inListener) +void Audio::unsubscribeInput() { QMutexLocker locker(&d->audioLock); - if (inListener && d->inputSubscriptions.size()) - { - d->inputSubscriptions.removeOne(inListener); - qDebug() << "Unsubscribed from audio input device [" << d->inputSubscriptions.size() << "subscriptions left ]"; + if (d->inSubscriptions > 0) { + d->inSubscriptions--; + qDebug() << "Unsubscribed from audio input device [" << d->inSubscriptions << "subscriptions left ]"; } - if (d->inputSubscriptions.isEmpty()) + if (!d->inSubscriptions) d->cleanupInput(); } -void Audio::subscribeOutput(const void* outListener) -{ - QMutexLocker locker(&d->audioLock); - - if (!d->alOutDev) - d->initOutput(Settings::getInstance().getOutDev()); - - if (!d->outputSubscriptions.contains(outListener)) { - d->outputSubscriptions << outListener; - qDebug() << "Subscribed to audio output device [" << d->outputSubscriptions.size() << "subscriptions ]"; - } -} - -void Audio::unsubscribeOutput(const void* outListener) -{ - QMutexLocker locker(&d->audioLock); - - if (outListener && d->outputSubscriptions.size()) - { - d->outputSubscriptions.removeOne(outListener); - qDebug() << "Unsubscribed from audio output device [" << d->outputSubscriptions.size() << " subscriptions left ]"; - } - - if (d->outputSubscriptions.isEmpty()) - d->cleanupOutput(); -} - void AudioPrivate::initInput(const QString& inDevDescr) { qDebug() << "Opening audio input" << inDevDescr; @@ -473,10 +446,6 @@ void AudioPrivate::initInput(const QString& inDevDescr) else qWarning() << "Cannot open input audio device" << inDevDescr; - Core* core = Core::getInstance(); - if (core) - core->getAv()->resetCallSources(); // Force to regen each group call's sources - // Restart the capture if necessary if (alInDev) { @@ -500,6 +469,7 @@ Open an audio output device bool AudioPrivate::initOutput(const QString& outDevDescr) { qDebug() << "Opening audio output" << outDevDescr; + outSources.clear(); outputInitialized = false; if (outDevDescr == "none") @@ -508,29 +478,29 @@ bool AudioPrivate::initOutput(const QString& outDevDescr) assert(!alOutDev); if (outDevDescr.isEmpty()) + { + // Attempt to default to the first available audio device. + const ALchar *pDeviceList; + if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE) + pDeviceList = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); + else + pDeviceList = alcGetString(NULL, ALC_DEVICE_SPECIFIER); + if (pDeviceList) { - // Attempt to default to the first available audio device. - const ALchar *pDeviceList; - if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE) - pDeviceList = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); - else - pDeviceList = alcGetString(NULL, ALC_DEVICE_SPECIFIER); - if (pDeviceList) - { - alOutDev = alcOpenDevice(pDeviceList); - int len = strlen(pDeviceList); - #ifdef Q_OS_WIN - QString outDev = QString::fromUtf8(pDeviceList, len); - #else - QString outDev = QString::fromLocal8Bit(pDeviceList, len); - #endif - Settings::getInstance().setOutDev(outDev); - } - else - { - alOutDev = alcOpenDevice(nullptr); - } + alOutDev = alcOpenDevice(pDeviceList); + int len = strlen(pDeviceList); +#ifdef Q_OS_WIN + QString outDev = QString::fromUtf8(pDeviceList, len); +#else + QString outDev = QString::fromLocal8Bit(pDeviceList, len); +#endif + Settings::getInstance().setOutDev(outDev); } + else + { + alOutDev = alcOpenDevice(nullptr); + } + } else alOutDev = alcOpenDevice(outDevDescr.toStdString().c_str()); @@ -551,7 +521,7 @@ bool AudioPrivate::initOutput(const QString& outDevDescr) Core* core = Core::getInstance(); if (core) - core->getAv()->resetCallSources(); // Force to regen each group call's sources + core->getAv()->invalidateCallSources(); // Force to regen each group call's sources outputInitialized = true; return true; @@ -577,7 +547,7 @@ void Audio::playMono16Sound(const QByteArray& data) connect(player, &AudioPlayer::finished, [=]() { QMutexLocker locker(&d->audioLock); - if (d->outputSubscriptions.isEmpty()) + if (d->outSources.isEmpty()) d->cleanupOutput(); else qDebug("Audio output not closed -> there are pending subscriptions."); @@ -648,6 +618,9 @@ void Audio::playAudioBuffer(quint32 alSource, const int16_t *data, int samples, assert(channels == 1 || channels == 2); QMutexLocker locker(&d->audioLock); + if (!(d->alOutDev && d->outputInitialized)) + return; + ALuint bufid; ALint processed = 0, queued = 16; alGetSourcei(alSource, AL_BUFFERS_PROCESSED, &processed); @@ -767,19 +740,41 @@ const char* Audio::inDeviceNames() return alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); } -void Audio::createSource(quint32* sid) +void Audio::subscribeOutput(SID& sid) { - alGenSources(1, sid); - alSourcef(*sid, AL_GAIN, 1.f); + QMutexLocker locker(&d->audioLock); + + if (!d->alOutDev) + d->initOutput(Settings::getInstance().getOutDev()); + + alGenSources(1, &sid); + assert(sid); + alSourcef(sid, AL_GAIN, 1.f); + d->outSources << sid; + qDebug() << "Audio source" << sid << "created. Sources active:" + << d->outSources.size(); } -void Audio::deleteSource(quint32 sid) +void Audio::unsubscribeOutput(SID& sid) { - if (alIsSource(sid)) { - alDeleteSources(1, &sid); - } else { - qWarning() << "Trying to delete invalid audio source" << sid; + QMutexLocker locker(&d->audioLock); + + if (sid) { + if (alIsSource(sid)) { + alDeleteSources(1, &sid); + qDebug() << "Audio source" << sid << "deleted. Sources active:" + << d->outSources.size(); + } else { + qWarning() << "Trying to delete invalid audio source" << sid; + } + + sid = 0; } + + d->outSources.removeAll(sid); + + if (d->outSources.isEmpty()) + d->cleanupOutput(); } void Audio::startLoop() diff --git a/src/audio/audio.h b/src/audio/audio.h index 8a70382f7..777c30cb6 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -21,10 +21,10 @@ #ifndef AUDIO_H #define AUDIO_H -#include -#include #include #include + +#include #include struct Tox; @@ -44,7 +44,7 @@ class Audio : public QObject Q_OBJECT public: - typedef QList PtrList; + typedef quint32 SID; public: static Audio& getInstance(); @@ -68,8 +68,8 @@ public: static const char* outDeviceNames(); static const char* inDeviceNames(); - void createSource(quint32* sid); - void deleteSource(quint32 sid); + void subscribeOutput(SID& sid); + void unsubscribeOutput(SID& sid); void startLoop(); void stopLoop(); @@ -88,10 +88,8 @@ public: #endif public slots: - void subscribeInput(const void* inListener); - void subscribeOutput(const void* outListener); - void unsubscribeInput(const void* inListener); - void unsubscribeOutput(const void* outListener); + void subscribeInput(); + void unsubscribeInput(); void playGroupAudio(int group, int peer, const int16_t* data, unsigned samples, uint8_t channels, unsigned sample_rate); diff --git a/src/core/coreav.cpp b/src/core/coreav.cpp index 6c3a15ef8..43c0faaf7 100644 --- a/src/core/coreav.cpp +++ b/src/core/coreav.cpp @@ -470,24 +470,16 @@ bool CoreAV::isGroupAvEnabled(int groupId) const return tox_group_get_type(Core::getInstance()->tox, groupId) == TOX_GROUPCHAT_TYPE_AV; } -void CoreAV::resetCallSources() +void CoreAV::invalidateCallSources() { for (ToxGroupCall& call : groupCalls) { - if (call.alSource) - { - Audio::getInstance().deleteSource(call.alSource); - Audio::getInstance().createSource(&call.alSource); - } + call.alSource = 0; } for (ToxFriendCall& call : calls) { - if (call.alSource) - { - Audio::getInstance().deleteSource(call.alSource); - Audio::getInstance().createSource(&call.alSource); - } + call.alSource = 0; } } @@ -646,10 +638,11 @@ void CoreAV::audioFrameCallback(ToxAV *, uint32_t friendNum, const int16_t *pcm, if (call.muteVol) return; + Audio& audio = Audio::getInstance(); if (!call.alSource) - Audio::getInstance().createSource(&call.alSource); + audio.subscribeOutput(call.alSource); - Audio::getInstance().playAudioBuffer(call.alSource, pcm, sampleCount, channels, samplingRate); + audio.playAudioBuffer(call.alSource, pcm, sampleCount, channels, samplingRate); } void CoreAV::videoFrameCallback(ToxAV *, uint32_t friendNum, uint16_t w, uint16_t h, diff --git a/src/core/coreav.h b/src/core/coreav.h index dc5c9efc3..46071362a 100644 --- a/src/core/coreav.h +++ b/src/core/coreav.h @@ -57,7 +57,7 @@ public: bool sendGroupCallAudio(int groupNum); VideoSource* getVideoSourceFromCall(int callNumber); ///< Get a call's video source - void resetCallSources(); ///< Forces to regenerate each call's audio sources + void invalidateCallSources(); ///< Forces to regenerate each call's audio sources void sendNoVideo(); ///< Signal to all peers that we're not sending video anymore. The next frame sent cancels this. void joinGroupCall(int groupNum); ///< Starts a call in an existing AV groupchat. Call from the GUI thread. diff --git a/src/core/toxcall.cpp b/src/core/toxcall.cpp index 542e7baed..7a878edc6 100644 --- a/src/core/toxcall.cpp +++ b/src/core/toxcall.cpp @@ -21,8 +21,8 @@ ToxCall::ToxCall(uint32_t CallId) sendAudioTimer->setSingleShot(true); Audio& audio = Audio::getInstance(); - audio.subscribeInput(this); - audio.subscribeOutput(this); + audio.subscribeInput(); + audio.subscribeOutput(alSource); #ifdef QTOX_FILTER_AUDIO if (Settings::getInstance().getFilterAudio()) @@ -46,11 +46,10 @@ ToxCall::ToxCall(ToxCall&& other) noexcept other.callId = numeric_limits::max(); other.alSource = 0; + // required -> ownership of audio input is moved to new instance Audio& audio = Audio::getInstance(); - audio.subscribeInput(this); - audio.unsubscribeInput(&other); - audio.subscribeOutput(this); - audio.unsubscribeOutput(&other); + audio.subscribeInput(); + audio.subscribeOutput(alSource); #ifdef QTOX_FILTER_AUDIO filterer = other.filterer; @@ -68,11 +67,8 @@ ToxCall::~ToxCall() sendAudioTimer->stop(); } - if (alSource) - audio.deleteSource(alSource); - - audio.unsubscribeInput(this); - audio.unsubscribeOutput(this); + audio.unsubscribeInput(); + audio.unsubscribeOutput(alSource); #ifdef QTOX_FILTER_AUDIO if (filterer) @@ -92,6 +88,10 @@ const ToxCall& ToxCall::operator=(ToxCall&& other) noexcept alSource = other.alSource; other.alSource = 0; + // required -> ownership of audio input is moved to new instance + Audio& audio = Audio::getInstance(); + audio.subscribeInput(); + #ifdef QTOX_FILTER_AUDIO filterer = other.filterer; other.filterer = nullptr; diff --git a/src/widget/form/settings/avform.cpp b/src/widget/form/settings/avform.cpp index 15cfba86c..d6d1f4776 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -29,14 +29,17 @@ #include "src/core/coreav.h" #include +#include #ifndef ALC_ALL_DEVICES_SPECIFIER #define ALC_ALL_DEVICES_SPECIFIER ALC_DEVICE_SPECIFIER #endif AVForm::AVForm() : - GenericForm(QPixmap(":/img/settings/av.png")), - camVideoSurface{nullptr}, camera(CameraSource::getInstance()) + GenericForm(QPixmap(":/img/settings/av.png")) + , subscribedToAudioIn{false} + , camVideoSurface{nullptr} + , camera(CameraSource::getInstance()) { bodyUI = new Ui::AVSettings; bodyUI->setupUi(this); @@ -90,15 +93,38 @@ AVForm::~AVForm() delete bodyUI; } -void AVForm::showEvent(QShowEvent*) +void AVForm::hideEvent(QHideEvent* event) +{ + if (subscribedToAudioIn) { + // TODO: this should not be done in show/hide events + Audio::getInstance().unsubscribeInput(); + subscribedToAudioIn = false; + } + + if (camVideoSurface) + { + camVideoSurface->setSource(nullptr); + killVideoSurface(); + } + videoDeviceList.clear(); + + GenericForm::hideEvent(event); +} + +void AVForm::showEvent(QShowEvent* event) { getAudioOutDevices(); getAudioInDevices(); createVideoSurface(); getVideoDevices(); - Audio& audio = Audio::getInstance(); - audio.subscribeInput(this); - audio.subscribeOutput(this); + + if (!subscribedToAudioIn) { + // TODO: this should not be done in show/hide events + Audio::getInstance().subscribeInput(); + subscribedToAudioIn = true; + } + + GenericForm::showEvent(event); } void AVForm::onVideoModesIndexChanged(int index) @@ -227,19 +253,6 @@ void AVForm::onVideoDevChanged(int index) Core::getInstance()->getAv()->sendNoVideo(); } -void AVForm::hideEvent(QHideEvent *) -{ - if (camVideoSurface) - { - camVideoSurface->setSource(nullptr); - killVideoSurface(); - } - videoDeviceList.clear(); - Audio& audio = Audio::getInstance(); - audio.unsubscribeInput(this); - audio.unsubscribeOutput(this); -} - void AVForm::getVideoDevices() { QString settingsInDev = Settings::getInstance().getVideoDev(); diff --git a/src/widget/form/settings/avform.h b/src/widget/form/settings/avform.h index 44833be44..42c1b40fd 100644 --- a/src/widget/form/settings/avform.h +++ b/src/widget/form/settings/avform.h @@ -39,7 +39,7 @@ class AVForm : public GenericForm public: AVForm(); ~AVForm(); - virtual QString getFormName() final override {return tr("Audio/Video");} + QString getFormName() final override {return tr("Audio/Video");} private: void getAudioInDevices(); @@ -64,15 +64,18 @@ private slots: void onVideoDevChanged(int index); void onVideoModesIndexChanged(int index); - virtual void hideEvent(QHideEvent*) final override; - virtual void showEvent(QShowEvent*) final override; - protected: - virtual bool eventFilter(QObject *o, QEvent *e) final override; void updateVideoModes(int curIndex); +private: + bool eventFilter(QObject *o, QEvent *e) final override; + + void hideEvent(QHideEvent* event) final override; + void showEvent(QShowEvent*event) final override; + private: Ui::AVSettings *bodyUI; + bool subscribedToAudioIn; VideoSurface *camVideoSurface; CameraSource &camera; QVector> videoDeviceList; From e73fd27d8b126dc00b9ff82ce7eb3a86e7beec99 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sun, 13 Dec 2015 23:02:48 +0100 Subject: [PATCH 038/210] fix: don't subscribe to in/out device when initialization failed --- src/audio/audio.cpp | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index c219c48e6..d444b5654 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -181,7 +181,7 @@ public: cleanupOutput(); } - void initInput(const QString& inDevDescr); + bool initInput(const QString& inDevDescr); bool initOutput(const QString& outDevDescr); void cleanupInput(); void cleanupOutput(); @@ -377,8 +377,12 @@ void Audio::subscribeInput() { QMutexLocker locker(&d->audioLock); - if (!d->alInDev) - d->initInput(Settings::getInstance().getInDev()); + if (!d->alInDev) { + if (!d->initInput(Settings::getInstance().getInDev())) { + qWarning("Failed to subscribe to audio input device."); + return; + } + } d->inSubscriptions++; qDebug() << "Subscribed to audio input device [" << d->inSubscriptions << "subscriptions ]"; @@ -402,13 +406,13 @@ void Audio::unsubscribeInput() d->cleanupInput(); } -void AudioPrivate::initInput(const QString& inDevDescr) +bool AudioPrivate::initInput(const QString& inDevDescr) { qDebug() << "Opening audio input" << inDevDescr; inputInitialized = false; if (inDevDescr == "none") - return; + return true; assert(!alInDev); @@ -447,18 +451,15 @@ void AudioPrivate::initInput(const QString& inDevDescr) qWarning() << "Cannot open input audio device" << inDevDescr; // Restart the capture if necessary - if (alInDev) - { + if (alInDev) { alcCaptureStart(alInDev); - } - else - { -#if (FIX_SND_PCM_PREPARE_BUG) - alcCaptureStart(alInDev); -#endif + } else { + qCritical() << "Failed to initialize audio input device:" << inDevDescr; + return false; } inputInitialized = true; + return true; } /** @@ -744,8 +745,12 @@ void Audio::subscribeOutput(SID& sid) { QMutexLocker locker(&d->audioLock); - if (!d->alOutDev) - d->initOutput(Settings::getInstance().getOutDev()); + if (!d->alOutDev) { + if (!d->initOutput(Settings::getInstance().getOutDev())) { + qWarning("Failed to subscribe to audio input device."); + return; + } + } alGenSources(1, &sid); assert(sid); From 44b8568e83d9e4fc52555a47d4b8f254446767da Mon Sep 17 00:00:00 2001 From: ovalseven8 Date: Sun, 20 Dec 2015 13:38:37 +0100 Subject: [PATCH 039/210] Rename smiley packs - Rename 'krepa098' -> 'Classic' - Rename 'cylgom' -> 'Basic' - Rename 'TwitterEmojiSimple' -> 'ASCII+Universe' - Rename 'TwitterEmojiSVG' -> 'Universe' --- .../LICENSE-GRAPHICS | 0 .../README.md | 0 smileys/ASCII+Universe/emoticons.xml | 2529 +++++++++++++++++ smileys/{cylgom => Basic}/MrSmith.png | Bin smileys/{cylgom => Basic}/X(.png | Bin smileys/{cylgom => Basic}/XD.png | Bin smileys/{cylgom => Basic}/XP.png | Bin smileys/{cylgom => Basic}/angel.png | Bin smileys/{cylgom => Basic}/angry.png | Bin smileys/{cylgom => Basic}/beer.png | Bin smileys/{cylgom => Basic}/bomb.png | Bin smileys/{cylgom => Basic}/bored.png | Bin smileys/{cylgom => Basic}/cookie.png | Bin smileys/{cylgom => Basic}/cool.png | Bin smileys/{cylgom => Basic}/crossing.png | Bin smileys/{cylgom => Basic}/crying.png | Bin smileys/{cylgom => Basic}/devil.png | Bin smileys/{cylgom => Basic}/diamond.png | Bin smileys/{cylgom => Basic}/doh.png | Bin smileys/{cylgom => Basic}/emoticons.xml | 0 smileys/{cylgom => Basic}/evil.png | Bin smileys/{cylgom => Basic}/eye.png | Bin smileys/{cylgom => Basic}/facepalm.png | Bin smileys/{cylgom => Basic}/finger.png | Bin smileys/{cylgom => Basic}/hacker_terminal.png | Bin smileys/{cylgom => Basic}/happysmile.png | Bin smileys/{cylgom => Basic}/heart.png | Bin smileys/{cylgom => Basic}/hi.png | Bin smileys/{cylgom => Basic}/highfive.png | Bin smileys/{cylgom => Basic}/hot.png | Bin smileys/{cylgom => Basic}/impressed.png | Bin smileys/{cylgom => Basic}/inlove.png | Bin smileys/{cylgom => Basic}/jealous.png | Bin smileys/{cylgom => Basic}/kiss.png | Bin smileys/{cylgom => Basic}/lol.png | Bin smileys/{cylgom => Basic}/moustache.png | Bin smileys/{cylgom => Basic}/nerd.png | Bin smileys/{cylgom => Basic}/nospeak.png | Bin smileys/{cylgom => Basic}/oops.png | Bin smileys/{cylgom => Basic}/party.png | Bin smileys/{cylgom => Basic}/pressed.png | Bin smileys/{cylgom => Basic}/rain.png | Bin smileys/{cylgom => Basic}/rocknroll.png | Bin smileys/{cylgom => Basic}/sad.png | Bin smileys/{cylgom => Basic}/shy.png | Bin smileys/{cylgom => Basic}/sleeping.png | Bin smileys/{cylgom => Basic}/smile.png | Bin smileys/{cylgom => Basic}/sniggering.png | Bin smileys/{cylgom => Basic}/suspicious.png | Bin smileys/{cylgom => Basic}/syringe.png | Bin smileys/{cylgom => Basic}/tongue.png | Bin smileys/{cylgom => Basic}/toxlocker.png | Bin smileys/{cylgom => Basic}/vomit.png | Bin smileys/{cylgom => Basic}/wasntme.png | Bin smileys/{cylgom => Basic}/whew.png | Bin smileys/{cylgom => Basic}/wink.png | Bin smileys/{cylgom => Basic}/wondering.png | Bin smileys/{cylgom => Basic}/yawn.png | Bin smileys/{krepa098 => Classic}/Kappa.png | Bin smileys/{krepa098 => Classic}/angry.png | Bin smileys/{krepa098 => Classic}/cool.png | Bin smileys/{krepa098 => Classic}/crying.png | Bin smileys/{krepa098 => Classic}/emoticons.xml | 0 smileys/{krepa098 => Classic}/happy.png | Bin smileys/{krepa098 => Classic}/laugh.png | Bin .../laugh_closed_eyes.png | Bin smileys/{krepa098 => Classic}/plain.png | Bin smileys/{krepa098 => Classic}/raw.svg | 0 smileys/{krepa098 => Classic}/sad.png | Bin smileys/{krepa098 => Classic}/scared.png | Bin smileys/{krepa098 => Classic}/smile.png | Bin smileys/{krepa098 => Classic}/stunned.png | Bin smileys/{krepa098 => Classic}/tongue.png | Bin smileys/{krepa098 => Classic}/uncertain.png | Bin smileys/{krepa098 => Classic}/wink.png | Bin smileys/TwitterEmojiSimple/emoticons.xml | 2529 ----------------- .../{TwitterEmojiSVG => Universe}/1f004.svg | 0 .../{TwitterEmojiSVG => Universe}/1f0cf.svg | 0 .../{TwitterEmojiSVG => Universe}/1f170.svg | 0 .../{TwitterEmojiSVG => Universe}/1f171.svg | 0 .../{TwitterEmojiSVG => Universe}/1f17e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f17f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f18e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f191.svg | 0 .../{TwitterEmojiSVG => Universe}/1f192.svg | 0 .../{TwitterEmojiSVG => Universe}/1f193.svg | 0 .../{TwitterEmojiSVG => Universe}/1f194.svg | 0 .../{TwitterEmojiSVG => Universe}/1f195.svg | 0 .../{TwitterEmojiSVG => Universe}/1f196.svg | 0 .../{TwitterEmojiSVG => Universe}/1f197.svg | 0 .../{TwitterEmojiSVG => Universe}/1f198.svg | 0 .../{TwitterEmojiSVG => Universe}/1f199.svg | 0 .../{TwitterEmojiSVG => Universe}/1f19a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f1e6.svg | 0 .../{TwitterEmojiSVG => Universe}/1f1e7.svg | 0 .../1f1e8-1f1f3.svg | 0 .../{TwitterEmojiSVG => Universe}/1f1e8.svg | 0 .../1f1e9-1f1ea.svg | 0 .../{TwitterEmojiSVG => Universe}/1f1e9.svg | 0 .../1f1ea-1f1f8.svg | 0 .../{TwitterEmojiSVG => Universe}/1f1ea.svg | 0 .../1f1eb-1f1f7.svg | 0 .../{TwitterEmojiSVG => Universe}/1f1eb.svg | 0 .../1f1ec-1f1e7.svg | 0 .../{TwitterEmojiSVG => Universe}/1f1ec.svg | 0 .../{TwitterEmojiSVG => Universe}/1f1ed.svg | 0 .../1f1ee-1f1f9.svg | 0 .../{TwitterEmojiSVG => Universe}/1f1ee.svg | 0 .../1f1ef-1f1f5.svg | 0 .../{TwitterEmojiSVG => Universe}/1f1ef.svg | 0 .../1f1f0-1f1f7.svg | 0 .../{TwitterEmojiSVG => Universe}/1f1f0.svg | 0 .../{TwitterEmojiSVG => Universe}/1f1f1.svg | 0 .../{TwitterEmojiSVG => Universe}/1f1f2.svg | 0 .../{TwitterEmojiSVG => Universe}/1f1f3.svg | 0 .../{TwitterEmojiSVG => Universe}/1f1f4.svg | 0 .../{TwitterEmojiSVG => Universe}/1f1f5.svg | 0 .../{TwitterEmojiSVG => Universe}/1f1f6.svg | 0 .../1f1f7-1f1fa.svg | 0 .../{TwitterEmojiSVG => Universe}/1f1f7.svg | 0 .../{TwitterEmojiSVG => Universe}/1f1f8.svg | 0 .../{TwitterEmojiSVG => Universe}/1f1f9.svg | 0 .../1f1fa-1f1f8.svg | 0 .../{TwitterEmojiSVG => Universe}/1f1fa.svg | 0 .../{TwitterEmojiSVG => Universe}/1f1fb.svg | 0 .../{TwitterEmojiSVG => Universe}/1f1fc.svg | 0 .../{TwitterEmojiSVG => Universe}/1f1fd.svg | 0 .../{TwitterEmojiSVG => Universe}/1f1fe.svg | 0 .../{TwitterEmojiSVG => Universe}/1f1ff.svg | 0 .../{TwitterEmojiSVG => Universe}/1f201.svg | 0 .../{TwitterEmojiSVG => Universe}/1f202.svg | 0 .../{TwitterEmojiSVG => Universe}/1f21a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f22f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f232.svg | 0 .../{TwitterEmojiSVG => Universe}/1f233.svg | 0 .../{TwitterEmojiSVG => Universe}/1f234.svg | 0 .../{TwitterEmojiSVG => Universe}/1f235.svg | 0 .../{TwitterEmojiSVG => Universe}/1f236.svg | 0 .../{TwitterEmojiSVG => Universe}/1f237.svg | 0 .../{TwitterEmojiSVG => Universe}/1f238.svg | 0 .../{TwitterEmojiSVG => Universe}/1f239.svg | 0 .../{TwitterEmojiSVG => Universe}/1f23a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f250.svg | 0 .../{TwitterEmojiSVG => Universe}/1f251.svg | 0 .../{TwitterEmojiSVG => Universe}/1f300.svg | 0 .../{TwitterEmojiSVG => Universe}/1f301.svg | 0 .../{TwitterEmojiSVG => Universe}/1f302.svg | 0 .../{TwitterEmojiSVG => Universe}/1f303.svg | 0 .../{TwitterEmojiSVG => Universe}/1f304.svg | 0 .../{TwitterEmojiSVG => Universe}/1f305.svg | 0 .../{TwitterEmojiSVG => Universe}/1f306.svg | 0 .../{TwitterEmojiSVG => Universe}/1f307.svg | 0 .../{TwitterEmojiSVG => Universe}/1f308.svg | 0 .../{TwitterEmojiSVG => Universe}/1f309.svg | 0 .../{TwitterEmojiSVG => Universe}/1f30a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f30b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f30c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f30d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f30e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f30f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f310.svg | 0 .../{TwitterEmojiSVG => Universe}/1f311.svg | 0 .../{TwitterEmojiSVG => Universe}/1f312.svg | 0 .../{TwitterEmojiSVG => Universe}/1f313.svg | 0 .../{TwitterEmojiSVG => Universe}/1f314.svg | 0 .../{TwitterEmojiSVG => Universe}/1f315.svg | 0 .../{TwitterEmojiSVG => Universe}/1f316.svg | 0 .../{TwitterEmojiSVG => Universe}/1f317.svg | 0 .../{TwitterEmojiSVG => Universe}/1f318.svg | 0 .../{TwitterEmojiSVG => Universe}/1f319.svg | 0 .../{TwitterEmojiSVG => Universe}/1f31a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f31b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f31c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f31d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f31e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f31f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f320.svg | 0 .../{TwitterEmojiSVG => Universe}/1f330.svg | 0 .../{TwitterEmojiSVG => Universe}/1f331.svg | 0 .../{TwitterEmojiSVG => Universe}/1f332.svg | 0 .../{TwitterEmojiSVG => Universe}/1f333.svg | 0 .../{TwitterEmojiSVG => Universe}/1f334.svg | 0 .../{TwitterEmojiSVG => Universe}/1f335.svg | 0 .../{TwitterEmojiSVG => Universe}/1f337.svg | 0 .../{TwitterEmojiSVG => Universe}/1f338.svg | 0 .../{TwitterEmojiSVG => Universe}/1f339.svg | 0 .../{TwitterEmojiSVG => Universe}/1f33a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f33b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f33c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f33d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f33e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f33f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f340.svg | 0 .../{TwitterEmojiSVG => Universe}/1f341.svg | 0 .../{TwitterEmojiSVG => Universe}/1f342.svg | 0 .../{TwitterEmojiSVG => Universe}/1f343.svg | 0 .../{TwitterEmojiSVG => Universe}/1f344.svg | 0 .../{TwitterEmojiSVG => Universe}/1f345.svg | 0 .../{TwitterEmojiSVG => Universe}/1f346.svg | 0 .../{TwitterEmojiSVG => Universe}/1f347.svg | 0 .../{TwitterEmojiSVG => Universe}/1f348.svg | 0 .../{TwitterEmojiSVG => Universe}/1f349.svg | 0 .../{TwitterEmojiSVG => Universe}/1f34a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f34b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f34c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f34d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f34e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f34f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f350.svg | 0 .../{TwitterEmojiSVG => Universe}/1f351.svg | 0 .../{TwitterEmojiSVG => Universe}/1f352.svg | 0 .../{TwitterEmojiSVG => Universe}/1f353.svg | 0 .../{TwitterEmojiSVG => Universe}/1f354.svg | 0 .../{TwitterEmojiSVG => Universe}/1f355.svg | 0 .../{TwitterEmojiSVG => Universe}/1f356.svg | 0 .../{TwitterEmojiSVG => Universe}/1f357.svg | 0 .../{TwitterEmojiSVG => Universe}/1f358.svg | 0 .../{TwitterEmojiSVG => Universe}/1f359.svg | 0 .../{TwitterEmojiSVG => Universe}/1f35a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f35b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f35c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f35d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f35e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f35f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f360.svg | 0 .../{TwitterEmojiSVG => Universe}/1f361.svg | 0 .../{TwitterEmojiSVG => Universe}/1f362.svg | 0 .../{TwitterEmojiSVG => Universe}/1f363.svg | 0 .../{TwitterEmojiSVG => Universe}/1f364.svg | 0 .../{TwitterEmojiSVG => Universe}/1f365.svg | 0 .../{TwitterEmojiSVG => Universe}/1f366.svg | 0 .../{TwitterEmojiSVG => Universe}/1f367.svg | 0 .../{TwitterEmojiSVG => Universe}/1f368.svg | 0 .../{TwitterEmojiSVG => Universe}/1f369.svg | 0 .../{TwitterEmojiSVG => Universe}/1f36a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f36b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f36c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f36d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f36e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f36f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f370.svg | 0 .../{TwitterEmojiSVG => Universe}/1f371.svg | 0 .../{TwitterEmojiSVG => Universe}/1f372.svg | 0 .../{TwitterEmojiSVG => Universe}/1f373.svg | 0 .../{TwitterEmojiSVG => Universe}/1f374.svg | 0 .../{TwitterEmojiSVG => Universe}/1f375.svg | 0 .../{TwitterEmojiSVG => Universe}/1f376.svg | 0 .../{TwitterEmojiSVG => Universe}/1f377.svg | 0 .../{TwitterEmojiSVG => Universe}/1f378.svg | 0 .../{TwitterEmojiSVG => Universe}/1f379.svg | 0 .../{TwitterEmojiSVG => Universe}/1f37a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f37b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f37c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f380.svg | 0 .../{TwitterEmojiSVG => Universe}/1f381.svg | 0 .../{TwitterEmojiSVG => Universe}/1f382.svg | 0 .../{TwitterEmojiSVG => Universe}/1f383.svg | 0 .../{TwitterEmojiSVG => Universe}/1f384.svg | 0 .../{TwitterEmojiSVG => Universe}/1f385.svg | 0 .../{TwitterEmojiSVG => Universe}/1f386.svg | 0 .../{TwitterEmojiSVG => Universe}/1f387.svg | 0 .../{TwitterEmojiSVG => Universe}/1f388.svg | 0 .../{TwitterEmojiSVG => Universe}/1f389.svg | 0 .../{TwitterEmojiSVG => Universe}/1f38a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f38b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f38c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f38d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f38e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f38f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f390.svg | 0 .../{TwitterEmojiSVG => Universe}/1f391.svg | 0 .../{TwitterEmojiSVG => Universe}/1f392.svg | 0 .../{TwitterEmojiSVG => Universe}/1f393.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3a0.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3a1.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3a2.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3a3.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3a4.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3a5.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3a6.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3a7.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3a8.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3a9.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3aa.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3ab.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3ac.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3ad.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3ae.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3af.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3b0.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3b1.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3b2.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3b3.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3b4.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3b5.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3b6.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3b7.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3b8.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3b9.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3ba.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3bb.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3bc.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3bd.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3be.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3bf.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3c0.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3c1.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3c2.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3c3.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3c4.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3c6.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3c7.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3c8.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3c9.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3ca.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3e0.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3e1.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3e2.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3e3.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3e4.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3e5.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3e6.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3e7.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3e8.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3e9.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3ea.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3eb.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3ec.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3ed.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3ee.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3ef.svg | 0 .../{TwitterEmojiSVG => Universe}/1f3f0.svg | 0 .../{TwitterEmojiSVG => Universe}/1f400.svg | 0 .../{TwitterEmojiSVG => Universe}/1f401.svg | 0 .../{TwitterEmojiSVG => Universe}/1f402.svg | 0 .../{TwitterEmojiSVG => Universe}/1f403.svg | 0 .../{TwitterEmojiSVG => Universe}/1f404.svg | 0 .../{TwitterEmojiSVG => Universe}/1f405.svg | 0 .../{TwitterEmojiSVG => Universe}/1f406.svg | 0 .../{TwitterEmojiSVG => Universe}/1f407.svg | 0 .../{TwitterEmojiSVG => Universe}/1f408.svg | 0 .../{TwitterEmojiSVG => Universe}/1f409.svg | 0 .../{TwitterEmojiSVG => Universe}/1f40a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f40b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f40c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f40d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f40e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f40f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f410.svg | 0 .../{TwitterEmojiSVG => Universe}/1f411.svg | 0 .../{TwitterEmojiSVG => Universe}/1f412.svg | 0 .../{TwitterEmojiSVG => Universe}/1f413.svg | 0 .../{TwitterEmojiSVG => Universe}/1f414.svg | 0 .../{TwitterEmojiSVG => Universe}/1f415.svg | 0 .../{TwitterEmojiSVG => Universe}/1f416.svg | 0 .../{TwitterEmojiSVG => Universe}/1f417.svg | 0 .../{TwitterEmojiSVG => Universe}/1f418.svg | 0 .../{TwitterEmojiSVG => Universe}/1f419.svg | 0 .../{TwitterEmojiSVG => Universe}/1f41a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f41b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f41c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f41d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f41e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f41f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f420.svg | 0 .../{TwitterEmojiSVG => Universe}/1f421.svg | 0 .../{TwitterEmojiSVG => Universe}/1f422.svg | 0 .../{TwitterEmojiSVG => Universe}/1f423.svg | 0 .../{TwitterEmojiSVG => Universe}/1f424.svg | 0 .../{TwitterEmojiSVG => Universe}/1f425.svg | 0 .../{TwitterEmojiSVG => Universe}/1f426.svg | 0 .../{TwitterEmojiSVG => Universe}/1f427.svg | 0 .../{TwitterEmojiSVG => Universe}/1f428.svg | 0 .../{TwitterEmojiSVG => Universe}/1f429.svg | 0 .../{TwitterEmojiSVG => Universe}/1f42a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f42b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f42c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f42d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f42e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f42f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f430.svg | 0 .../{TwitterEmojiSVG => Universe}/1f431.svg | 0 .../{TwitterEmojiSVG => Universe}/1f432.svg | 0 .../{TwitterEmojiSVG => Universe}/1f433.svg | 0 .../{TwitterEmojiSVG => Universe}/1f434.svg | 0 .../{TwitterEmojiSVG => Universe}/1f435.svg | 0 .../{TwitterEmojiSVG => Universe}/1f436.svg | 0 .../{TwitterEmojiSVG => Universe}/1f437.svg | 0 .../{TwitterEmojiSVG => Universe}/1f438.svg | 0 .../{TwitterEmojiSVG => Universe}/1f439.svg | 0 .../{TwitterEmojiSVG => Universe}/1f43a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f43b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f43c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f43d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f43e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f440.svg | 0 .../{TwitterEmojiSVG => Universe}/1f442.svg | 0 .../{TwitterEmojiSVG => Universe}/1f443.svg | 0 .../{TwitterEmojiSVG => Universe}/1f444.svg | 0 .../{TwitterEmojiSVG => Universe}/1f445.svg | 0 .../{TwitterEmojiSVG => Universe}/1f446.svg | 0 .../{TwitterEmojiSVG => Universe}/1f447.svg | 0 .../{TwitterEmojiSVG => Universe}/1f448.svg | 0 .../{TwitterEmojiSVG => Universe}/1f449.svg | 0 .../{TwitterEmojiSVG => Universe}/1f44a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f44b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f44c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f44d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f44e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f44f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f450.svg | 0 .../{TwitterEmojiSVG => Universe}/1f451.svg | 0 .../{TwitterEmojiSVG => Universe}/1f452.svg | 0 .../{TwitterEmojiSVG => Universe}/1f453.svg | 0 .../{TwitterEmojiSVG => Universe}/1f454.svg | 0 .../{TwitterEmojiSVG => Universe}/1f455.svg | 0 .../{TwitterEmojiSVG => Universe}/1f456.svg | 0 .../{TwitterEmojiSVG => Universe}/1f457.svg | 0 .../{TwitterEmojiSVG => Universe}/1f458.svg | 0 .../{TwitterEmojiSVG => Universe}/1f459.svg | 0 .../{TwitterEmojiSVG => Universe}/1f45a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f45b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f45c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f45d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f45e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f45f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f460.svg | 0 .../{TwitterEmojiSVG => Universe}/1f461.svg | 0 .../{TwitterEmojiSVG => Universe}/1f462.svg | 0 .../{TwitterEmojiSVG => Universe}/1f463.svg | 0 .../{TwitterEmojiSVG => Universe}/1f464.svg | 0 .../{TwitterEmojiSVG => Universe}/1f465.svg | 0 .../{TwitterEmojiSVG => Universe}/1f466.svg | 0 .../{TwitterEmojiSVG => Universe}/1f467.svg | 0 .../{TwitterEmojiSVG => Universe}/1f468.svg | 0 .../{TwitterEmojiSVG => Universe}/1f469.svg | 0 .../{TwitterEmojiSVG => Universe}/1f46a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f46b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f46c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f46d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f46e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f46f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f470.svg | 0 .../{TwitterEmojiSVG => Universe}/1f471.svg | 0 .../{TwitterEmojiSVG => Universe}/1f472.svg | 0 .../{TwitterEmojiSVG => Universe}/1f473.svg | 0 .../{TwitterEmojiSVG => Universe}/1f474.svg | 0 .../{TwitterEmojiSVG => Universe}/1f475.svg | 0 .../{TwitterEmojiSVG => Universe}/1f476.svg | 0 .../{TwitterEmojiSVG => Universe}/1f477.svg | 0 .../{TwitterEmojiSVG => Universe}/1f478.svg | 0 .../{TwitterEmojiSVG => Universe}/1f479.svg | 0 .../{TwitterEmojiSVG => Universe}/1f47a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f47b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f47c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f47d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f47e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f47f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f480.svg | 0 .../{TwitterEmojiSVG => Universe}/1f481.svg | 0 .../{TwitterEmojiSVG => Universe}/1f482.svg | 0 .../{TwitterEmojiSVG => Universe}/1f483.svg | 0 .../{TwitterEmojiSVG => Universe}/1f484.svg | 0 .../{TwitterEmojiSVG => Universe}/1f485.svg | 0 .../{TwitterEmojiSVG => Universe}/1f486.svg | 0 .../{TwitterEmojiSVG => Universe}/1f487.svg | 0 .../{TwitterEmojiSVG => Universe}/1f488.svg | 0 .../{TwitterEmojiSVG => Universe}/1f489.svg | 0 .../{TwitterEmojiSVG => Universe}/1f48a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f48b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f48c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f48d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f48e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f48f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f490.svg | 0 .../{TwitterEmojiSVG => Universe}/1f491.svg | 0 .../{TwitterEmojiSVG => Universe}/1f492.svg | 0 .../{TwitterEmojiSVG => Universe}/1f493.svg | 0 .../{TwitterEmojiSVG => Universe}/1f494.svg | 0 .../{TwitterEmojiSVG => Universe}/1f495.svg | 0 .../{TwitterEmojiSVG => Universe}/1f496.svg | 0 .../{TwitterEmojiSVG => Universe}/1f497.svg | 0 .../{TwitterEmojiSVG => Universe}/1f498.svg | 0 .../{TwitterEmojiSVG => Universe}/1f499.svg | 0 .../{TwitterEmojiSVG => Universe}/1f49a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f49b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f49c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f49d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f49e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f49f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4a0.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4a1.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4a2.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4a3.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4a4.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4a5.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4a6.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4a7.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4a8.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4a9.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4aa.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4ab.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4ac.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4ad.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4ae.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4af.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4b0.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4b1.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4b2.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4b3.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4b4.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4b5.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4b6.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4b7.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4b8.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4b9.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4ba.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4bb.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4bc.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4bd.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4be.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4bf.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4c0.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4c1.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4c2.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4c3.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4c4.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4c5.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4c6.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4c7.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4c8.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4c9.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4ca.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4cb.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4cc.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4cd.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4ce.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4cf.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4d0.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4d1.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4d2.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4d3.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4d4.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4d5.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4d6.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4d7.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4d8.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4d9.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4da.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4db.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4dc.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4dd.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4de.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4df.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4e0.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4e1.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4e2.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4e3.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4e4.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4e5.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4e6.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4e7.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4e8.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4e9.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4ea.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4eb.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4ec.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4ed.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4ee.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4ef.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4f0.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4f1.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4f2.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4f3.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4f4.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4f5.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4f6.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4f7.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4f9.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4fa.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4fb.svg | 0 .../{TwitterEmojiSVG => Universe}/1f4fc.svg | 0 .../{TwitterEmojiSVG => Universe}/1f500.svg | 0 .../{TwitterEmojiSVG => Universe}/1f501.svg | 0 .../{TwitterEmojiSVG => Universe}/1f502.svg | 0 .../{TwitterEmojiSVG => Universe}/1f503.svg | 0 .../{TwitterEmojiSVG => Universe}/1f504.svg | 0 .../{TwitterEmojiSVG => Universe}/1f505.svg | 0 .../{TwitterEmojiSVG => Universe}/1f506.svg | 0 .../{TwitterEmojiSVG => Universe}/1f507.svg | 0 .../{TwitterEmojiSVG => Universe}/1f508.svg | 0 .../{TwitterEmojiSVG => Universe}/1f509.svg | 0 .../{TwitterEmojiSVG => Universe}/1f50a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f50b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f50c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f50d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f50e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f50f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f510.svg | 0 .../{TwitterEmojiSVG => Universe}/1f511.svg | 0 .../{TwitterEmojiSVG => Universe}/1f512.svg | 0 .../{TwitterEmojiSVG => Universe}/1f513.svg | 0 .../{TwitterEmojiSVG => Universe}/1f514.svg | 0 .../{TwitterEmojiSVG => Universe}/1f515.svg | 0 .../{TwitterEmojiSVG => Universe}/1f516.svg | 0 .../{TwitterEmojiSVG => Universe}/1f517.svg | 0 .../{TwitterEmojiSVG => Universe}/1f518.svg | 0 .../{TwitterEmojiSVG => Universe}/1f519.svg | 0 .../{TwitterEmojiSVG => Universe}/1f51a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f51b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f51c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f51d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f51e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f51f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f520.svg | 0 .../{TwitterEmojiSVG => Universe}/1f521.svg | 0 .../{TwitterEmojiSVG => Universe}/1f522.svg | 0 .../{TwitterEmojiSVG => Universe}/1f523.svg | 0 .../{TwitterEmojiSVG => Universe}/1f524.svg | 0 .../{TwitterEmojiSVG => Universe}/1f525.svg | 0 .../{TwitterEmojiSVG => Universe}/1f526.svg | 0 .../{TwitterEmojiSVG => Universe}/1f527.svg | 0 .../{TwitterEmojiSVG => Universe}/1f528.svg | 0 .../{TwitterEmojiSVG => Universe}/1f529.svg | 0 .../{TwitterEmojiSVG => Universe}/1f52a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f52b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f52c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f52d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f52e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f52f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f530.svg | 0 .../{TwitterEmojiSVG => Universe}/1f531.svg | 0 .../{TwitterEmojiSVG => Universe}/1f532.svg | 0 .../{TwitterEmojiSVG => Universe}/1f533.svg | 0 .../{TwitterEmojiSVG => Universe}/1f534.svg | 0 .../{TwitterEmojiSVG => Universe}/1f535.svg | 0 .../{TwitterEmojiSVG => Universe}/1f536.svg | 0 .../{TwitterEmojiSVG => Universe}/1f537.svg | 0 .../{TwitterEmojiSVG => Universe}/1f538.svg | 0 .../{TwitterEmojiSVG => Universe}/1f539.svg | 0 .../{TwitterEmojiSVG => Universe}/1f53a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f53b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f53c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f53d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f550.svg | 0 .../{TwitterEmojiSVG => Universe}/1f551.svg | 0 .../{TwitterEmojiSVG => Universe}/1f552.svg | 0 .../{TwitterEmojiSVG => Universe}/1f553.svg | 0 .../{TwitterEmojiSVG => Universe}/1f554.svg | 0 .../{TwitterEmojiSVG => Universe}/1f555.svg | 0 .../{TwitterEmojiSVG => Universe}/1f556.svg | 0 .../{TwitterEmojiSVG => Universe}/1f557.svg | 0 .../{TwitterEmojiSVG => Universe}/1f558.svg | 0 .../{TwitterEmojiSVG => Universe}/1f559.svg | 0 .../{TwitterEmojiSVG => Universe}/1f55a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f55b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f55c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f55d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f55e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f55f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f560.svg | 0 .../{TwitterEmojiSVG => Universe}/1f561.svg | 0 .../{TwitterEmojiSVG => Universe}/1f562.svg | 0 .../{TwitterEmojiSVG => Universe}/1f563.svg | 0 .../{TwitterEmojiSVG => Universe}/1f564.svg | 0 .../{TwitterEmojiSVG => Universe}/1f565.svg | 0 .../{TwitterEmojiSVG => Universe}/1f566.svg | 0 .../{TwitterEmojiSVG => Universe}/1f567.svg | 0 .../{TwitterEmojiSVG => Universe}/1f595.svg | 0 .../{TwitterEmojiSVG => Universe}/1f5fb.svg | 0 .../{TwitterEmojiSVG => Universe}/1f5fc.svg | 0 .../{TwitterEmojiSVG => Universe}/1f5fd.svg | 0 .../{TwitterEmojiSVG => Universe}/1f5fe.svg | 0 .../{TwitterEmojiSVG => Universe}/1f5ff.svg | 0 .../{TwitterEmojiSVG => Universe}/1f600.svg | 0 .../{TwitterEmojiSVG => Universe}/1f601.svg | 0 .../{TwitterEmojiSVG => Universe}/1f602.svg | 0 .../{TwitterEmojiSVG => Universe}/1f603.svg | 0 .../{TwitterEmojiSVG => Universe}/1f604.svg | 0 .../{TwitterEmojiSVG => Universe}/1f605.svg | 0 .../{TwitterEmojiSVG => Universe}/1f606.svg | 0 .../{TwitterEmojiSVG => Universe}/1f607.svg | 0 .../{TwitterEmojiSVG => Universe}/1f608.svg | 0 .../{TwitterEmojiSVG => Universe}/1f609.svg | 0 .../{TwitterEmojiSVG => Universe}/1f60a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f60b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f60c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f60d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f60e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f60f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f610.svg | 0 .../{TwitterEmojiSVG => Universe}/1f611.svg | 0 .../{TwitterEmojiSVG => Universe}/1f612.svg | 0 .../{TwitterEmojiSVG => Universe}/1f613.svg | 0 .../{TwitterEmojiSVG => Universe}/1f614.svg | 0 .../{TwitterEmojiSVG => Universe}/1f615.svg | 0 .../{TwitterEmojiSVG => Universe}/1f616.svg | 0 .../{TwitterEmojiSVG => Universe}/1f617.svg | 0 .../{TwitterEmojiSVG => Universe}/1f618.svg | 0 .../{TwitterEmojiSVG => Universe}/1f619.svg | 0 .../{TwitterEmojiSVG => Universe}/1f61a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f61b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f61c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f61d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f61e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f61f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f620.svg | 0 .../{TwitterEmojiSVG => Universe}/1f621.svg | 0 .../{TwitterEmojiSVG => Universe}/1f622.svg | 0 .../{TwitterEmojiSVG => Universe}/1f623.svg | 0 .../{TwitterEmojiSVG => Universe}/1f624.svg | 0 .../{TwitterEmojiSVG => Universe}/1f625.svg | 0 .../{TwitterEmojiSVG => Universe}/1f626.svg | 0 .../{TwitterEmojiSVG => Universe}/1f627.svg | 0 .../{TwitterEmojiSVG => Universe}/1f628.svg | 0 .../{TwitterEmojiSVG => Universe}/1f629.svg | 0 .../{TwitterEmojiSVG => Universe}/1f62a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f62b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f62c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f62d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f62e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f62f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f630.svg | 0 .../{TwitterEmojiSVG => Universe}/1f631.svg | 0 .../{TwitterEmojiSVG => Universe}/1f632.svg | 0 .../{TwitterEmojiSVG => Universe}/1f633.svg | 0 .../{TwitterEmojiSVG => Universe}/1f634.svg | 0 .../{TwitterEmojiSVG => Universe}/1f635.svg | 0 .../{TwitterEmojiSVG => Universe}/1f636.svg | 0 .../{TwitterEmojiSVG => Universe}/1f637.svg | 0 .../{TwitterEmojiSVG => Universe}/1f638.svg | 0 .../{TwitterEmojiSVG => Universe}/1f639.svg | 0 .../{TwitterEmojiSVG => Universe}/1f63a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f63b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f63c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f63d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f63e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f63f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f640.svg | 0 .../{TwitterEmojiSVG => Universe}/1f645.svg | 0 .../{TwitterEmojiSVG => Universe}/1f646.svg | 0 .../{TwitterEmojiSVG => Universe}/1f647.svg | 0 .../{TwitterEmojiSVG => Universe}/1f648.svg | 0 .../{TwitterEmojiSVG => Universe}/1f649.svg | 0 .../{TwitterEmojiSVG => Universe}/1f64a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f64b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f64c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f64d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f64e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f64f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f680.svg | 0 .../{TwitterEmojiSVG => Universe}/1f681.svg | 0 .../{TwitterEmojiSVG => Universe}/1f682.svg | 0 .../{TwitterEmojiSVG => Universe}/1f683.svg | 0 .../{TwitterEmojiSVG => Universe}/1f684.svg | 0 .../{TwitterEmojiSVG => Universe}/1f685.svg | 0 .../{TwitterEmojiSVG => Universe}/1f686.svg | 0 .../{TwitterEmojiSVG => Universe}/1f687.svg | 0 .../{TwitterEmojiSVG => Universe}/1f688.svg | 0 .../{TwitterEmojiSVG => Universe}/1f689.svg | 0 .../{TwitterEmojiSVG => Universe}/1f68a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f68b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f68c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f68d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f68e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f68f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f690.svg | 0 .../{TwitterEmojiSVG => Universe}/1f691.svg | 0 .../{TwitterEmojiSVG => Universe}/1f692.svg | 0 .../{TwitterEmojiSVG => Universe}/1f693.svg | 0 .../{TwitterEmojiSVG => Universe}/1f694.svg | 0 .../{TwitterEmojiSVG => Universe}/1f695.svg | 0 .../{TwitterEmojiSVG => Universe}/1f696.svg | 0 .../{TwitterEmojiSVG => Universe}/1f697.svg | 0 .../{TwitterEmojiSVG => Universe}/1f698.svg | 0 .../{TwitterEmojiSVG => Universe}/1f699.svg | 0 .../{TwitterEmojiSVG => Universe}/1f69a.svg | 0 .../{TwitterEmojiSVG => Universe}/1f69b.svg | 0 .../{TwitterEmojiSVG => Universe}/1f69c.svg | 0 .../{TwitterEmojiSVG => Universe}/1f69d.svg | 0 .../{TwitterEmojiSVG => Universe}/1f69e.svg | 0 .../{TwitterEmojiSVG => Universe}/1f69f.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6a0.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6a1.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6a2.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6a3.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6a4.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6a5.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6a6.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6a7.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6a8.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6a9.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6aa.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6ab.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6ac.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6ad.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6ae.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6af.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6b0.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6b1.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6b2.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6b3.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6b4.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6b5.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6b6.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6b7.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6b8.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6b9.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6ba.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6bb.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6bc.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6bd.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6be.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6bf.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6c0.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6c1.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6c2.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6c3.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6c4.svg | 0 .../{TwitterEmojiSVG => Universe}/1f6c5.svg | 0 .../{TwitterEmojiSVG => Universe}/203c.svg | 0 .../{TwitterEmojiSVG => Universe}/2049.svg | 0 .../{TwitterEmojiSVG => Universe}/2122.svg | 0 .../{TwitterEmojiSVG => Universe}/2139.svg | 0 .../{TwitterEmojiSVG => Universe}/2194.svg | 0 .../{TwitterEmojiSVG => Universe}/2195.svg | 0 .../{TwitterEmojiSVG => Universe}/2196.svg | 0 .../{TwitterEmojiSVG => Universe}/2197.svg | 0 .../{TwitterEmojiSVG => Universe}/2198.svg | 0 .../{TwitterEmojiSVG => Universe}/2199.svg | 0 .../{TwitterEmojiSVG => Universe}/21a9.svg | 0 .../{TwitterEmojiSVG => Universe}/21aa.svg | 0 .../{TwitterEmojiSVG => Universe}/23-20e3.svg | 0 .../{TwitterEmojiSVG => Universe}/231a.svg | 0 .../{TwitterEmojiSVG => Universe}/231b.svg | 0 .../{TwitterEmojiSVG => Universe}/23e9.svg | 0 .../{TwitterEmojiSVG => Universe}/23ea.svg | 0 .../{TwitterEmojiSVG => Universe}/23eb.svg | 0 .../{TwitterEmojiSVG => Universe}/23ec.svg | 0 .../{TwitterEmojiSVG => Universe}/23f0.svg | 0 .../{TwitterEmojiSVG => Universe}/23f3.svg | 0 .../{TwitterEmojiSVG => Universe}/24c2.svg | 0 .../{TwitterEmojiSVG => Universe}/25aa.svg | 0 .../{TwitterEmojiSVG => Universe}/25ab.svg | 0 .../{TwitterEmojiSVG => Universe}/25b6.svg | 0 .../{TwitterEmojiSVG => Universe}/25c0.svg | 0 .../{TwitterEmojiSVG => Universe}/25fb.svg | 0 .../{TwitterEmojiSVG => Universe}/25fc.svg | 0 .../{TwitterEmojiSVG => Universe}/25fd.svg | 0 .../{TwitterEmojiSVG => Universe}/25fe.svg | 0 .../{TwitterEmojiSVG => Universe}/2600.svg | 0 .../{TwitterEmojiSVG => Universe}/2601.svg | 0 .../{TwitterEmojiSVG => Universe}/260e.svg | 0 .../{TwitterEmojiSVG => Universe}/2611.svg | 0 .../{TwitterEmojiSVG => Universe}/2614.svg | 0 .../{TwitterEmojiSVG => Universe}/2615.svg | 0 .../{TwitterEmojiSVG => Universe}/261d.svg | 0 .../{TwitterEmojiSVG => Universe}/263a.svg | 0 .../{TwitterEmojiSVG => Universe}/2648.svg | 0 .../{TwitterEmojiSVG => Universe}/2649.svg | 0 .../{TwitterEmojiSVG => Universe}/264a.svg | 0 .../{TwitterEmojiSVG => Universe}/264b.svg | 0 .../{TwitterEmojiSVG => Universe}/264c.svg | 0 .../{TwitterEmojiSVG => Universe}/264d.svg | 0 .../{TwitterEmojiSVG => Universe}/264e.svg | 0 .../{TwitterEmojiSVG => Universe}/264f.svg | 0 .../{TwitterEmojiSVG => Universe}/2650.svg | 0 .../{TwitterEmojiSVG => Universe}/2651.svg | 0 .../{TwitterEmojiSVG => Universe}/2652.svg | 0 .../{TwitterEmojiSVG => Universe}/2653.svg | 0 .../{TwitterEmojiSVG => Universe}/2660.svg | 0 .../{TwitterEmojiSVG => Universe}/2663.svg | 0 .../{TwitterEmojiSVG => Universe}/2665.svg | 0 .../{TwitterEmojiSVG => Universe}/2666.svg | 0 .../{TwitterEmojiSVG => Universe}/2668.svg | 0 .../{TwitterEmojiSVG => Universe}/267b.svg | 0 .../{TwitterEmojiSVG => Universe}/267f.svg | 0 .../{TwitterEmojiSVG => Universe}/2693.svg | 0 .../{TwitterEmojiSVG => Universe}/26a0.svg | 0 .../{TwitterEmojiSVG => Universe}/26a1.svg | 0 .../{TwitterEmojiSVG => Universe}/26aa.svg | 0 .../{TwitterEmojiSVG => Universe}/26ab.svg | 0 .../{TwitterEmojiSVG => Universe}/26bd.svg | 0 .../{TwitterEmojiSVG => Universe}/26be.svg | 0 .../{TwitterEmojiSVG => Universe}/26c4.svg | 0 .../{TwitterEmojiSVG => Universe}/26c5.svg | 0 .../{TwitterEmojiSVG => Universe}/26ce.svg | 0 .../{TwitterEmojiSVG => Universe}/26d4.svg | 0 .../{TwitterEmojiSVG => Universe}/26ea.svg | 0 .../{TwitterEmojiSVG => Universe}/26f2.svg | 0 .../{TwitterEmojiSVG => Universe}/26f3.svg | 0 .../{TwitterEmojiSVG => Universe}/26f5.svg | 0 .../{TwitterEmojiSVG => Universe}/26fa.svg | 0 .../{TwitterEmojiSVG => Universe}/26fd.svg | 0 .../{TwitterEmojiSVG => Universe}/2702.svg | 0 .../{TwitterEmojiSVG => Universe}/2705.svg | 0 .../{TwitterEmojiSVG => Universe}/2708.svg | 0 .../{TwitterEmojiSVG => Universe}/2709.svg | 0 .../{TwitterEmojiSVG => Universe}/270a.svg | 0 .../{TwitterEmojiSVG => Universe}/270b.svg | 0 .../{TwitterEmojiSVG => Universe}/270c.svg | 0 .../{TwitterEmojiSVG => Universe}/270f.svg | 0 .../{TwitterEmojiSVG => Universe}/2712.svg | 0 .../{TwitterEmojiSVG => Universe}/2714.svg | 0 .../{TwitterEmojiSVG => Universe}/2716.svg | 0 .../{TwitterEmojiSVG => Universe}/2728.svg | 0 .../{TwitterEmojiSVG => Universe}/2733.svg | 0 .../{TwitterEmojiSVG => Universe}/2734.svg | 0 .../{TwitterEmojiSVG => Universe}/2744.svg | 0 .../{TwitterEmojiSVG => Universe}/2747.svg | 0 .../{TwitterEmojiSVG => Universe}/274c.svg | 0 .../{TwitterEmojiSVG => Universe}/274e.svg | 0 .../{TwitterEmojiSVG => Universe}/2753.svg | 0 .../{TwitterEmojiSVG => Universe}/2754.svg | 0 .../{TwitterEmojiSVG => Universe}/2755.svg | 0 .../{TwitterEmojiSVG => Universe}/2757.svg | 0 .../{TwitterEmojiSVG => Universe}/2764.svg | 0 .../{TwitterEmojiSVG => Universe}/2795.svg | 0 .../{TwitterEmojiSVG => Universe}/2796.svg | 0 .../{TwitterEmojiSVG => Universe}/2797.svg | 0 .../{TwitterEmojiSVG => Universe}/27a1.svg | 0 .../{TwitterEmojiSVG => Universe}/27b0.svg | 0 .../{TwitterEmojiSVG => Universe}/27bf.svg | 0 .../{TwitterEmojiSVG => Universe}/2934.svg | 0 .../{TwitterEmojiSVG => Universe}/2935.svg | 0 .../{TwitterEmojiSVG => Universe}/2b05.svg | 0 .../{TwitterEmojiSVG => Universe}/2b06.svg | 0 .../{TwitterEmojiSVG => Universe}/2b07.svg | 0 .../{TwitterEmojiSVG => Universe}/2b1b.svg | 0 .../{TwitterEmojiSVG => Universe}/2b1c.svg | 0 .../{TwitterEmojiSVG => Universe}/2b50.svg | 0 .../{TwitterEmojiSVG => Universe}/2b55.svg | 0 .../{TwitterEmojiSVG => Universe}/30-20e3.svg | 0 .../{TwitterEmojiSVG => Universe}/3030.svg | 0 .../{TwitterEmojiSVG => Universe}/303d.svg | 0 .../{TwitterEmojiSVG => Universe}/31-20e3.svg | 0 .../{TwitterEmojiSVG => Universe}/32-20e3.svg | 0 .../{TwitterEmojiSVG => Universe}/3297.svg | 0 .../{TwitterEmojiSVG => Universe}/3299.svg | 0 .../{TwitterEmojiSVG => Universe}/33-20e3.svg | 0 .../{TwitterEmojiSVG => Universe}/34-20e3.svg | 0 .../{TwitterEmojiSVG => Universe}/35-20e3.svg | 0 .../{TwitterEmojiSVG => Universe}/36-20e3.svg | 0 .../{TwitterEmojiSVG => Universe}/37-20e3.svg | 0 .../{TwitterEmojiSVG => Universe}/38-20e3.svg | 0 .../{TwitterEmojiSVG => Universe}/39-20e3.svg | 0 smileys/{TwitterEmojiSVG => Universe}/LICENSE | 0 .../LICENSE-GRAPHICS | 0 .../README.md | 0 smileys/{TwitterEmojiSVG => Universe}/a9.svg | 0 smileys/{TwitterEmojiSVG => Universe}/ae.svg | 0 .../{TwitterEmojiSVG => Universe}/e50a.svg | 0 .../emoticons.xml | 0 smileys/smileys.qrc | 1796 ++++++------ 954 files changed, 3427 insertions(+), 3427 deletions(-) rename smileys/{TwitterEmojiSVG => ASCII+Universe}/LICENSE-GRAPHICS (100%) rename smileys/{TwitterEmojiSVG => ASCII+Universe}/README.md (100%) create mode 100644 smileys/ASCII+Universe/emoticons.xml rename smileys/{cylgom => Basic}/MrSmith.png (100%) rename smileys/{cylgom => Basic}/X(.png (100%) rename smileys/{cylgom => Basic}/XD.png (100%) rename smileys/{cylgom => Basic}/XP.png (100%) rename smileys/{cylgom => Basic}/angel.png (100%) rename smileys/{cylgom => Basic}/angry.png (100%) rename smileys/{cylgom => Basic}/beer.png (100%) rename smileys/{cylgom => Basic}/bomb.png (100%) rename smileys/{cylgom => Basic}/bored.png (100%) rename smileys/{cylgom => Basic}/cookie.png (100%) rename smileys/{cylgom => Basic}/cool.png (100%) rename smileys/{cylgom => Basic}/crossing.png (100%) rename smileys/{cylgom => Basic}/crying.png (100%) rename smileys/{cylgom => Basic}/devil.png (100%) rename smileys/{cylgom => Basic}/diamond.png (100%) rename smileys/{cylgom => Basic}/doh.png (100%) rename smileys/{cylgom => Basic}/emoticons.xml (100%) rename smileys/{cylgom => Basic}/evil.png (100%) rename smileys/{cylgom => Basic}/eye.png (100%) rename smileys/{cylgom => Basic}/facepalm.png (100%) rename smileys/{cylgom => Basic}/finger.png (100%) rename smileys/{cylgom => Basic}/hacker_terminal.png (100%) rename smileys/{cylgom => Basic}/happysmile.png (100%) rename smileys/{cylgom => Basic}/heart.png (100%) rename smileys/{cylgom => Basic}/hi.png (100%) rename smileys/{cylgom => Basic}/highfive.png (100%) rename smileys/{cylgom => Basic}/hot.png (100%) rename smileys/{cylgom => Basic}/impressed.png (100%) rename smileys/{cylgom => Basic}/inlove.png (100%) rename smileys/{cylgom => Basic}/jealous.png (100%) rename smileys/{cylgom => Basic}/kiss.png (100%) rename smileys/{cylgom => Basic}/lol.png (100%) rename smileys/{cylgom => Basic}/moustache.png (100%) rename smileys/{cylgom => Basic}/nerd.png (100%) rename smileys/{cylgom => Basic}/nospeak.png (100%) rename smileys/{cylgom => Basic}/oops.png (100%) rename smileys/{cylgom => Basic}/party.png (100%) rename smileys/{cylgom => Basic}/pressed.png (100%) rename smileys/{cylgom => Basic}/rain.png (100%) rename smileys/{cylgom => Basic}/rocknroll.png (100%) rename smileys/{cylgom => Basic}/sad.png (100%) rename smileys/{cylgom => Basic}/shy.png (100%) rename smileys/{cylgom => Basic}/sleeping.png (100%) rename smileys/{cylgom => Basic}/smile.png (100%) rename smileys/{cylgom => Basic}/sniggering.png (100%) rename smileys/{cylgom => Basic}/suspicious.png (100%) rename smileys/{cylgom => Basic}/syringe.png (100%) rename smileys/{cylgom => Basic}/tongue.png (100%) rename smileys/{cylgom => Basic}/toxlocker.png (100%) rename smileys/{cylgom => Basic}/vomit.png (100%) rename smileys/{cylgom => Basic}/wasntme.png (100%) rename smileys/{cylgom => Basic}/whew.png (100%) rename smileys/{cylgom => Basic}/wink.png (100%) rename smileys/{cylgom => Basic}/wondering.png (100%) rename smileys/{cylgom => Basic}/yawn.png (100%) rename smileys/{krepa098 => Classic}/Kappa.png (100%) rename smileys/{krepa098 => Classic}/angry.png (100%) rename smileys/{krepa098 => Classic}/cool.png (100%) rename smileys/{krepa098 => Classic}/crying.png (100%) rename smileys/{krepa098 => Classic}/emoticons.xml (100%) rename smileys/{krepa098 => Classic}/happy.png (100%) rename smileys/{krepa098 => Classic}/laugh.png (100%) rename smileys/{krepa098 => Classic}/laugh_closed_eyes.png (100%) rename smileys/{krepa098 => Classic}/plain.png (100%) rename smileys/{krepa098 => Classic}/raw.svg (100%) rename smileys/{krepa098 => Classic}/sad.png (100%) rename smileys/{krepa098 => Classic}/scared.png (100%) rename smileys/{krepa098 => Classic}/smile.png (100%) rename smileys/{krepa098 => Classic}/stunned.png (100%) rename smileys/{krepa098 => Classic}/tongue.png (100%) rename smileys/{krepa098 => Classic}/uncertain.png (100%) rename smileys/{krepa098 => Classic}/wink.png (100%) delete mode 100644 smileys/TwitterEmojiSimple/emoticons.xml rename smileys/{TwitterEmojiSVG => Universe}/1f004.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f0cf.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f170.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f171.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f17e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f17f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f18e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f191.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f192.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f193.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f194.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f195.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f196.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f197.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f198.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f199.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f19a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1e6.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1e7.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1e8-1f1f3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1e8.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1e9-1f1ea.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1e9.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1ea-1f1f8.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1ea.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1eb-1f1f7.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1eb.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1ec-1f1e7.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1ec.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1ed.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1ee-1f1f9.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1ee.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1ef-1f1f5.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1ef.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1f0-1f1f7.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1f0.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1f1.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1f2.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1f3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1f4.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1f5.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1f6.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1f7-1f1fa.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1f7.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1f8.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1f9.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1fa-1f1f8.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1fa.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1fb.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1fc.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1fd.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1fe.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f1ff.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f201.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f202.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f21a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f22f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f232.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f233.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f234.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f235.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f236.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f237.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f238.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f239.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f23a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f250.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f251.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f300.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f301.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f302.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f303.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f304.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f305.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f306.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f307.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f308.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f309.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f30a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f30b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f30c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f30d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f30e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f30f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f310.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f311.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f312.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f313.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f314.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f315.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f316.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f317.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f318.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f319.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f31a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f31b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f31c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f31d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f31e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f31f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f320.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f330.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f331.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f332.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f333.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f334.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f335.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f337.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f338.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f339.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f33a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f33b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f33c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f33d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f33e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f33f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f340.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f341.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f342.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f343.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f344.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f345.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f346.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f347.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f348.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f349.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f34a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f34b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f34c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f34d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f34e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f34f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f350.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f351.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f352.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f353.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f354.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f355.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f356.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f357.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f358.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f359.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f35a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f35b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f35c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f35d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f35e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f35f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f360.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f361.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f362.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f363.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f364.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f365.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f366.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f367.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f368.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f369.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f36a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f36b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f36c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f36d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f36e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f36f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f370.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f371.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f372.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f373.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f374.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f375.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f376.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f377.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f378.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f379.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f37a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f37b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f37c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f380.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f381.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f382.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f383.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f384.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f385.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f386.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f387.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f388.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f389.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f38a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f38b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f38c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f38d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f38e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f38f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f390.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f391.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f392.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f393.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3a0.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3a1.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3a2.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3a3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3a4.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3a5.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3a6.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3a7.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3a8.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3a9.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3aa.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3ab.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3ac.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3ad.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3ae.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3af.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3b0.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3b1.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3b2.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3b3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3b4.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3b5.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3b6.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3b7.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3b8.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3b9.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3ba.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3bb.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3bc.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3bd.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3be.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3bf.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3c0.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3c1.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3c2.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3c3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3c4.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3c6.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3c7.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3c8.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3c9.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3ca.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3e0.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3e1.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3e2.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3e3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3e4.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3e5.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3e6.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3e7.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3e8.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3e9.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3ea.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3eb.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3ec.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3ed.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3ee.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3ef.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f3f0.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f400.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f401.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f402.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f403.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f404.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f405.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f406.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f407.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f408.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f409.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f40a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f40b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f40c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f40d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f40e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f40f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f410.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f411.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f412.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f413.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f414.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f415.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f416.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f417.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f418.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f419.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f41a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f41b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f41c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f41d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f41e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f41f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f420.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f421.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f422.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f423.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f424.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f425.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f426.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f427.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f428.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f429.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f42a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f42b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f42c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f42d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f42e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f42f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f430.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f431.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f432.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f433.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f434.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f435.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f436.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f437.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f438.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f439.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f43a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f43b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f43c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f43d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f43e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f440.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f442.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f443.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f444.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f445.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f446.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f447.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f448.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f449.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f44a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f44b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f44c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f44d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f44e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f44f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f450.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f451.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f452.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f453.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f454.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f455.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f456.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f457.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f458.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f459.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f45a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f45b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f45c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f45d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f45e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f45f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f460.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f461.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f462.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f463.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f464.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f465.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f466.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f467.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f468.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f469.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f46a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f46b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f46c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f46d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f46e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f46f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f470.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f471.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f472.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f473.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f474.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f475.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f476.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f477.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f478.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f479.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f47a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f47b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f47c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f47d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f47e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f47f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f480.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f481.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f482.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f483.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f484.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f485.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f486.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f487.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f488.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f489.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f48a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f48b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f48c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f48d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f48e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f48f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f490.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f491.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f492.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f493.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f494.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f495.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f496.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f497.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f498.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f499.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f49a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f49b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f49c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f49d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f49e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f49f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4a0.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4a1.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4a2.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4a3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4a4.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4a5.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4a6.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4a7.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4a8.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4a9.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4aa.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4ab.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4ac.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4ad.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4ae.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4af.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4b0.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4b1.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4b2.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4b3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4b4.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4b5.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4b6.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4b7.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4b8.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4b9.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4ba.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4bb.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4bc.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4bd.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4be.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4bf.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4c0.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4c1.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4c2.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4c3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4c4.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4c5.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4c6.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4c7.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4c8.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4c9.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4ca.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4cb.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4cc.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4cd.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4ce.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4cf.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4d0.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4d1.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4d2.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4d3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4d4.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4d5.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4d6.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4d7.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4d8.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4d9.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4da.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4db.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4dc.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4dd.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4de.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4df.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4e0.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4e1.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4e2.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4e3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4e4.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4e5.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4e6.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4e7.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4e8.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4e9.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4ea.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4eb.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4ec.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4ed.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4ee.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4ef.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4f0.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4f1.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4f2.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4f3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4f4.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4f5.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4f6.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4f7.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4f9.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4fa.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4fb.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f4fc.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f500.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f501.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f502.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f503.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f504.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f505.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f506.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f507.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f508.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f509.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f50a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f50b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f50c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f50d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f50e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f50f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f510.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f511.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f512.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f513.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f514.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f515.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f516.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f517.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f518.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f519.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f51a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f51b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f51c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f51d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f51e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f51f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f520.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f521.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f522.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f523.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f524.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f525.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f526.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f527.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f528.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f529.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f52a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f52b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f52c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f52d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f52e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f52f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f530.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f531.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f532.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f533.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f534.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f535.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f536.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f537.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f538.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f539.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f53a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f53b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f53c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f53d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f550.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f551.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f552.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f553.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f554.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f555.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f556.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f557.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f558.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f559.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f55a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f55b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f55c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f55d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f55e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f55f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f560.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f561.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f562.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f563.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f564.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f565.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f566.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f567.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f595.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f5fb.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f5fc.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f5fd.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f5fe.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f5ff.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f600.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f601.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f602.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f603.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f604.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f605.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f606.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f607.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f608.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f609.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f60a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f60b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f60c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f60d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f60e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f60f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f610.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f611.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f612.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f613.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f614.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f615.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f616.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f617.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f618.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f619.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f61a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f61b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f61c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f61d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f61e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f61f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f620.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f621.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f622.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f623.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f624.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f625.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f626.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f627.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f628.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f629.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f62a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f62b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f62c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f62d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f62e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f62f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f630.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f631.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f632.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f633.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f634.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f635.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f636.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f637.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f638.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f639.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f63a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f63b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f63c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f63d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f63e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f63f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f640.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f645.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f646.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f647.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f648.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f649.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f64a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f64b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f64c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f64d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f64e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f64f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f680.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f681.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f682.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f683.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f684.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f685.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f686.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f687.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f688.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f689.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f68a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f68b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f68c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f68d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f68e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f68f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f690.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f691.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f692.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f693.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f694.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f695.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f696.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f697.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f698.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f699.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f69a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f69b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f69c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f69d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f69e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f69f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6a0.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6a1.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6a2.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6a3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6a4.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6a5.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6a6.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6a7.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6a8.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6a9.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6aa.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6ab.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6ac.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6ad.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6ae.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6af.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6b0.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6b1.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6b2.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6b3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6b4.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6b5.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6b6.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6b7.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6b8.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6b9.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6ba.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6bb.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6bc.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6bd.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6be.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6bf.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6c0.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6c1.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6c2.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6c3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6c4.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/1f6c5.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/203c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2049.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2122.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2139.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2194.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2195.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2196.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2197.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2198.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2199.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/21a9.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/21aa.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/23-20e3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/231a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/231b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/23e9.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/23ea.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/23eb.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/23ec.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/23f0.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/23f3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/24c2.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/25aa.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/25ab.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/25b6.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/25c0.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/25fb.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/25fc.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/25fd.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/25fe.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2600.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2601.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/260e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2611.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2614.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2615.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/261d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/263a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2648.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2649.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/264a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/264b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/264c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/264d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/264e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/264f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2650.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2651.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2652.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2653.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2660.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2663.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2665.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2666.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2668.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/267b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/267f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2693.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/26a0.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/26a1.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/26aa.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/26ab.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/26bd.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/26be.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/26c4.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/26c5.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/26ce.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/26d4.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/26ea.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/26f2.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/26f3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/26f5.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/26fa.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/26fd.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2702.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2705.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2708.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2709.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/270a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/270b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/270c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/270f.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2712.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2714.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2716.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2728.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2733.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2734.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2744.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2747.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/274c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/274e.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2753.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2754.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2755.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2757.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2764.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2795.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2796.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2797.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/27a1.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/27b0.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/27bf.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2934.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2935.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2b05.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2b06.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2b07.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2b1b.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2b1c.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2b50.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/2b55.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/30-20e3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/3030.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/303d.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/31-20e3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/32-20e3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/3297.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/3299.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/33-20e3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/34-20e3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/35-20e3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/36-20e3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/37-20e3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/38-20e3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/39-20e3.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/LICENSE (100%) rename smileys/{TwitterEmojiSimple => Universe}/LICENSE-GRAPHICS (100%) rename smileys/{TwitterEmojiSimple => Universe}/README.md (100%) rename smileys/{TwitterEmojiSVG => Universe}/a9.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/ae.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/e50a.svg (100%) rename smileys/{TwitterEmojiSVG => Universe}/emoticons.xml (100%) diff --git a/smileys/TwitterEmojiSVG/LICENSE-GRAPHICS b/smileys/ASCII+Universe/LICENSE-GRAPHICS similarity index 100% rename from smileys/TwitterEmojiSVG/LICENSE-GRAPHICS rename to smileys/ASCII+Universe/LICENSE-GRAPHICS diff --git a/smileys/TwitterEmojiSVG/README.md b/smileys/ASCII+Universe/README.md similarity index 100% rename from smileys/TwitterEmojiSVG/README.md rename to smileys/ASCII+Universe/README.md diff --git a/smileys/ASCII+Universe/emoticons.xml b/smileys/ASCII+Universe/emoticons.xml new file mode 100644 index 000000000..488104016 --- /dev/null +++ b/smileys/ASCII+Universe/emoticons.xml @@ -0,0 +1,2529 @@ + + + + + :smile: + + + 😀 + :grinning: + + + 😁 + + + 😂 + :tearsofjoy: + + + 😃 + + + 😄 + :happy: + + + 😅 + + + 😆 + + + 😇 + + + 😈 + + + 😉 + + + 😊 + + + 😋 + + + 😌 + + + 😍 + + + 😎 + :cool: + + + 😏 + + + 😐 + :disappointed: + + + 😑 + + + 😒 + + + 😓 + + + 😔 + + + 😕 + + + 😖 + :oops: + + + 😗 + + + 😘 + + + 😙 + + + 😚 + + + 😛 + + + 😜 + + + 😝 + + + 😞 + :sad: + + + 😟 + + + 😠 + :angry: + + + 😡 + + + 😢 + :cry: + + + 😣 + + + 😤 + + + 😥 + + + 😦 + + + 😧 + + + 😨 + + + 😩 + + + 😪 + + + 😫 + + + 😬 + + + 😭 + + + 😮 + + + 😯 + + + 😰 + + + 😱 + + + 😲 + + + 😳 + + + 😴 + :sleep: + :sleeping: + + + 😵 + + + 😶 + + + 😷 + + + 😸 + + + 😹 + + + 😺 + + + 😻 + + + 😼 + + + 😽 + + + 😾 + + + 😿 + + + 🙀 + + + 🙅 + + + 🙆 + + + 🙇 + + + 🙈 + + + 🙉 + + + 🙊 + :silence: + + + 🙋 + :hi: + + + 🙌 + + + 🙍 + + + 🙎 + + + 🙏 + + + 💩 + + + 🌀 + + + 🌁 + + + 🌂 + + + 🌃 + + + 🌄 + + + 🌅 + + + 🌆 + + + 🌇 + + + 🌈 + + + 🌉 + + + 🌊 + + + 🌋 + + + 🌌 + + + 🌍 + + + 🌎 + + + 🌏 + + + 🌐 + + + 🌑 + + + 🌒 + + + 🌓 + + + 🌔 + + + 🌕 + + + 🌖 + + + 🌗 + + + 🌘 + + + 🌙 + + + 🌚 + + + 🌛 + + + 🌜 + + + 🌝 + + + 🌞 + + + 🌟 + + + 🌠 + + + 🌰 + + + 🌱 + + + 🌲 + + + 🌳 + + + 🌴 + + + 🌵 + + + 🌷 + + + 🌸 + + + 🌹 + + + 🌺 + + + 🌻 + + + 🌼 + + + 🌽 + + + 🌾 + + + 🌿 + + + 🍀 + + + 🍁 + + + 🍂 + + + 🍃 + + + 🍄 + + + 🍅 + + + 🍆 + + + 🍇 + + + 🍈 + + + 🍉 + + + 🍊 + + + 🍋 + + + 🍌 + + + 🍍 + + + 🍎 + + + 🍏 + + + 🍐 + + + 🍑 + + + 🍒 + + + 🍓 + + + 🍔 + + + 🍕 + + + 🍖 + + + 🍗 + + + 🍘 + + + 🍙 + + + 🍚 + + + 🍛 + + + 🍜 + + + 🍝 + + + 🍞 + + + 🍟 + + + 🍠 + + + 🍡 + + + 🍢 + + + 🍣 + + + 🍤 + + + 🍥 + + + 🍦 + + + 🍧 + + + 🍨 + + + 🍩 + + + 🍪 + :cookie: + + + 🍫 + + + 🍬 + + + 🍭 + + + 🍮 + + + 🍯 + + + 🍰 + + + 🍱 + + + 🍲 + + + 🍳 + + + 🍴 + + + 🍵 + + + 🍶 + + + 🍷 + + + 🍸 + + + 🍹 + + + 🍺 + :beer: + + + 🍻 + :beers: + + + 🍼 + + + 🎀 + + + 🎁 + + + 🎂 + + + 🎃 + + + 🎄 + + + 🎅 + + + 🎆 + + + 🎇 + + + 🎈 + + + 🎉 + + + 🎊 + + + 🎋 + + + 🎌 + + + 🎍 + + + 🎎 + + + 🎏 + + + 🎐 + + + 🎑 + + + 🎒 + + + 🎓 + + + 🎠 + + + 🎡 + + + 🎢 + + + 🎣 + + + 🎤 + + + 🎥 + + + 🎦 + + + 🎧 + + + 🎨 + + + 🎩 + + + 🎪 + + + 🎫 + + + 🎬 + + + 🎭 + + + 🎮 + + + 🎯 + + + 🎰 + + + 🎱 + + + 🎲 + + + 🎳 + + + 🎴 + + + 🎵 + + + 🎶 + + + 🎷 + + + 🎸 + + + 🎹 + + + 🎺 + + + 🎻 + + + 🎼 + + + 🎽 + + + 🎾 + + + 🎿 + + + 🏀 + + + 🏁 + + + 🏂 + + + 🏃 + + + 🏄 + + + 🏆 + + + 🏇 + + + 🏈 + + + 🏉 + + + 🏊 + + + 🏠 + + + 🏡 + + + 🏢 + + + 🏣 + + + 🏤 + + + 🏥 + + + 🏦 + + + 🏧 + + + 🏨 + + + 🏩 + + + 🏪 + + + 🏫 + + + 🏬 + + + 🏭 + + + 🏮 + + + 🏯 + + + 🏰 + + + 🐀 + + + 🐁 + + + 🐂 + + + 🐃 + + + 🐄 + + + 🐅 + + + 🐆 + + + 🐇 + + + 🐈 + + + 🐉 + + + 🐊 + + + 🐋 + + + 🐌 + + + 🐍 + + + 🐎 + + + 🐏 + + + 🐐 + + + 🐑 + + + 🐒 + + + 🐓 + + + 🐔 + + + 🐕 + + + 🐖 + + + 🐗 + + + 🐘 + + + 🐙 + + + 🐚 + + + 🐛 + + + 🐜 + + + 🐝 + + + 🐞 + + + 🐟 + + + 🐠 + + + 🐡 + + + 🐢 + + + 🐣 + + + 🐤 + + + 🐥 + + + 🐦 + + + 🐧 + + + 🐨 + + + 🐩 + + + 🐪 + + + 🐫 + + + 🐬 + + + 🐭 + + + 🐮 + + + 🐯 + + + 🐰 + + + 🐱 + + + 🐲 + + + 🐳 + + + 🐴 + + + 🐵 + + + 🐶 + + + 🐷 + + + 🐸 + + + 🐹 + + + 🐺 + + + 🐻 + + + 🐼 + + + 🐽 + + + 🐾 + + + 👀 + + + 👂 + + + 👃 + + + 👄 + + + 👅 + + + 🖕 + :finger: + :fuck: + + + 👆 + + + 👇 + + + 👈 + + + 👉 + + + 👊 + + + 👋 + + + 👌 + + + 👍 + + + 👎 + + + 👏 + + + 👐 + + + 👑 + + + 👒 + + + 👓 + + + 👔 + + + 👕 + + + 👖 + + + 👗 + + + 👘 + + + 👙 + + + 👚 + + + 👛 + + + 👜 + + + 👝 + + + 👞 + + + 👟 + + + 👠 + + + 👡 + + + 👢 + + + 👣 + + + 👤 + + + 👥 + + + 👦 + + + 👧 + + + 👨 + + + 👩 + + + 👪 + + + 👫 + + + 👬 + + + 👭 + + + 👮 + + + 👯 + + + 👰 + + + 👱 + + + 👲 + + + 👳 + + + 👴 + + + 👵 + + + 👶 + + + 👷 + + + 👸 + + + 👹 + + + 👺 + + + 👻 + + + 👼 + :angel: + + + 👽 + + + 👾 + + + 👿 + :devil: + :666: + + + 💀 + :skull: + + + 💁 + + + 💂 + + + 💃 + + + 💄 + + + 💅 + + + 💆 + + + 💇 + + + 💈 + + + 💉 + :syringe: + :injection: + + + 💊 + + + 💋 + + + 💌 + + + 💍 + + + 💎 + + + 💏 + + + 💐 + + + 💑 + + + 💒 + + + 💓 + + + 💔 + + + 💕 + + + 💖 + + + 💗 + + + 💘 + + + 💙 + + + 💚 + + + 💛 + + + 💜 + + + 💝 + + + 💞 + + + 💟 + + + 💠 + + + 💡 + + + 💢 + + + 💣 + :bomb: + + + 💤 + + + 💥 + + + 💦 + + + 💧 + + + 💨 + + + 💪 + + + 💫 + + + 💬 + + + 💭 + + + 💮 + + + 💯 + + + 💰 + + + 💱 + + + 💲 + + + 💳 + + + 💴 + + + 💵 + + + 💶 + + + 💷 + + + 💸 + + + 💹 + + + 💺 + + + 💻 + + + 💼 + + + 💽 + + + 💾 + + + 💿 + + + 📀 + + + 📁 + + + 📂 + + + 📃 + + + 📄 + + + 📅 + + + 📆 + + + 📇 + + + 📈 + + + 📉 + + + 📊 + + + 📋 + + + 📌 + + + 📍 + + + 📎 + + + 📏 + + + 📐 + + + 📑 + + + 📒 + + + 📓 + + + 📔 + + + 📕 + + + 📖 + + + 📗 + + + 📘 + + + 📙 + + + 📚 + + + 📛 + + + 📜 + + + 📝 + + + 📞 + + + 📟 + + + 📠 + + + 📡 + + + 📢 + + + 📣 + + + 📤 + + + 📥 + + + 📦 + + + 📧 + + + 📨 + + + 📩 + + + 📪 + + + 📫 + + + 📬 + + + 📭 + + + 📮 + + + 📯 + + + 📰 + + + 📱 + + + 📲 + + + 📳 + + + 📴 + + + 📵 + + + 📶 + + + 📷 + + + 📹 + + + 📺 + + + 📻 + + + 📼 + + + 🔀 + + + 🔁 + + + 🔂 + + + 🔃 + + + 🔄 + + + 🔅 + + + 🔆 + + + 🔇 + + + 🔈 + + + 🔉 + + + 🔊 + + + 🔋 + + + 🔌 + + + 🔍 + + + 🔎 + + + 🔏 + + + 🔐 + + + 🔑 + + + 🔒 + + + 🔓 + + + 🔔 + + + 🔕 + + + 🔖 + + + 🔗 + + + 🔘 + + + 🔙 + + + 🔚 + + + 🔛 + + + 🔜 + + + 🔝 + + + 🔞 + + + 🔟 + + + 🔠 + + + 🔡 + + + 🔢 + + + 🔣 + + + 🔤 + + + 🔥 + + + 🔦 + + + 🔧 + + + 🔨 + + + 🔩 + + + 🔪 + + + 🔫 + + + 🔬 + + + 🔭 + + + 🔮 + + + 🔯 + + + 🔰 + + + 🔱 + + + 🔲 + + + 🔳 + + + 🔴 + + + 🔵 + + + 🔶 + + + 🔷 + + + 🔸 + + + 🔹 + + + 🔺 + + + 🔻 + + + 🔼 + + + 🔽 + + + 🕐 + + + 🕑 + + + 🕒 + + + 🕓 + + + 🕔 + + + 🕕 + + + 🕖 + + + 🕗 + + + 🕘 + + + 🕙 + + + 🕚 + + + 🕛 + + + 🕜 + + + 🕝 + + + 🕞 + + + 🕟 + + + 🕠 + + + 🕡 + + + 🕢 + + + 🕣 + + + 🕤 + + + 🕥 + + + 🕦 + + + 🕧 + + + 🗻 + + + 🗼 + + + 🗽 + + + 🗾 + + + 🗿 + + + 🀄 + + + 🃏 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 🚀 + + + 🚁 + + + 🚂 + + + 🚃 + + + 🚄 + + + 🚅 + + + 🚆 + + + 🚇 + + + 🚈 + + + 🚉 + + + 🚊 + + + 🚋 + + + 🚌 + + + 🚍 + + + 🚎 + + + 🚏 + + + 🚐 + + + 🚑 + + + 🚒 + + + 🚓 + + + 🚔 + + + 🚕 + + + 🚖 + + + 🚗 + + + 🚘 + + + 🚙 + + + 🚚 + + + 🚛 + + + 🚜 + + + 🚝 + + + 🚞 + + + 🚟 + + + 🚠 + + + 🚡 + + + 🚢 + + + 🚣 + + + 🚤 + + + 🚥 + + + 🚦 + + + 🚧 + + + 🚨 + + + 🚩 + + + 🚪 + + + 🚫 + + + 🚬 + + + 🚭 + + + 🚮 + + + 🚯 + + + 🚰 + + + 🚱 + + + 🚲 + + + 🚳 + + + 🚴 + + + 🚵 + + + 🚶 + + + 🚷 + + + 🚸 + + + 🚹 + + + 🚺 + + + 🚻 + + + 🚼 + + + 🚽 + + + 🚾 + + + 🚿 + + + 🛀 + + + 🛁 + + + 🛂 + + + 🛃 + + + 🛄 + + + 🛅 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <3 + :heart: + :love: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + © + + + ® + + + 🈚 + + + 🈯 + + + 🈺 + + + 🈁 + + + 🈂 + + + 🈲 + + + 🈳 + + + 🈴 + + + 🈵 + + + 🈶 + + + 🈷 + + + 🈸 + + + 🈹 + + + 🉐 + + + 🉑 + + + 🅰 + + + 🅱 + + + 🅾 + + + 🅿 + + + 🆎 + + + 🆑 + + + 🆒 + + + 🆓 + + + 🆔 + + + 🆕 + + + 🆖 + + + 🆗 + + + 🆘 + + + 🆙 + + + 🆚 + + + 🇦 + + + 🇧 + + + 🇨 + + + 🇩 + + + 🇪 + + + 🇫 + + + 🇬 + + + 🇭 + + + 🇮 + + + 🇯 + + + 🇰 + + + 🇱 + + + 🇲 + + + 🇳 + + + 🇴 + + + 🇵 + + + 🇶 + + + 🇷 + + + 🇸 + + + 🇹 + + + 🇺 + + + 🇻 + + + 🇼 + + + 🇽 + + + 🇾 + + + 🇿 + + + 🇨🇳 + + + 🇩🇪 + + + 🇪🇸 + + + 🇫🇷 + + + 🇬🇧 + + + 🇮🇹 + + + 🇯🇵 + + + 🇰🇷 + + + 🇷🇺 + + + 🇺🇸 + + + \ No newline at end of file diff --git a/smileys/cylgom/MrSmith.png b/smileys/Basic/MrSmith.png similarity index 100% rename from smileys/cylgom/MrSmith.png rename to smileys/Basic/MrSmith.png diff --git a/smileys/cylgom/X(.png b/smileys/Basic/X(.png similarity index 100% rename from smileys/cylgom/X(.png rename to smileys/Basic/X(.png diff --git a/smileys/cylgom/XD.png b/smileys/Basic/XD.png similarity index 100% rename from smileys/cylgom/XD.png rename to smileys/Basic/XD.png diff --git a/smileys/cylgom/XP.png b/smileys/Basic/XP.png similarity index 100% rename from smileys/cylgom/XP.png rename to smileys/Basic/XP.png diff --git a/smileys/cylgom/angel.png b/smileys/Basic/angel.png similarity index 100% rename from smileys/cylgom/angel.png rename to smileys/Basic/angel.png diff --git a/smileys/cylgom/angry.png b/smileys/Basic/angry.png similarity index 100% rename from smileys/cylgom/angry.png rename to smileys/Basic/angry.png diff --git a/smileys/cylgom/beer.png b/smileys/Basic/beer.png similarity index 100% rename from smileys/cylgom/beer.png rename to smileys/Basic/beer.png diff --git a/smileys/cylgom/bomb.png b/smileys/Basic/bomb.png similarity index 100% rename from smileys/cylgom/bomb.png rename to smileys/Basic/bomb.png diff --git a/smileys/cylgom/bored.png b/smileys/Basic/bored.png similarity index 100% rename from smileys/cylgom/bored.png rename to smileys/Basic/bored.png diff --git a/smileys/cylgom/cookie.png b/smileys/Basic/cookie.png similarity index 100% rename from smileys/cylgom/cookie.png rename to smileys/Basic/cookie.png diff --git a/smileys/cylgom/cool.png b/smileys/Basic/cool.png similarity index 100% rename from smileys/cylgom/cool.png rename to smileys/Basic/cool.png diff --git a/smileys/cylgom/crossing.png b/smileys/Basic/crossing.png similarity index 100% rename from smileys/cylgom/crossing.png rename to smileys/Basic/crossing.png diff --git a/smileys/cylgom/crying.png b/smileys/Basic/crying.png similarity index 100% rename from smileys/cylgom/crying.png rename to smileys/Basic/crying.png diff --git a/smileys/cylgom/devil.png b/smileys/Basic/devil.png similarity index 100% rename from smileys/cylgom/devil.png rename to smileys/Basic/devil.png diff --git a/smileys/cylgom/diamond.png b/smileys/Basic/diamond.png similarity index 100% rename from smileys/cylgom/diamond.png rename to smileys/Basic/diamond.png diff --git a/smileys/cylgom/doh.png b/smileys/Basic/doh.png similarity index 100% rename from smileys/cylgom/doh.png rename to smileys/Basic/doh.png diff --git a/smileys/cylgom/emoticons.xml b/smileys/Basic/emoticons.xml similarity index 100% rename from smileys/cylgom/emoticons.xml rename to smileys/Basic/emoticons.xml diff --git a/smileys/cylgom/evil.png b/smileys/Basic/evil.png similarity index 100% rename from smileys/cylgom/evil.png rename to smileys/Basic/evil.png diff --git a/smileys/cylgom/eye.png b/smileys/Basic/eye.png similarity index 100% rename from smileys/cylgom/eye.png rename to smileys/Basic/eye.png diff --git a/smileys/cylgom/facepalm.png b/smileys/Basic/facepalm.png similarity index 100% rename from smileys/cylgom/facepalm.png rename to smileys/Basic/facepalm.png diff --git a/smileys/cylgom/finger.png b/smileys/Basic/finger.png similarity index 100% rename from smileys/cylgom/finger.png rename to smileys/Basic/finger.png diff --git a/smileys/cylgom/hacker_terminal.png b/smileys/Basic/hacker_terminal.png similarity index 100% rename from smileys/cylgom/hacker_terminal.png rename to smileys/Basic/hacker_terminal.png diff --git a/smileys/cylgom/happysmile.png b/smileys/Basic/happysmile.png similarity index 100% rename from smileys/cylgom/happysmile.png rename to smileys/Basic/happysmile.png diff --git a/smileys/cylgom/heart.png b/smileys/Basic/heart.png similarity index 100% rename from smileys/cylgom/heart.png rename to smileys/Basic/heart.png diff --git a/smileys/cylgom/hi.png b/smileys/Basic/hi.png similarity index 100% rename from smileys/cylgom/hi.png rename to smileys/Basic/hi.png diff --git a/smileys/cylgom/highfive.png b/smileys/Basic/highfive.png similarity index 100% rename from smileys/cylgom/highfive.png rename to smileys/Basic/highfive.png diff --git a/smileys/cylgom/hot.png b/smileys/Basic/hot.png similarity index 100% rename from smileys/cylgom/hot.png rename to smileys/Basic/hot.png diff --git a/smileys/cylgom/impressed.png b/smileys/Basic/impressed.png similarity index 100% rename from smileys/cylgom/impressed.png rename to smileys/Basic/impressed.png diff --git a/smileys/cylgom/inlove.png b/smileys/Basic/inlove.png similarity index 100% rename from smileys/cylgom/inlove.png rename to smileys/Basic/inlove.png diff --git a/smileys/cylgom/jealous.png b/smileys/Basic/jealous.png similarity index 100% rename from smileys/cylgom/jealous.png rename to smileys/Basic/jealous.png diff --git a/smileys/cylgom/kiss.png b/smileys/Basic/kiss.png similarity index 100% rename from smileys/cylgom/kiss.png rename to smileys/Basic/kiss.png diff --git a/smileys/cylgom/lol.png b/smileys/Basic/lol.png similarity index 100% rename from smileys/cylgom/lol.png rename to smileys/Basic/lol.png diff --git a/smileys/cylgom/moustache.png b/smileys/Basic/moustache.png similarity index 100% rename from smileys/cylgom/moustache.png rename to smileys/Basic/moustache.png diff --git a/smileys/cylgom/nerd.png b/smileys/Basic/nerd.png similarity index 100% rename from smileys/cylgom/nerd.png rename to smileys/Basic/nerd.png diff --git a/smileys/cylgom/nospeak.png b/smileys/Basic/nospeak.png similarity index 100% rename from smileys/cylgom/nospeak.png rename to smileys/Basic/nospeak.png diff --git a/smileys/cylgom/oops.png b/smileys/Basic/oops.png similarity index 100% rename from smileys/cylgom/oops.png rename to smileys/Basic/oops.png diff --git a/smileys/cylgom/party.png b/smileys/Basic/party.png similarity index 100% rename from smileys/cylgom/party.png rename to smileys/Basic/party.png diff --git a/smileys/cylgom/pressed.png b/smileys/Basic/pressed.png similarity index 100% rename from smileys/cylgom/pressed.png rename to smileys/Basic/pressed.png diff --git a/smileys/cylgom/rain.png b/smileys/Basic/rain.png similarity index 100% rename from smileys/cylgom/rain.png rename to smileys/Basic/rain.png diff --git a/smileys/cylgom/rocknroll.png b/smileys/Basic/rocknroll.png similarity index 100% rename from smileys/cylgom/rocknroll.png rename to smileys/Basic/rocknroll.png diff --git a/smileys/cylgom/sad.png b/smileys/Basic/sad.png similarity index 100% rename from smileys/cylgom/sad.png rename to smileys/Basic/sad.png diff --git a/smileys/cylgom/shy.png b/smileys/Basic/shy.png similarity index 100% rename from smileys/cylgom/shy.png rename to smileys/Basic/shy.png diff --git a/smileys/cylgom/sleeping.png b/smileys/Basic/sleeping.png similarity index 100% rename from smileys/cylgom/sleeping.png rename to smileys/Basic/sleeping.png diff --git a/smileys/cylgom/smile.png b/smileys/Basic/smile.png similarity index 100% rename from smileys/cylgom/smile.png rename to smileys/Basic/smile.png diff --git a/smileys/cylgom/sniggering.png b/smileys/Basic/sniggering.png similarity index 100% rename from smileys/cylgom/sniggering.png rename to smileys/Basic/sniggering.png diff --git a/smileys/cylgom/suspicious.png b/smileys/Basic/suspicious.png similarity index 100% rename from smileys/cylgom/suspicious.png rename to smileys/Basic/suspicious.png diff --git a/smileys/cylgom/syringe.png b/smileys/Basic/syringe.png similarity index 100% rename from smileys/cylgom/syringe.png rename to smileys/Basic/syringe.png diff --git a/smileys/cylgom/tongue.png b/smileys/Basic/tongue.png similarity index 100% rename from smileys/cylgom/tongue.png rename to smileys/Basic/tongue.png diff --git a/smileys/cylgom/toxlocker.png b/smileys/Basic/toxlocker.png similarity index 100% rename from smileys/cylgom/toxlocker.png rename to smileys/Basic/toxlocker.png diff --git a/smileys/cylgom/vomit.png b/smileys/Basic/vomit.png similarity index 100% rename from smileys/cylgom/vomit.png rename to smileys/Basic/vomit.png diff --git a/smileys/cylgom/wasntme.png b/smileys/Basic/wasntme.png similarity index 100% rename from smileys/cylgom/wasntme.png rename to smileys/Basic/wasntme.png diff --git a/smileys/cylgom/whew.png b/smileys/Basic/whew.png similarity index 100% rename from smileys/cylgom/whew.png rename to smileys/Basic/whew.png diff --git a/smileys/cylgom/wink.png b/smileys/Basic/wink.png similarity index 100% rename from smileys/cylgom/wink.png rename to smileys/Basic/wink.png diff --git a/smileys/cylgom/wondering.png b/smileys/Basic/wondering.png similarity index 100% rename from smileys/cylgom/wondering.png rename to smileys/Basic/wondering.png diff --git a/smileys/cylgom/yawn.png b/smileys/Basic/yawn.png similarity index 100% rename from smileys/cylgom/yawn.png rename to smileys/Basic/yawn.png diff --git a/smileys/krepa098/Kappa.png b/smileys/Classic/Kappa.png similarity index 100% rename from smileys/krepa098/Kappa.png rename to smileys/Classic/Kappa.png diff --git a/smileys/krepa098/angry.png b/smileys/Classic/angry.png similarity index 100% rename from smileys/krepa098/angry.png rename to smileys/Classic/angry.png diff --git a/smileys/krepa098/cool.png b/smileys/Classic/cool.png similarity index 100% rename from smileys/krepa098/cool.png rename to smileys/Classic/cool.png diff --git a/smileys/krepa098/crying.png b/smileys/Classic/crying.png similarity index 100% rename from smileys/krepa098/crying.png rename to smileys/Classic/crying.png diff --git a/smileys/krepa098/emoticons.xml b/smileys/Classic/emoticons.xml similarity index 100% rename from smileys/krepa098/emoticons.xml rename to smileys/Classic/emoticons.xml diff --git a/smileys/krepa098/happy.png b/smileys/Classic/happy.png similarity index 100% rename from smileys/krepa098/happy.png rename to smileys/Classic/happy.png diff --git a/smileys/krepa098/laugh.png b/smileys/Classic/laugh.png similarity index 100% rename from smileys/krepa098/laugh.png rename to smileys/Classic/laugh.png diff --git a/smileys/krepa098/laugh_closed_eyes.png b/smileys/Classic/laugh_closed_eyes.png similarity index 100% rename from smileys/krepa098/laugh_closed_eyes.png rename to smileys/Classic/laugh_closed_eyes.png diff --git a/smileys/krepa098/plain.png b/smileys/Classic/plain.png similarity index 100% rename from smileys/krepa098/plain.png rename to smileys/Classic/plain.png diff --git a/smileys/krepa098/raw.svg b/smileys/Classic/raw.svg similarity index 100% rename from smileys/krepa098/raw.svg rename to smileys/Classic/raw.svg diff --git a/smileys/krepa098/sad.png b/smileys/Classic/sad.png similarity index 100% rename from smileys/krepa098/sad.png rename to smileys/Classic/sad.png diff --git a/smileys/krepa098/scared.png b/smileys/Classic/scared.png similarity index 100% rename from smileys/krepa098/scared.png rename to smileys/Classic/scared.png diff --git a/smileys/krepa098/smile.png b/smileys/Classic/smile.png similarity index 100% rename from smileys/krepa098/smile.png rename to smileys/Classic/smile.png diff --git a/smileys/krepa098/stunned.png b/smileys/Classic/stunned.png similarity index 100% rename from smileys/krepa098/stunned.png rename to smileys/Classic/stunned.png diff --git a/smileys/krepa098/tongue.png b/smileys/Classic/tongue.png similarity index 100% rename from smileys/krepa098/tongue.png rename to smileys/Classic/tongue.png diff --git a/smileys/krepa098/uncertain.png b/smileys/Classic/uncertain.png similarity index 100% rename from smileys/krepa098/uncertain.png rename to smileys/Classic/uncertain.png diff --git a/smileys/krepa098/wink.png b/smileys/Classic/wink.png similarity index 100% rename from smileys/krepa098/wink.png rename to smileys/Classic/wink.png diff --git a/smileys/TwitterEmojiSimple/emoticons.xml b/smileys/TwitterEmojiSimple/emoticons.xml deleted file mode 100644 index 7e2d59846..000000000 --- a/smileys/TwitterEmojiSimple/emoticons.xml +++ /dev/null @@ -1,2529 +0,0 @@ - - - - - :smile: - - - 😀 - :grinning: - - - 😁 - - - 😂 - :tearsofjoy: - - - 😃 - - - 😄 - :happy: - - - 😅 - - - 😆 - - - 😇 - - - 😈 - - - 😉 - - - 😊 - - - 😋 - - - 😌 - - - 😍 - - - 😎 - :cool: - - - 😏 - - - 😐 - :disappointed: - - - 😑 - - - 😒 - - - 😓 - - - 😔 - - - 😕 - - - 😖 - :oops: - - - 😗 - - - 😘 - - - 😙 - - - 😚 - - - 😛 - - - 😜 - - - 😝 - - - 😞 - :sad: - - - 😟 - - - 😠 - :angry: - - - 😡 - - - 😢 - :cry: - - - 😣 - - - 😤 - - - 😥 - - - 😦 - - - 😧 - - - 😨 - - - 😩 - - - 😪 - - - 😫 - - - 😬 - - - 😭 - - - 😮 - - - 😯 - - - 😰 - - - 😱 - - - 😲 - - - 😳 - - - 😴 - :sleep: - :sleeping: - - - 😵 - - - 😶 - - - 😷 - - - 😸 - - - 😹 - - - 😺 - - - 😻 - - - 😼 - - - 😽 - - - 😾 - - - 😿 - - - 🙀 - - - 🙅 - - - 🙆 - - - 🙇 - - - 🙈 - - - 🙉 - - - 🙊 - :silence: - - - 🙋 - :hi: - - - 🙌 - - - 🙍 - - - 🙎 - - - 🙏 - - - 💩 - - - 🌀 - - - 🌁 - - - 🌂 - - - 🌃 - - - 🌄 - - - 🌅 - - - 🌆 - - - 🌇 - - - 🌈 - - - 🌉 - - - 🌊 - - - 🌋 - - - 🌌 - - - 🌍 - - - 🌎 - - - 🌏 - - - 🌐 - - - 🌑 - - - 🌒 - - - 🌓 - - - 🌔 - - - 🌕 - - - 🌖 - - - 🌗 - - - 🌘 - - - 🌙 - - - 🌚 - - - 🌛 - - - 🌜 - - - 🌝 - - - 🌞 - - - 🌟 - - - 🌠 - - - 🌰 - - - 🌱 - - - 🌲 - - - 🌳 - - - 🌴 - - - 🌵 - - - 🌷 - - - 🌸 - - - 🌹 - - - 🌺 - - - 🌻 - - - 🌼 - - - 🌽 - - - 🌾 - - - 🌿 - - - 🍀 - - - 🍁 - - - 🍂 - - - 🍃 - - - 🍄 - - - 🍅 - - - 🍆 - - - 🍇 - - - 🍈 - - - 🍉 - - - 🍊 - - - 🍋 - - - 🍌 - - - 🍍 - - - 🍎 - - - 🍏 - - - 🍐 - - - 🍑 - - - 🍒 - - - 🍓 - - - 🍔 - - - 🍕 - - - 🍖 - - - 🍗 - - - 🍘 - - - 🍙 - - - 🍚 - - - 🍛 - - - 🍜 - - - 🍝 - - - 🍞 - - - 🍟 - - - 🍠 - - - 🍡 - - - 🍢 - - - 🍣 - - - 🍤 - - - 🍥 - - - 🍦 - - - 🍧 - - - 🍨 - - - 🍩 - - - 🍪 - :cookie: - - - 🍫 - - - 🍬 - - - 🍭 - - - 🍮 - - - 🍯 - - - 🍰 - - - 🍱 - - - 🍲 - - - 🍳 - - - 🍴 - - - 🍵 - - - 🍶 - - - 🍷 - - - 🍸 - - - 🍹 - - - 🍺 - :beer: - - - 🍻 - :beers: - - - 🍼 - - - 🎀 - - - 🎁 - - - 🎂 - - - 🎃 - - - 🎄 - - - 🎅 - - - 🎆 - - - 🎇 - - - 🎈 - - - 🎉 - - - 🎊 - - - 🎋 - - - 🎌 - - - 🎍 - - - 🎎 - - - 🎏 - - - 🎐 - - - 🎑 - - - 🎒 - - - 🎓 - - - 🎠 - - - 🎡 - - - 🎢 - - - 🎣 - - - 🎤 - - - 🎥 - - - 🎦 - - - 🎧 - - - 🎨 - - - 🎩 - - - 🎪 - - - 🎫 - - - 🎬 - - - 🎭 - - - 🎮 - - - 🎯 - - - 🎰 - - - 🎱 - - - 🎲 - - - 🎳 - - - 🎴 - - - 🎵 - - - 🎶 - - - 🎷 - - - 🎸 - - - 🎹 - - - 🎺 - - - 🎻 - - - 🎼 - - - 🎽 - - - 🎾 - - - 🎿 - - - 🏀 - - - 🏁 - - - 🏂 - - - 🏃 - - - 🏄 - - - 🏆 - - - 🏇 - - - 🏈 - - - 🏉 - - - 🏊 - - - 🏠 - - - 🏡 - - - 🏢 - - - 🏣 - - - 🏤 - - - 🏥 - - - 🏦 - - - 🏧 - - - 🏨 - - - 🏩 - - - 🏪 - - - 🏫 - - - 🏬 - - - 🏭 - - - 🏮 - - - 🏯 - - - 🏰 - - - 🐀 - - - 🐁 - - - 🐂 - - - 🐃 - - - 🐄 - - - 🐅 - - - 🐆 - - - 🐇 - - - 🐈 - - - 🐉 - - - 🐊 - - - 🐋 - - - 🐌 - - - 🐍 - - - 🐎 - - - 🐏 - - - 🐐 - - - 🐑 - - - 🐒 - - - 🐓 - - - 🐔 - - - 🐕 - - - 🐖 - - - 🐗 - - - 🐘 - - - 🐙 - - - 🐚 - - - 🐛 - - - 🐜 - - - 🐝 - - - 🐞 - - - 🐟 - - - 🐠 - - - 🐡 - - - 🐢 - - - 🐣 - - - 🐤 - - - 🐥 - - - 🐦 - - - 🐧 - - - 🐨 - - - 🐩 - - - 🐪 - - - 🐫 - - - 🐬 - - - 🐭 - - - 🐮 - - - 🐯 - - - 🐰 - - - 🐱 - - - 🐲 - - - 🐳 - - - 🐴 - - - 🐵 - - - 🐶 - - - 🐷 - - - 🐸 - - - 🐹 - - - 🐺 - - - 🐻 - - - 🐼 - - - 🐽 - - - 🐾 - - - 👀 - - - 👂 - - - 👃 - - - 👄 - - - 👅 - - - 🖕 - :finger: - :fuck: - - - 👆 - - - 👇 - - - 👈 - - - 👉 - - - 👊 - - - 👋 - - - 👌 - - - 👍 - - - 👎 - - - 👏 - - - 👐 - - - 👑 - - - 👒 - - - 👓 - - - 👔 - - - 👕 - - - 👖 - - - 👗 - - - 👘 - - - 👙 - - - 👚 - - - 👛 - - - 👜 - - - 👝 - - - 👞 - - - 👟 - - - 👠 - - - 👡 - - - 👢 - - - 👣 - - - 👤 - - - 👥 - - - 👦 - - - 👧 - - - 👨 - - - 👩 - - - 👪 - - - 👫 - - - 👬 - - - 👭 - - - 👮 - - - 👯 - - - 👰 - - - 👱 - - - 👲 - - - 👳 - - - 👴 - - - 👵 - - - 👶 - - - 👷 - - - 👸 - - - 👹 - - - 👺 - - - 👻 - - - 👼 - :angel: - - - 👽 - - - 👾 - - - 👿 - :devil: - :666: - - - 💀 - :skull: - - - 💁 - - - 💂 - - - 💃 - - - 💄 - - - 💅 - - - 💆 - - - 💇 - - - 💈 - - - 💉 - :syringe: - :injection: - - - 💊 - - - 💋 - - - 💌 - - - 💍 - - - 💎 - - - 💏 - - - 💐 - - - 💑 - - - 💒 - - - 💓 - - - 💔 - - - 💕 - - - 💖 - - - 💗 - - - 💘 - - - 💙 - - - 💚 - - - 💛 - - - 💜 - - - 💝 - - - 💞 - - - 💟 - - - 💠 - - - 💡 - - - 💢 - - - 💣 - :bomb: - - - 💤 - - - 💥 - - - 💦 - - - 💧 - - - 💨 - - - 💪 - - - 💫 - - - 💬 - - - 💭 - - - 💮 - - - 💯 - - - 💰 - - - 💱 - - - 💲 - - - 💳 - - - 💴 - - - 💵 - - - 💶 - - - 💷 - - - 💸 - - - 💹 - - - 💺 - - - 💻 - - - 💼 - - - 💽 - - - 💾 - - - 💿 - - - 📀 - - - 📁 - - - 📂 - - - 📃 - - - 📄 - - - 📅 - - - 📆 - - - 📇 - - - 📈 - - - 📉 - - - 📊 - - - 📋 - - - 📌 - - - 📍 - - - 📎 - - - 📏 - - - 📐 - - - 📑 - - - 📒 - - - 📓 - - - 📔 - - - 📕 - - - 📖 - - - 📗 - - - 📘 - - - 📙 - - - 📚 - - - 📛 - - - 📜 - - - 📝 - - - 📞 - - - 📟 - - - 📠 - - - 📡 - - - 📢 - - - 📣 - - - 📤 - - - 📥 - - - 📦 - - - 📧 - - - 📨 - - - 📩 - - - 📪 - - - 📫 - - - 📬 - - - 📭 - - - 📮 - - - 📯 - - - 📰 - - - 📱 - - - 📲 - - - 📳 - - - 📴 - - - 📵 - - - 📶 - - - 📷 - - - 📹 - - - 📺 - - - 📻 - - - 📼 - - - 🔀 - - - 🔁 - - - 🔂 - - - 🔃 - - - 🔄 - - - 🔅 - - - 🔆 - - - 🔇 - - - 🔈 - - - 🔉 - - - 🔊 - - - 🔋 - - - 🔌 - - - 🔍 - - - 🔎 - - - 🔏 - - - 🔐 - - - 🔑 - - - 🔒 - - - 🔓 - - - 🔔 - - - 🔕 - - - 🔖 - - - 🔗 - - - 🔘 - - - 🔙 - - - 🔚 - - - 🔛 - - - 🔜 - - - 🔝 - - - 🔞 - - - 🔟 - - - 🔠 - - - 🔡 - - - 🔢 - - - 🔣 - - - 🔤 - - - 🔥 - - - 🔦 - - - 🔧 - - - 🔨 - - - 🔩 - - - 🔪 - - - 🔫 - - - 🔬 - - - 🔭 - - - 🔮 - - - 🔯 - - - 🔰 - - - 🔱 - - - 🔲 - - - 🔳 - - - 🔴 - - - 🔵 - - - 🔶 - - - 🔷 - - - 🔸 - - - 🔹 - - - 🔺 - - - 🔻 - - - 🔼 - - - 🔽 - - - 🕐 - - - 🕑 - - - 🕒 - - - 🕓 - - - 🕔 - - - 🕕 - - - 🕖 - - - 🕗 - - - 🕘 - - - 🕙 - - - 🕚 - - - 🕛 - - - 🕜 - - - 🕝 - - - 🕞 - - - 🕟 - - - 🕠 - - - 🕡 - - - 🕢 - - - 🕣 - - - 🕤 - - - 🕥 - - - 🕦 - - - 🕧 - - - 🗻 - - - 🗼 - - - 🗽 - - - 🗾 - - - 🗿 - - - 🀄 - - - 🃏 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 🚀 - - - 🚁 - - - 🚂 - - - 🚃 - - - 🚄 - - - 🚅 - - - 🚆 - - - 🚇 - - - 🚈 - - - 🚉 - - - 🚊 - - - 🚋 - - - 🚌 - - - 🚍 - - - 🚎 - - - 🚏 - - - 🚐 - - - 🚑 - - - 🚒 - - - 🚓 - - - 🚔 - - - 🚕 - - - 🚖 - - - 🚗 - - - 🚘 - - - 🚙 - - - 🚚 - - - 🚛 - - - 🚜 - - - 🚝 - - - 🚞 - - - 🚟 - - - 🚠 - - - 🚡 - - - 🚢 - - - 🚣 - - - 🚤 - - - 🚥 - - - 🚦 - - - 🚧 - - - 🚨 - - - 🚩 - - - 🚪 - - - 🚫 - - - 🚬 - - - 🚭 - - - 🚮 - - - 🚯 - - - 🚰 - - - 🚱 - - - 🚲 - - - 🚳 - - - 🚴 - - - 🚵 - - - 🚶 - - - 🚷 - - - 🚸 - - - 🚹 - - - 🚺 - - - 🚻 - - - 🚼 - - - 🚽 - - - 🚾 - - - 🚿 - - - 🛀 - - - 🛁 - - - 🛂 - - - 🛃 - - - 🛄 - - - 🛅 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <3 - :heart: - :love: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - © - - - ® - - - 🈚 - - - 🈯 - - - 🈺 - - - 🈁 - - - 🈂 - - - 🈲 - - - 🈳 - - - 🈴 - - - 🈵 - - - 🈶 - - - 🈷 - - - 🈸 - - - 🈹 - - - 🉐 - - - 🉑 - - - 🅰 - - - 🅱 - - - 🅾 - - - 🅿 - - - 🆎 - - - 🆑 - - - 🆒 - - - 🆓 - - - 🆔 - - - 🆕 - - - 🆖 - - - 🆗 - - - 🆘 - - - 🆙 - - - 🆚 - - - 🇦 - - - 🇧 - - - 🇨 - - - 🇩 - - - 🇪 - - - 🇫 - - - 🇬 - - - 🇭 - - - 🇮 - - - 🇯 - - - 🇰 - - - 🇱 - - - 🇲 - - - 🇳 - - - 🇴 - - - 🇵 - - - 🇶 - - - 🇷 - - - 🇸 - - - 🇹 - - - 🇺 - - - 🇻 - - - 🇼 - - - 🇽 - - - 🇾 - - - 🇿 - - - 🇨🇳 - - - 🇩🇪 - - - 🇪🇸 - - - 🇫🇷 - - - 🇬🇧 - - - 🇮🇹 - - - 🇯🇵 - - - 🇰🇷 - - - 🇷🇺 - - - 🇺🇸 - - - \ No newline at end of file diff --git a/smileys/TwitterEmojiSVG/1f004.svg b/smileys/Universe/1f004.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f004.svg rename to smileys/Universe/1f004.svg diff --git a/smileys/TwitterEmojiSVG/1f0cf.svg b/smileys/Universe/1f0cf.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f0cf.svg rename to smileys/Universe/1f0cf.svg diff --git a/smileys/TwitterEmojiSVG/1f170.svg b/smileys/Universe/1f170.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f170.svg rename to smileys/Universe/1f170.svg diff --git a/smileys/TwitterEmojiSVG/1f171.svg b/smileys/Universe/1f171.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f171.svg rename to smileys/Universe/1f171.svg diff --git a/smileys/TwitterEmojiSVG/1f17e.svg b/smileys/Universe/1f17e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f17e.svg rename to smileys/Universe/1f17e.svg diff --git a/smileys/TwitterEmojiSVG/1f17f.svg b/smileys/Universe/1f17f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f17f.svg rename to smileys/Universe/1f17f.svg diff --git a/smileys/TwitterEmojiSVG/1f18e.svg b/smileys/Universe/1f18e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f18e.svg rename to smileys/Universe/1f18e.svg diff --git a/smileys/TwitterEmojiSVG/1f191.svg b/smileys/Universe/1f191.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f191.svg rename to smileys/Universe/1f191.svg diff --git a/smileys/TwitterEmojiSVG/1f192.svg b/smileys/Universe/1f192.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f192.svg rename to smileys/Universe/1f192.svg diff --git a/smileys/TwitterEmojiSVG/1f193.svg b/smileys/Universe/1f193.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f193.svg rename to smileys/Universe/1f193.svg diff --git a/smileys/TwitterEmojiSVG/1f194.svg b/smileys/Universe/1f194.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f194.svg rename to smileys/Universe/1f194.svg diff --git a/smileys/TwitterEmojiSVG/1f195.svg b/smileys/Universe/1f195.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f195.svg rename to smileys/Universe/1f195.svg diff --git a/smileys/TwitterEmojiSVG/1f196.svg b/smileys/Universe/1f196.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f196.svg rename to smileys/Universe/1f196.svg diff --git a/smileys/TwitterEmojiSVG/1f197.svg b/smileys/Universe/1f197.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f197.svg rename to smileys/Universe/1f197.svg diff --git a/smileys/TwitterEmojiSVG/1f198.svg b/smileys/Universe/1f198.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f198.svg rename to smileys/Universe/1f198.svg diff --git a/smileys/TwitterEmojiSVG/1f199.svg b/smileys/Universe/1f199.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f199.svg rename to smileys/Universe/1f199.svg diff --git a/smileys/TwitterEmojiSVG/1f19a.svg b/smileys/Universe/1f19a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f19a.svg rename to smileys/Universe/1f19a.svg diff --git a/smileys/TwitterEmojiSVG/1f1e6.svg b/smileys/Universe/1f1e6.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1e6.svg rename to smileys/Universe/1f1e6.svg diff --git a/smileys/TwitterEmojiSVG/1f1e7.svg b/smileys/Universe/1f1e7.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1e7.svg rename to smileys/Universe/1f1e7.svg diff --git a/smileys/TwitterEmojiSVG/1f1e8-1f1f3.svg b/smileys/Universe/1f1e8-1f1f3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1e8-1f1f3.svg rename to smileys/Universe/1f1e8-1f1f3.svg diff --git a/smileys/TwitterEmojiSVG/1f1e8.svg b/smileys/Universe/1f1e8.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1e8.svg rename to smileys/Universe/1f1e8.svg diff --git a/smileys/TwitterEmojiSVG/1f1e9-1f1ea.svg b/smileys/Universe/1f1e9-1f1ea.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1e9-1f1ea.svg rename to smileys/Universe/1f1e9-1f1ea.svg diff --git a/smileys/TwitterEmojiSVG/1f1e9.svg b/smileys/Universe/1f1e9.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1e9.svg rename to smileys/Universe/1f1e9.svg diff --git a/smileys/TwitterEmojiSVG/1f1ea-1f1f8.svg b/smileys/Universe/1f1ea-1f1f8.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1ea-1f1f8.svg rename to smileys/Universe/1f1ea-1f1f8.svg diff --git a/smileys/TwitterEmojiSVG/1f1ea.svg b/smileys/Universe/1f1ea.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1ea.svg rename to smileys/Universe/1f1ea.svg diff --git a/smileys/TwitterEmojiSVG/1f1eb-1f1f7.svg b/smileys/Universe/1f1eb-1f1f7.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1eb-1f1f7.svg rename to smileys/Universe/1f1eb-1f1f7.svg diff --git a/smileys/TwitterEmojiSVG/1f1eb.svg b/smileys/Universe/1f1eb.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1eb.svg rename to smileys/Universe/1f1eb.svg diff --git a/smileys/TwitterEmojiSVG/1f1ec-1f1e7.svg b/smileys/Universe/1f1ec-1f1e7.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1ec-1f1e7.svg rename to smileys/Universe/1f1ec-1f1e7.svg diff --git a/smileys/TwitterEmojiSVG/1f1ec.svg b/smileys/Universe/1f1ec.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1ec.svg rename to smileys/Universe/1f1ec.svg diff --git a/smileys/TwitterEmojiSVG/1f1ed.svg b/smileys/Universe/1f1ed.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1ed.svg rename to smileys/Universe/1f1ed.svg diff --git a/smileys/TwitterEmojiSVG/1f1ee-1f1f9.svg b/smileys/Universe/1f1ee-1f1f9.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1ee-1f1f9.svg rename to smileys/Universe/1f1ee-1f1f9.svg diff --git a/smileys/TwitterEmojiSVG/1f1ee.svg b/smileys/Universe/1f1ee.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1ee.svg rename to smileys/Universe/1f1ee.svg diff --git a/smileys/TwitterEmojiSVG/1f1ef-1f1f5.svg b/smileys/Universe/1f1ef-1f1f5.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1ef-1f1f5.svg rename to smileys/Universe/1f1ef-1f1f5.svg diff --git a/smileys/TwitterEmojiSVG/1f1ef.svg b/smileys/Universe/1f1ef.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1ef.svg rename to smileys/Universe/1f1ef.svg diff --git a/smileys/TwitterEmojiSVG/1f1f0-1f1f7.svg b/smileys/Universe/1f1f0-1f1f7.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1f0-1f1f7.svg rename to smileys/Universe/1f1f0-1f1f7.svg diff --git a/smileys/TwitterEmojiSVG/1f1f0.svg b/smileys/Universe/1f1f0.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1f0.svg rename to smileys/Universe/1f1f0.svg diff --git a/smileys/TwitterEmojiSVG/1f1f1.svg b/smileys/Universe/1f1f1.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1f1.svg rename to smileys/Universe/1f1f1.svg diff --git a/smileys/TwitterEmojiSVG/1f1f2.svg b/smileys/Universe/1f1f2.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1f2.svg rename to smileys/Universe/1f1f2.svg diff --git a/smileys/TwitterEmojiSVG/1f1f3.svg b/smileys/Universe/1f1f3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1f3.svg rename to smileys/Universe/1f1f3.svg diff --git a/smileys/TwitterEmojiSVG/1f1f4.svg b/smileys/Universe/1f1f4.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1f4.svg rename to smileys/Universe/1f1f4.svg diff --git a/smileys/TwitterEmojiSVG/1f1f5.svg b/smileys/Universe/1f1f5.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1f5.svg rename to smileys/Universe/1f1f5.svg diff --git a/smileys/TwitterEmojiSVG/1f1f6.svg b/smileys/Universe/1f1f6.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1f6.svg rename to smileys/Universe/1f1f6.svg diff --git a/smileys/TwitterEmojiSVG/1f1f7-1f1fa.svg b/smileys/Universe/1f1f7-1f1fa.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1f7-1f1fa.svg rename to smileys/Universe/1f1f7-1f1fa.svg diff --git a/smileys/TwitterEmojiSVG/1f1f7.svg b/smileys/Universe/1f1f7.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1f7.svg rename to smileys/Universe/1f1f7.svg diff --git a/smileys/TwitterEmojiSVG/1f1f8.svg b/smileys/Universe/1f1f8.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1f8.svg rename to smileys/Universe/1f1f8.svg diff --git a/smileys/TwitterEmojiSVG/1f1f9.svg b/smileys/Universe/1f1f9.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1f9.svg rename to smileys/Universe/1f1f9.svg diff --git a/smileys/TwitterEmojiSVG/1f1fa-1f1f8.svg b/smileys/Universe/1f1fa-1f1f8.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1fa-1f1f8.svg rename to smileys/Universe/1f1fa-1f1f8.svg diff --git a/smileys/TwitterEmojiSVG/1f1fa.svg b/smileys/Universe/1f1fa.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1fa.svg rename to smileys/Universe/1f1fa.svg diff --git a/smileys/TwitterEmojiSVG/1f1fb.svg b/smileys/Universe/1f1fb.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1fb.svg rename to smileys/Universe/1f1fb.svg diff --git a/smileys/TwitterEmojiSVG/1f1fc.svg b/smileys/Universe/1f1fc.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1fc.svg rename to smileys/Universe/1f1fc.svg diff --git a/smileys/TwitterEmojiSVG/1f1fd.svg b/smileys/Universe/1f1fd.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1fd.svg rename to smileys/Universe/1f1fd.svg diff --git a/smileys/TwitterEmojiSVG/1f1fe.svg b/smileys/Universe/1f1fe.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1fe.svg rename to smileys/Universe/1f1fe.svg diff --git a/smileys/TwitterEmojiSVG/1f1ff.svg b/smileys/Universe/1f1ff.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f1ff.svg rename to smileys/Universe/1f1ff.svg diff --git a/smileys/TwitterEmojiSVG/1f201.svg b/smileys/Universe/1f201.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f201.svg rename to smileys/Universe/1f201.svg diff --git a/smileys/TwitterEmojiSVG/1f202.svg b/smileys/Universe/1f202.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f202.svg rename to smileys/Universe/1f202.svg diff --git a/smileys/TwitterEmojiSVG/1f21a.svg b/smileys/Universe/1f21a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f21a.svg rename to smileys/Universe/1f21a.svg diff --git a/smileys/TwitterEmojiSVG/1f22f.svg b/smileys/Universe/1f22f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f22f.svg rename to smileys/Universe/1f22f.svg diff --git a/smileys/TwitterEmojiSVG/1f232.svg b/smileys/Universe/1f232.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f232.svg rename to smileys/Universe/1f232.svg diff --git a/smileys/TwitterEmojiSVG/1f233.svg b/smileys/Universe/1f233.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f233.svg rename to smileys/Universe/1f233.svg diff --git a/smileys/TwitterEmojiSVG/1f234.svg b/smileys/Universe/1f234.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f234.svg rename to smileys/Universe/1f234.svg diff --git a/smileys/TwitterEmojiSVG/1f235.svg b/smileys/Universe/1f235.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f235.svg rename to smileys/Universe/1f235.svg diff --git a/smileys/TwitterEmojiSVG/1f236.svg b/smileys/Universe/1f236.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f236.svg rename to smileys/Universe/1f236.svg diff --git a/smileys/TwitterEmojiSVG/1f237.svg b/smileys/Universe/1f237.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f237.svg rename to smileys/Universe/1f237.svg diff --git a/smileys/TwitterEmojiSVG/1f238.svg b/smileys/Universe/1f238.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f238.svg rename to smileys/Universe/1f238.svg diff --git a/smileys/TwitterEmojiSVG/1f239.svg b/smileys/Universe/1f239.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f239.svg rename to smileys/Universe/1f239.svg diff --git a/smileys/TwitterEmojiSVG/1f23a.svg b/smileys/Universe/1f23a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f23a.svg rename to smileys/Universe/1f23a.svg diff --git a/smileys/TwitterEmojiSVG/1f250.svg b/smileys/Universe/1f250.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f250.svg rename to smileys/Universe/1f250.svg diff --git a/smileys/TwitterEmojiSVG/1f251.svg b/smileys/Universe/1f251.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f251.svg rename to smileys/Universe/1f251.svg diff --git a/smileys/TwitterEmojiSVG/1f300.svg b/smileys/Universe/1f300.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f300.svg rename to smileys/Universe/1f300.svg diff --git a/smileys/TwitterEmojiSVG/1f301.svg b/smileys/Universe/1f301.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f301.svg rename to smileys/Universe/1f301.svg diff --git a/smileys/TwitterEmojiSVG/1f302.svg b/smileys/Universe/1f302.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f302.svg rename to smileys/Universe/1f302.svg diff --git a/smileys/TwitterEmojiSVG/1f303.svg b/smileys/Universe/1f303.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f303.svg rename to smileys/Universe/1f303.svg diff --git a/smileys/TwitterEmojiSVG/1f304.svg b/smileys/Universe/1f304.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f304.svg rename to smileys/Universe/1f304.svg diff --git a/smileys/TwitterEmojiSVG/1f305.svg b/smileys/Universe/1f305.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f305.svg rename to smileys/Universe/1f305.svg diff --git a/smileys/TwitterEmojiSVG/1f306.svg b/smileys/Universe/1f306.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f306.svg rename to smileys/Universe/1f306.svg diff --git a/smileys/TwitterEmojiSVG/1f307.svg b/smileys/Universe/1f307.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f307.svg rename to smileys/Universe/1f307.svg diff --git a/smileys/TwitterEmojiSVG/1f308.svg b/smileys/Universe/1f308.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f308.svg rename to smileys/Universe/1f308.svg diff --git a/smileys/TwitterEmojiSVG/1f309.svg b/smileys/Universe/1f309.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f309.svg rename to smileys/Universe/1f309.svg diff --git a/smileys/TwitterEmojiSVG/1f30a.svg b/smileys/Universe/1f30a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f30a.svg rename to smileys/Universe/1f30a.svg diff --git a/smileys/TwitterEmojiSVG/1f30b.svg b/smileys/Universe/1f30b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f30b.svg rename to smileys/Universe/1f30b.svg diff --git a/smileys/TwitterEmojiSVG/1f30c.svg b/smileys/Universe/1f30c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f30c.svg rename to smileys/Universe/1f30c.svg diff --git a/smileys/TwitterEmojiSVG/1f30d.svg b/smileys/Universe/1f30d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f30d.svg rename to smileys/Universe/1f30d.svg diff --git a/smileys/TwitterEmojiSVG/1f30e.svg b/smileys/Universe/1f30e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f30e.svg rename to smileys/Universe/1f30e.svg diff --git a/smileys/TwitterEmojiSVG/1f30f.svg b/smileys/Universe/1f30f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f30f.svg rename to smileys/Universe/1f30f.svg diff --git a/smileys/TwitterEmojiSVG/1f310.svg b/smileys/Universe/1f310.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f310.svg rename to smileys/Universe/1f310.svg diff --git a/smileys/TwitterEmojiSVG/1f311.svg b/smileys/Universe/1f311.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f311.svg rename to smileys/Universe/1f311.svg diff --git a/smileys/TwitterEmojiSVG/1f312.svg b/smileys/Universe/1f312.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f312.svg rename to smileys/Universe/1f312.svg diff --git a/smileys/TwitterEmojiSVG/1f313.svg b/smileys/Universe/1f313.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f313.svg rename to smileys/Universe/1f313.svg diff --git a/smileys/TwitterEmojiSVG/1f314.svg b/smileys/Universe/1f314.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f314.svg rename to smileys/Universe/1f314.svg diff --git a/smileys/TwitterEmojiSVG/1f315.svg b/smileys/Universe/1f315.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f315.svg rename to smileys/Universe/1f315.svg diff --git a/smileys/TwitterEmojiSVG/1f316.svg b/smileys/Universe/1f316.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f316.svg rename to smileys/Universe/1f316.svg diff --git a/smileys/TwitterEmojiSVG/1f317.svg b/smileys/Universe/1f317.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f317.svg rename to smileys/Universe/1f317.svg diff --git a/smileys/TwitterEmojiSVG/1f318.svg b/smileys/Universe/1f318.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f318.svg rename to smileys/Universe/1f318.svg diff --git a/smileys/TwitterEmojiSVG/1f319.svg b/smileys/Universe/1f319.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f319.svg rename to smileys/Universe/1f319.svg diff --git a/smileys/TwitterEmojiSVG/1f31a.svg b/smileys/Universe/1f31a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f31a.svg rename to smileys/Universe/1f31a.svg diff --git a/smileys/TwitterEmojiSVG/1f31b.svg b/smileys/Universe/1f31b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f31b.svg rename to smileys/Universe/1f31b.svg diff --git a/smileys/TwitterEmojiSVG/1f31c.svg b/smileys/Universe/1f31c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f31c.svg rename to smileys/Universe/1f31c.svg diff --git a/smileys/TwitterEmojiSVG/1f31d.svg b/smileys/Universe/1f31d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f31d.svg rename to smileys/Universe/1f31d.svg diff --git a/smileys/TwitterEmojiSVG/1f31e.svg b/smileys/Universe/1f31e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f31e.svg rename to smileys/Universe/1f31e.svg diff --git a/smileys/TwitterEmojiSVG/1f31f.svg b/smileys/Universe/1f31f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f31f.svg rename to smileys/Universe/1f31f.svg diff --git a/smileys/TwitterEmojiSVG/1f320.svg b/smileys/Universe/1f320.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f320.svg rename to smileys/Universe/1f320.svg diff --git a/smileys/TwitterEmojiSVG/1f330.svg b/smileys/Universe/1f330.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f330.svg rename to smileys/Universe/1f330.svg diff --git a/smileys/TwitterEmojiSVG/1f331.svg b/smileys/Universe/1f331.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f331.svg rename to smileys/Universe/1f331.svg diff --git a/smileys/TwitterEmojiSVG/1f332.svg b/smileys/Universe/1f332.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f332.svg rename to smileys/Universe/1f332.svg diff --git a/smileys/TwitterEmojiSVG/1f333.svg b/smileys/Universe/1f333.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f333.svg rename to smileys/Universe/1f333.svg diff --git a/smileys/TwitterEmojiSVG/1f334.svg b/smileys/Universe/1f334.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f334.svg rename to smileys/Universe/1f334.svg diff --git a/smileys/TwitterEmojiSVG/1f335.svg b/smileys/Universe/1f335.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f335.svg rename to smileys/Universe/1f335.svg diff --git a/smileys/TwitterEmojiSVG/1f337.svg b/smileys/Universe/1f337.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f337.svg rename to smileys/Universe/1f337.svg diff --git a/smileys/TwitterEmojiSVG/1f338.svg b/smileys/Universe/1f338.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f338.svg rename to smileys/Universe/1f338.svg diff --git a/smileys/TwitterEmojiSVG/1f339.svg b/smileys/Universe/1f339.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f339.svg rename to smileys/Universe/1f339.svg diff --git a/smileys/TwitterEmojiSVG/1f33a.svg b/smileys/Universe/1f33a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f33a.svg rename to smileys/Universe/1f33a.svg diff --git a/smileys/TwitterEmojiSVG/1f33b.svg b/smileys/Universe/1f33b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f33b.svg rename to smileys/Universe/1f33b.svg diff --git a/smileys/TwitterEmojiSVG/1f33c.svg b/smileys/Universe/1f33c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f33c.svg rename to smileys/Universe/1f33c.svg diff --git a/smileys/TwitterEmojiSVG/1f33d.svg b/smileys/Universe/1f33d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f33d.svg rename to smileys/Universe/1f33d.svg diff --git a/smileys/TwitterEmojiSVG/1f33e.svg b/smileys/Universe/1f33e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f33e.svg rename to smileys/Universe/1f33e.svg diff --git a/smileys/TwitterEmojiSVG/1f33f.svg b/smileys/Universe/1f33f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f33f.svg rename to smileys/Universe/1f33f.svg diff --git a/smileys/TwitterEmojiSVG/1f340.svg b/smileys/Universe/1f340.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f340.svg rename to smileys/Universe/1f340.svg diff --git a/smileys/TwitterEmojiSVG/1f341.svg b/smileys/Universe/1f341.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f341.svg rename to smileys/Universe/1f341.svg diff --git a/smileys/TwitterEmojiSVG/1f342.svg b/smileys/Universe/1f342.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f342.svg rename to smileys/Universe/1f342.svg diff --git a/smileys/TwitterEmojiSVG/1f343.svg b/smileys/Universe/1f343.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f343.svg rename to smileys/Universe/1f343.svg diff --git a/smileys/TwitterEmojiSVG/1f344.svg b/smileys/Universe/1f344.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f344.svg rename to smileys/Universe/1f344.svg diff --git a/smileys/TwitterEmojiSVG/1f345.svg b/smileys/Universe/1f345.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f345.svg rename to smileys/Universe/1f345.svg diff --git a/smileys/TwitterEmojiSVG/1f346.svg b/smileys/Universe/1f346.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f346.svg rename to smileys/Universe/1f346.svg diff --git a/smileys/TwitterEmojiSVG/1f347.svg b/smileys/Universe/1f347.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f347.svg rename to smileys/Universe/1f347.svg diff --git a/smileys/TwitterEmojiSVG/1f348.svg b/smileys/Universe/1f348.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f348.svg rename to smileys/Universe/1f348.svg diff --git a/smileys/TwitterEmojiSVG/1f349.svg b/smileys/Universe/1f349.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f349.svg rename to smileys/Universe/1f349.svg diff --git a/smileys/TwitterEmojiSVG/1f34a.svg b/smileys/Universe/1f34a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f34a.svg rename to smileys/Universe/1f34a.svg diff --git a/smileys/TwitterEmojiSVG/1f34b.svg b/smileys/Universe/1f34b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f34b.svg rename to smileys/Universe/1f34b.svg diff --git a/smileys/TwitterEmojiSVG/1f34c.svg b/smileys/Universe/1f34c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f34c.svg rename to smileys/Universe/1f34c.svg diff --git a/smileys/TwitterEmojiSVG/1f34d.svg b/smileys/Universe/1f34d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f34d.svg rename to smileys/Universe/1f34d.svg diff --git a/smileys/TwitterEmojiSVG/1f34e.svg b/smileys/Universe/1f34e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f34e.svg rename to smileys/Universe/1f34e.svg diff --git a/smileys/TwitterEmojiSVG/1f34f.svg b/smileys/Universe/1f34f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f34f.svg rename to smileys/Universe/1f34f.svg diff --git a/smileys/TwitterEmojiSVG/1f350.svg b/smileys/Universe/1f350.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f350.svg rename to smileys/Universe/1f350.svg diff --git a/smileys/TwitterEmojiSVG/1f351.svg b/smileys/Universe/1f351.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f351.svg rename to smileys/Universe/1f351.svg diff --git a/smileys/TwitterEmojiSVG/1f352.svg b/smileys/Universe/1f352.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f352.svg rename to smileys/Universe/1f352.svg diff --git a/smileys/TwitterEmojiSVG/1f353.svg b/smileys/Universe/1f353.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f353.svg rename to smileys/Universe/1f353.svg diff --git a/smileys/TwitterEmojiSVG/1f354.svg b/smileys/Universe/1f354.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f354.svg rename to smileys/Universe/1f354.svg diff --git a/smileys/TwitterEmojiSVG/1f355.svg b/smileys/Universe/1f355.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f355.svg rename to smileys/Universe/1f355.svg diff --git a/smileys/TwitterEmojiSVG/1f356.svg b/smileys/Universe/1f356.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f356.svg rename to smileys/Universe/1f356.svg diff --git a/smileys/TwitterEmojiSVG/1f357.svg b/smileys/Universe/1f357.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f357.svg rename to smileys/Universe/1f357.svg diff --git a/smileys/TwitterEmojiSVG/1f358.svg b/smileys/Universe/1f358.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f358.svg rename to smileys/Universe/1f358.svg diff --git a/smileys/TwitterEmojiSVG/1f359.svg b/smileys/Universe/1f359.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f359.svg rename to smileys/Universe/1f359.svg diff --git a/smileys/TwitterEmojiSVG/1f35a.svg b/smileys/Universe/1f35a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f35a.svg rename to smileys/Universe/1f35a.svg diff --git a/smileys/TwitterEmojiSVG/1f35b.svg b/smileys/Universe/1f35b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f35b.svg rename to smileys/Universe/1f35b.svg diff --git a/smileys/TwitterEmojiSVG/1f35c.svg b/smileys/Universe/1f35c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f35c.svg rename to smileys/Universe/1f35c.svg diff --git a/smileys/TwitterEmojiSVG/1f35d.svg b/smileys/Universe/1f35d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f35d.svg rename to smileys/Universe/1f35d.svg diff --git a/smileys/TwitterEmojiSVG/1f35e.svg b/smileys/Universe/1f35e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f35e.svg rename to smileys/Universe/1f35e.svg diff --git a/smileys/TwitterEmojiSVG/1f35f.svg b/smileys/Universe/1f35f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f35f.svg rename to smileys/Universe/1f35f.svg diff --git a/smileys/TwitterEmojiSVG/1f360.svg b/smileys/Universe/1f360.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f360.svg rename to smileys/Universe/1f360.svg diff --git a/smileys/TwitterEmojiSVG/1f361.svg b/smileys/Universe/1f361.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f361.svg rename to smileys/Universe/1f361.svg diff --git a/smileys/TwitterEmojiSVG/1f362.svg b/smileys/Universe/1f362.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f362.svg rename to smileys/Universe/1f362.svg diff --git a/smileys/TwitterEmojiSVG/1f363.svg b/smileys/Universe/1f363.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f363.svg rename to smileys/Universe/1f363.svg diff --git a/smileys/TwitterEmojiSVG/1f364.svg b/smileys/Universe/1f364.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f364.svg rename to smileys/Universe/1f364.svg diff --git a/smileys/TwitterEmojiSVG/1f365.svg b/smileys/Universe/1f365.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f365.svg rename to smileys/Universe/1f365.svg diff --git a/smileys/TwitterEmojiSVG/1f366.svg b/smileys/Universe/1f366.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f366.svg rename to smileys/Universe/1f366.svg diff --git a/smileys/TwitterEmojiSVG/1f367.svg b/smileys/Universe/1f367.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f367.svg rename to smileys/Universe/1f367.svg diff --git a/smileys/TwitterEmojiSVG/1f368.svg b/smileys/Universe/1f368.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f368.svg rename to smileys/Universe/1f368.svg diff --git a/smileys/TwitterEmojiSVG/1f369.svg b/smileys/Universe/1f369.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f369.svg rename to smileys/Universe/1f369.svg diff --git a/smileys/TwitterEmojiSVG/1f36a.svg b/smileys/Universe/1f36a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f36a.svg rename to smileys/Universe/1f36a.svg diff --git a/smileys/TwitterEmojiSVG/1f36b.svg b/smileys/Universe/1f36b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f36b.svg rename to smileys/Universe/1f36b.svg diff --git a/smileys/TwitterEmojiSVG/1f36c.svg b/smileys/Universe/1f36c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f36c.svg rename to smileys/Universe/1f36c.svg diff --git a/smileys/TwitterEmojiSVG/1f36d.svg b/smileys/Universe/1f36d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f36d.svg rename to smileys/Universe/1f36d.svg diff --git a/smileys/TwitterEmojiSVG/1f36e.svg b/smileys/Universe/1f36e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f36e.svg rename to smileys/Universe/1f36e.svg diff --git a/smileys/TwitterEmojiSVG/1f36f.svg b/smileys/Universe/1f36f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f36f.svg rename to smileys/Universe/1f36f.svg diff --git a/smileys/TwitterEmojiSVG/1f370.svg b/smileys/Universe/1f370.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f370.svg rename to smileys/Universe/1f370.svg diff --git a/smileys/TwitterEmojiSVG/1f371.svg b/smileys/Universe/1f371.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f371.svg rename to smileys/Universe/1f371.svg diff --git a/smileys/TwitterEmojiSVG/1f372.svg b/smileys/Universe/1f372.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f372.svg rename to smileys/Universe/1f372.svg diff --git a/smileys/TwitterEmojiSVG/1f373.svg b/smileys/Universe/1f373.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f373.svg rename to smileys/Universe/1f373.svg diff --git a/smileys/TwitterEmojiSVG/1f374.svg b/smileys/Universe/1f374.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f374.svg rename to smileys/Universe/1f374.svg diff --git a/smileys/TwitterEmojiSVG/1f375.svg b/smileys/Universe/1f375.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f375.svg rename to smileys/Universe/1f375.svg diff --git a/smileys/TwitterEmojiSVG/1f376.svg b/smileys/Universe/1f376.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f376.svg rename to smileys/Universe/1f376.svg diff --git a/smileys/TwitterEmojiSVG/1f377.svg b/smileys/Universe/1f377.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f377.svg rename to smileys/Universe/1f377.svg diff --git a/smileys/TwitterEmojiSVG/1f378.svg b/smileys/Universe/1f378.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f378.svg rename to smileys/Universe/1f378.svg diff --git a/smileys/TwitterEmojiSVG/1f379.svg b/smileys/Universe/1f379.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f379.svg rename to smileys/Universe/1f379.svg diff --git a/smileys/TwitterEmojiSVG/1f37a.svg b/smileys/Universe/1f37a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f37a.svg rename to smileys/Universe/1f37a.svg diff --git a/smileys/TwitterEmojiSVG/1f37b.svg b/smileys/Universe/1f37b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f37b.svg rename to smileys/Universe/1f37b.svg diff --git a/smileys/TwitterEmojiSVG/1f37c.svg b/smileys/Universe/1f37c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f37c.svg rename to smileys/Universe/1f37c.svg diff --git a/smileys/TwitterEmojiSVG/1f380.svg b/smileys/Universe/1f380.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f380.svg rename to smileys/Universe/1f380.svg diff --git a/smileys/TwitterEmojiSVG/1f381.svg b/smileys/Universe/1f381.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f381.svg rename to smileys/Universe/1f381.svg diff --git a/smileys/TwitterEmojiSVG/1f382.svg b/smileys/Universe/1f382.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f382.svg rename to smileys/Universe/1f382.svg diff --git a/smileys/TwitterEmojiSVG/1f383.svg b/smileys/Universe/1f383.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f383.svg rename to smileys/Universe/1f383.svg diff --git a/smileys/TwitterEmojiSVG/1f384.svg b/smileys/Universe/1f384.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f384.svg rename to smileys/Universe/1f384.svg diff --git a/smileys/TwitterEmojiSVG/1f385.svg b/smileys/Universe/1f385.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f385.svg rename to smileys/Universe/1f385.svg diff --git a/smileys/TwitterEmojiSVG/1f386.svg b/smileys/Universe/1f386.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f386.svg rename to smileys/Universe/1f386.svg diff --git a/smileys/TwitterEmojiSVG/1f387.svg b/smileys/Universe/1f387.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f387.svg rename to smileys/Universe/1f387.svg diff --git a/smileys/TwitterEmojiSVG/1f388.svg b/smileys/Universe/1f388.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f388.svg rename to smileys/Universe/1f388.svg diff --git a/smileys/TwitterEmojiSVG/1f389.svg b/smileys/Universe/1f389.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f389.svg rename to smileys/Universe/1f389.svg diff --git a/smileys/TwitterEmojiSVG/1f38a.svg b/smileys/Universe/1f38a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f38a.svg rename to smileys/Universe/1f38a.svg diff --git a/smileys/TwitterEmojiSVG/1f38b.svg b/smileys/Universe/1f38b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f38b.svg rename to smileys/Universe/1f38b.svg diff --git a/smileys/TwitterEmojiSVG/1f38c.svg b/smileys/Universe/1f38c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f38c.svg rename to smileys/Universe/1f38c.svg diff --git a/smileys/TwitterEmojiSVG/1f38d.svg b/smileys/Universe/1f38d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f38d.svg rename to smileys/Universe/1f38d.svg diff --git a/smileys/TwitterEmojiSVG/1f38e.svg b/smileys/Universe/1f38e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f38e.svg rename to smileys/Universe/1f38e.svg diff --git a/smileys/TwitterEmojiSVG/1f38f.svg b/smileys/Universe/1f38f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f38f.svg rename to smileys/Universe/1f38f.svg diff --git a/smileys/TwitterEmojiSVG/1f390.svg b/smileys/Universe/1f390.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f390.svg rename to smileys/Universe/1f390.svg diff --git a/smileys/TwitterEmojiSVG/1f391.svg b/smileys/Universe/1f391.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f391.svg rename to smileys/Universe/1f391.svg diff --git a/smileys/TwitterEmojiSVG/1f392.svg b/smileys/Universe/1f392.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f392.svg rename to smileys/Universe/1f392.svg diff --git a/smileys/TwitterEmojiSVG/1f393.svg b/smileys/Universe/1f393.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f393.svg rename to smileys/Universe/1f393.svg diff --git a/smileys/TwitterEmojiSVG/1f3a0.svg b/smileys/Universe/1f3a0.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3a0.svg rename to smileys/Universe/1f3a0.svg diff --git a/smileys/TwitterEmojiSVG/1f3a1.svg b/smileys/Universe/1f3a1.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3a1.svg rename to smileys/Universe/1f3a1.svg diff --git a/smileys/TwitterEmojiSVG/1f3a2.svg b/smileys/Universe/1f3a2.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3a2.svg rename to smileys/Universe/1f3a2.svg diff --git a/smileys/TwitterEmojiSVG/1f3a3.svg b/smileys/Universe/1f3a3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3a3.svg rename to smileys/Universe/1f3a3.svg diff --git a/smileys/TwitterEmojiSVG/1f3a4.svg b/smileys/Universe/1f3a4.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3a4.svg rename to smileys/Universe/1f3a4.svg diff --git a/smileys/TwitterEmojiSVG/1f3a5.svg b/smileys/Universe/1f3a5.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3a5.svg rename to smileys/Universe/1f3a5.svg diff --git a/smileys/TwitterEmojiSVG/1f3a6.svg b/smileys/Universe/1f3a6.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3a6.svg rename to smileys/Universe/1f3a6.svg diff --git a/smileys/TwitterEmojiSVG/1f3a7.svg b/smileys/Universe/1f3a7.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3a7.svg rename to smileys/Universe/1f3a7.svg diff --git a/smileys/TwitterEmojiSVG/1f3a8.svg b/smileys/Universe/1f3a8.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3a8.svg rename to smileys/Universe/1f3a8.svg diff --git a/smileys/TwitterEmojiSVG/1f3a9.svg b/smileys/Universe/1f3a9.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3a9.svg rename to smileys/Universe/1f3a9.svg diff --git a/smileys/TwitterEmojiSVG/1f3aa.svg b/smileys/Universe/1f3aa.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3aa.svg rename to smileys/Universe/1f3aa.svg diff --git a/smileys/TwitterEmojiSVG/1f3ab.svg b/smileys/Universe/1f3ab.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3ab.svg rename to smileys/Universe/1f3ab.svg diff --git a/smileys/TwitterEmojiSVG/1f3ac.svg b/smileys/Universe/1f3ac.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3ac.svg rename to smileys/Universe/1f3ac.svg diff --git a/smileys/TwitterEmojiSVG/1f3ad.svg b/smileys/Universe/1f3ad.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3ad.svg rename to smileys/Universe/1f3ad.svg diff --git a/smileys/TwitterEmojiSVG/1f3ae.svg b/smileys/Universe/1f3ae.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3ae.svg rename to smileys/Universe/1f3ae.svg diff --git a/smileys/TwitterEmojiSVG/1f3af.svg b/smileys/Universe/1f3af.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3af.svg rename to smileys/Universe/1f3af.svg diff --git a/smileys/TwitterEmojiSVG/1f3b0.svg b/smileys/Universe/1f3b0.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3b0.svg rename to smileys/Universe/1f3b0.svg diff --git a/smileys/TwitterEmojiSVG/1f3b1.svg b/smileys/Universe/1f3b1.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3b1.svg rename to smileys/Universe/1f3b1.svg diff --git a/smileys/TwitterEmojiSVG/1f3b2.svg b/smileys/Universe/1f3b2.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3b2.svg rename to smileys/Universe/1f3b2.svg diff --git a/smileys/TwitterEmojiSVG/1f3b3.svg b/smileys/Universe/1f3b3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3b3.svg rename to smileys/Universe/1f3b3.svg diff --git a/smileys/TwitterEmojiSVG/1f3b4.svg b/smileys/Universe/1f3b4.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3b4.svg rename to smileys/Universe/1f3b4.svg diff --git a/smileys/TwitterEmojiSVG/1f3b5.svg b/smileys/Universe/1f3b5.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3b5.svg rename to smileys/Universe/1f3b5.svg diff --git a/smileys/TwitterEmojiSVG/1f3b6.svg b/smileys/Universe/1f3b6.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3b6.svg rename to smileys/Universe/1f3b6.svg diff --git a/smileys/TwitterEmojiSVG/1f3b7.svg b/smileys/Universe/1f3b7.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3b7.svg rename to smileys/Universe/1f3b7.svg diff --git a/smileys/TwitterEmojiSVG/1f3b8.svg b/smileys/Universe/1f3b8.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3b8.svg rename to smileys/Universe/1f3b8.svg diff --git a/smileys/TwitterEmojiSVG/1f3b9.svg b/smileys/Universe/1f3b9.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3b9.svg rename to smileys/Universe/1f3b9.svg diff --git a/smileys/TwitterEmojiSVG/1f3ba.svg b/smileys/Universe/1f3ba.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3ba.svg rename to smileys/Universe/1f3ba.svg diff --git a/smileys/TwitterEmojiSVG/1f3bb.svg b/smileys/Universe/1f3bb.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3bb.svg rename to smileys/Universe/1f3bb.svg diff --git a/smileys/TwitterEmojiSVG/1f3bc.svg b/smileys/Universe/1f3bc.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3bc.svg rename to smileys/Universe/1f3bc.svg diff --git a/smileys/TwitterEmojiSVG/1f3bd.svg b/smileys/Universe/1f3bd.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3bd.svg rename to smileys/Universe/1f3bd.svg diff --git a/smileys/TwitterEmojiSVG/1f3be.svg b/smileys/Universe/1f3be.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3be.svg rename to smileys/Universe/1f3be.svg diff --git a/smileys/TwitterEmojiSVG/1f3bf.svg b/smileys/Universe/1f3bf.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3bf.svg rename to smileys/Universe/1f3bf.svg diff --git a/smileys/TwitterEmojiSVG/1f3c0.svg b/smileys/Universe/1f3c0.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3c0.svg rename to smileys/Universe/1f3c0.svg diff --git a/smileys/TwitterEmojiSVG/1f3c1.svg b/smileys/Universe/1f3c1.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3c1.svg rename to smileys/Universe/1f3c1.svg diff --git a/smileys/TwitterEmojiSVG/1f3c2.svg b/smileys/Universe/1f3c2.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3c2.svg rename to smileys/Universe/1f3c2.svg diff --git a/smileys/TwitterEmojiSVG/1f3c3.svg b/smileys/Universe/1f3c3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3c3.svg rename to smileys/Universe/1f3c3.svg diff --git a/smileys/TwitterEmojiSVG/1f3c4.svg b/smileys/Universe/1f3c4.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3c4.svg rename to smileys/Universe/1f3c4.svg diff --git a/smileys/TwitterEmojiSVG/1f3c6.svg b/smileys/Universe/1f3c6.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3c6.svg rename to smileys/Universe/1f3c6.svg diff --git a/smileys/TwitterEmojiSVG/1f3c7.svg b/smileys/Universe/1f3c7.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3c7.svg rename to smileys/Universe/1f3c7.svg diff --git a/smileys/TwitterEmojiSVG/1f3c8.svg b/smileys/Universe/1f3c8.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3c8.svg rename to smileys/Universe/1f3c8.svg diff --git a/smileys/TwitterEmojiSVG/1f3c9.svg b/smileys/Universe/1f3c9.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3c9.svg rename to smileys/Universe/1f3c9.svg diff --git a/smileys/TwitterEmojiSVG/1f3ca.svg b/smileys/Universe/1f3ca.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3ca.svg rename to smileys/Universe/1f3ca.svg diff --git a/smileys/TwitterEmojiSVG/1f3e0.svg b/smileys/Universe/1f3e0.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3e0.svg rename to smileys/Universe/1f3e0.svg diff --git a/smileys/TwitterEmojiSVG/1f3e1.svg b/smileys/Universe/1f3e1.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3e1.svg rename to smileys/Universe/1f3e1.svg diff --git a/smileys/TwitterEmojiSVG/1f3e2.svg b/smileys/Universe/1f3e2.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3e2.svg rename to smileys/Universe/1f3e2.svg diff --git a/smileys/TwitterEmojiSVG/1f3e3.svg b/smileys/Universe/1f3e3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3e3.svg rename to smileys/Universe/1f3e3.svg diff --git a/smileys/TwitterEmojiSVG/1f3e4.svg b/smileys/Universe/1f3e4.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3e4.svg rename to smileys/Universe/1f3e4.svg diff --git a/smileys/TwitterEmojiSVG/1f3e5.svg b/smileys/Universe/1f3e5.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3e5.svg rename to smileys/Universe/1f3e5.svg diff --git a/smileys/TwitterEmojiSVG/1f3e6.svg b/smileys/Universe/1f3e6.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3e6.svg rename to smileys/Universe/1f3e6.svg diff --git a/smileys/TwitterEmojiSVG/1f3e7.svg b/smileys/Universe/1f3e7.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3e7.svg rename to smileys/Universe/1f3e7.svg diff --git a/smileys/TwitterEmojiSVG/1f3e8.svg b/smileys/Universe/1f3e8.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3e8.svg rename to smileys/Universe/1f3e8.svg diff --git a/smileys/TwitterEmojiSVG/1f3e9.svg b/smileys/Universe/1f3e9.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3e9.svg rename to smileys/Universe/1f3e9.svg diff --git a/smileys/TwitterEmojiSVG/1f3ea.svg b/smileys/Universe/1f3ea.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3ea.svg rename to smileys/Universe/1f3ea.svg diff --git a/smileys/TwitterEmojiSVG/1f3eb.svg b/smileys/Universe/1f3eb.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3eb.svg rename to smileys/Universe/1f3eb.svg diff --git a/smileys/TwitterEmojiSVG/1f3ec.svg b/smileys/Universe/1f3ec.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3ec.svg rename to smileys/Universe/1f3ec.svg diff --git a/smileys/TwitterEmojiSVG/1f3ed.svg b/smileys/Universe/1f3ed.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3ed.svg rename to smileys/Universe/1f3ed.svg diff --git a/smileys/TwitterEmojiSVG/1f3ee.svg b/smileys/Universe/1f3ee.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3ee.svg rename to smileys/Universe/1f3ee.svg diff --git a/smileys/TwitterEmojiSVG/1f3ef.svg b/smileys/Universe/1f3ef.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3ef.svg rename to smileys/Universe/1f3ef.svg diff --git a/smileys/TwitterEmojiSVG/1f3f0.svg b/smileys/Universe/1f3f0.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f3f0.svg rename to smileys/Universe/1f3f0.svg diff --git a/smileys/TwitterEmojiSVG/1f400.svg b/smileys/Universe/1f400.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f400.svg rename to smileys/Universe/1f400.svg diff --git a/smileys/TwitterEmojiSVG/1f401.svg b/smileys/Universe/1f401.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f401.svg rename to smileys/Universe/1f401.svg diff --git a/smileys/TwitterEmojiSVG/1f402.svg b/smileys/Universe/1f402.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f402.svg rename to smileys/Universe/1f402.svg diff --git a/smileys/TwitterEmojiSVG/1f403.svg b/smileys/Universe/1f403.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f403.svg rename to smileys/Universe/1f403.svg diff --git a/smileys/TwitterEmojiSVG/1f404.svg b/smileys/Universe/1f404.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f404.svg rename to smileys/Universe/1f404.svg diff --git a/smileys/TwitterEmojiSVG/1f405.svg b/smileys/Universe/1f405.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f405.svg rename to smileys/Universe/1f405.svg diff --git a/smileys/TwitterEmojiSVG/1f406.svg b/smileys/Universe/1f406.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f406.svg rename to smileys/Universe/1f406.svg diff --git a/smileys/TwitterEmojiSVG/1f407.svg b/smileys/Universe/1f407.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f407.svg rename to smileys/Universe/1f407.svg diff --git a/smileys/TwitterEmojiSVG/1f408.svg b/smileys/Universe/1f408.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f408.svg rename to smileys/Universe/1f408.svg diff --git a/smileys/TwitterEmojiSVG/1f409.svg b/smileys/Universe/1f409.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f409.svg rename to smileys/Universe/1f409.svg diff --git a/smileys/TwitterEmojiSVG/1f40a.svg b/smileys/Universe/1f40a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f40a.svg rename to smileys/Universe/1f40a.svg diff --git a/smileys/TwitterEmojiSVG/1f40b.svg b/smileys/Universe/1f40b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f40b.svg rename to smileys/Universe/1f40b.svg diff --git a/smileys/TwitterEmojiSVG/1f40c.svg b/smileys/Universe/1f40c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f40c.svg rename to smileys/Universe/1f40c.svg diff --git a/smileys/TwitterEmojiSVG/1f40d.svg b/smileys/Universe/1f40d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f40d.svg rename to smileys/Universe/1f40d.svg diff --git a/smileys/TwitterEmojiSVG/1f40e.svg b/smileys/Universe/1f40e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f40e.svg rename to smileys/Universe/1f40e.svg diff --git a/smileys/TwitterEmojiSVG/1f40f.svg b/smileys/Universe/1f40f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f40f.svg rename to smileys/Universe/1f40f.svg diff --git a/smileys/TwitterEmojiSVG/1f410.svg b/smileys/Universe/1f410.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f410.svg rename to smileys/Universe/1f410.svg diff --git a/smileys/TwitterEmojiSVG/1f411.svg b/smileys/Universe/1f411.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f411.svg rename to smileys/Universe/1f411.svg diff --git a/smileys/TwitterEmojiSVG/1f412.svg b/smileys/Universe/1f412.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f412.svg rename to smileys/Universe/1f412.svg diff --git a/smileys/TwitterEmojiSVG/1f413.svg b/smileys/Universe/1f413.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f413.svg rename to smileys/Universe/1f413.svg diff --git a/smileys/TwitterEmojiSVG/1f414.svg b/smileys/Universe/1f414.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f414.svg rename to smileys/Universe/1f414.svg diff --git a/smileys/TwitterEmojiSVG/1f415.svg b/smileys/Universe/1f415.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f415.svg rename to smileys/Universe/1f415.svg diff --git a/smileys/TwitterEmojiSVG/1f416.svg b/smileys/Universe/1f416.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f416.svg rename to smileys/Universe/1f416.svg diff --git a/smileys/TwitterEmojiSVG/1f417.svg b/smileys/Universe/1f417.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f417.svg rename to smileys/Universe/1f417.svg diff --git a/smileys/TwitterEmojiSVG/1f418.svg b/smileys/Universe/1f418.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f418.svg rename to smileys/Universe/1f418.svg diff --git a/smileys/TwitterEmojiSVG/1f419.svg b/smileys/Universe/1f419.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f419.svg rename to smileys/Universe/1f419.svg diff --git a/smileys/TwitterEmojiSVG/1f41a.svg b/smileys/Universe/1f41a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f41a.svg rename to smileys/Universe/1f41a.svg diff --git a/smileys/TwitterEmojiSVG/1f41b.svg b/smileys/Universe/1f41b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f41b.svg rename to smileys/Universe/1f41b.svg diff --git a/smileys/TwitterEmojiSVG/1f41c.svg b/smileys/Universe/1f41c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f41c.svg rename to smileys/Universe/1f41c.svg diff --git a/smileys/TwitterEmojiSVG/1f41d.svg b/smileys/Universe/1f41d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f41d.svg rename to smileys/Universe/1f41d.svg diff --git a/smileys/TwitterEmojiSVG/1f41e.svg b/smileys/Universe/1f41e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f41e.svg rename to smileys/Universe/1f41e.svg diff --git a/smileys/TwitterEmojiSVG/1f41f.svg b/smileys/Universe/1f41f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f41f.svg rename to smileys/Universe/1f41f.svg diff --git a/smileys/TwitterEmojiSVG/1f420.svg b/smileys/Universe/1f420.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f420.svg rename to smileys/Universe/1f420.svg diff --git a/smileys/TwitterEmojiSVG/1f421.svg b/smileys/Universe/1f421.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f421.svg rename to smileys/Universe/1f421.svg diff --git a/smileys/TwitterEmojiSVG/1f422.svg b/smileys/Universe/1f422.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f422.svg rename to smileys/Universe/1f422.svg diff --git a/smileys/TwitterEmojiSVG/1f423.svg b/smileys/Universe/1f423.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f423.svg rename to smileys/Universe/1f423.svg diff --git a/smileys/TwitterEmojiSVG/1f424.svg b/smileys/Universe/1f424.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f424.svg rename to smileys/Universe/1f424.svg diff --git a/smileys/TwitterEmojiSVG/1f425.svg b/smileys/Universe/1f425.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f425.svg rename to smileys/Universe/1f425.svg diff --git a/smileys/TwitterEmojiSVG/1f426.svg b/smileys/Universe/1f426.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f426.svg rename to smileys/Universe/1f426.svg diff --git a/smileys/TwitterEmojiSVG/1f427.svg b/smileys/Universe/1f427.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f427.svg rename to smileys/Universe/1f427.svg diff --git a/smileys/TwitterEmojiSVG/1f428.svg b/smileys/Universe/1f428.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f428.svg rename to smileys/Universe/1f428.svg diff --git a/smileys/TwitterEmojiSVG/1f429.svg b/smileys/Universe/1f429.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f429.svg rename to smileys/Universe/1f429.svg diff --git a/smileys/TwitterEmojiSVG/1f42a.svg b/smileys/Universe/1f42a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f42a.svg rename to smileys/Universe/1f42a.svg diff --git a/smileys/TwitterEmojiSVG/1f42b.svg b/smileys/Universe/1f42b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f42b.svg rename to smileys/Universe/1f42b.svg diff --git a/smileys/TwitterEmojiSVG/1f42c.svg b/smileys/Universe/1f42c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f42c.svg rename to smileys/Universe/1f42c.svg diff --git a/smileys/TwitterEmojiSVG/1f42d.svg b/smileys/Universe/1f42d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f42d.svg rename to smileys/Universe/1f42d.svg diff --git a/smileys/TwitterEmojiSVG/1f42e.svg b/smileys/Universe/1f42e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f42e.svg rename to smileys/Universe/1f42e.svg diff --git a/smileys/TwitterEmojiSVG/1f42f.svg b/smileys/Universe/1f42f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f42f.svg rename to smileys/Universe/1f42f.svg diff --git a/smileys/TwitterEmojiSVG/1f430.svg b/smileys/Universe/1f430.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f430.svg rename to smileys/Universe/1f430.svg diff --git a/smileys/TwitterEmojiSVG/1f431.svg b/smileys/Universe/1f431.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f431.svg rename to smileys/Universe/1f431.svg diff --git a/smileys/TwitterEmojiSVG/1f432.svg b/smileys/Universe/1f432.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f432.svg rename to smileys/Universe/1f432.svg diff --git a/smileys/TwitterEmojiSVG/1f433.svg b/smileys/Universe/1f433.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f433.svg rename to smileys/Universe/1f433.svg diff --git a/smileys/TwitterEmojiSVG/1f434.svg b/smileys/Universe/1f434.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f434.svg rename to smileys/Universe/1f434.svg diff --git a/smileys/TwitterEmojiSVG/1f435.svg b/smileys/Universe/1f435.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f435.svg rename to smileys/Universe/1f435.svg diff --git a/smileys/TwitterEmojiSVG/1f436.svg b/smileys/Universe/1f436.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f436.svg rename to smileys/Universe/1f436.svg diff --git a/smileys/TwitterEmojiSVG/1f437.svg b/smileys/Universe/1f437.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f437.svg rename to smileys/Universe/1f437.svg diff --git a/smileys/TwitterEmojiSVG/1f438.svg b/smileys/Universe/1f438.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f438.svg rename to smileys/Universe/1f438.svg diff --git a/smileys/TwitterEmojiSVG/1f439.svg b/smileys/Universe/1f439.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f439.svg rename to smileys/Universe/1f439.svg diff --git a/smileys/TwitterEmojiSVG/1f43a.svg b/smileys/Universe/1f43a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f43a.svg rename to smileys/Universe/1f43a.svg diff --git a/smileys/TwitterEmojiSVG/1f43b.svg b/smileys/Universe/1f43b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f43b.svg rename to smileys/Universe/1f43b.svg diff --git a/smileys/TwitterEmojiSVG/1f43c.svg b/smileys/Universe/1f43c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f43c.svg rename to smileys/Universe/1f43c.svg diff --git a/smileys/TwitterEmojiSVG/1f43d.svg b/smileys/Universe/1f43d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f43d.svg rename to smileys/Universe/1f43d.svg diff --git a/smileys/TwitterEmojiSVG/1f43e.svg b/smileys/Universe/1f43e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f43e.svg rename to smileys/Universe/1f43e.svg diff --git a/smileys/TwitterEmojiSVG/1f440.svg b/smileys/Universe/1f440.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f440.svg rename to smileys/Universe/1f440.svg diff --git a/smileys/TwitterEmojiSVG/1f442.svg b/smileys/Universe/1f442.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f442.svg rename to smileys/Universe/1f442.svg diff --git a/smileys/TwitterEmojiSVG/1f443.svg b/smileys/Universe/1f443.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f443.svg rename to smileys/Universe/1f443.svg diff --git a/smileys/TwitterEmojiSVG/1f444.svg b/smileys/Universe/1f444.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f444.svg rename to smileys/Universe/1f444.svg diff --git a/smileys/TwitterEmojiSVG/1f445.svg b/smileys/Universe/1f445.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f445.svg rename to smileys/Universe/1f445.svg diff --git a/smileys/TwitterEmojiSVG/1f446.svg b/smileys/Universe/1f446.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f446.svg rename to smileys/Universe/1f446.svg diff --git a/smileys/TwitterEmojiSVG/1f447.svg b/smileys/Universe/1f447.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f447.svg rename to smileys/Universe/1f447.svg diff --git a/smileys/TwitterEmojiSVG/1f448.svg b/smileys/Universe/1f448.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f448.svg rename to smileys/Universe/1f448.svg diff --git a/smileys/TwitterEmojiSVG/1f449.svg b/smileys/Universe/1f449.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f449.svg rename to smileys/Universe/1f449.svg diff --git a/smileys/TwitterEmojiSVG/1f44a.svg b/smileys/Universe/1f44a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f44a.svg rename to smileys/Universe/1f44a.svg diff --git a/smileys/TwitterEmojiSVG/1f44b.svg b/smileys/Universe/1f44b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f44b.svg rename to smileys/Universe/1f44b.svg diff --git a/smileys/TwitterEmojiSVG/1f44c.svg b/smileys/Universe/1f44c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f44c.svg rename to smileys/Universe/1f44c.svg diff --git a/smileys/TwitterEmojiSVG/1f44d.svg b/smileys/Universe/1f44d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f44d.svg rename to smileys/Universe/1f44d.svg diff --git a/smileys/TwitterEmojiSVG/1f44e.svg b/smileys/Universe/1f44e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f44e.svg rename to smileys/Universe/1f44e.svg diff --git a/smileys/TwitterEmojiSVG/1f44f.svg b/smileys/Universe/1f44f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f44f.svg rename to smileys/Universe/1f44f.svg diff --git a/smileys/TwitterEmojiSVG/1f450.svg b/smileys/Universe/1f450.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f450.svg rename to smileys/Universe/1f450.svg diff --git a/smileys/TwitterEmojiSVG/1f451.svg b/smileys/Universe/1f451.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f451.svg rename to smileys/Universe/1f451.svg diff --git a/smileys/TwitterEmojiSVG/1f452.svg b/smileys/Universe/1f452.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f452.svg rename to smileys/Universe/1f452.svg diff --git a/smileys/TwitterEmojiSVG/1f453.svg b/smileys/Universe/1f453.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f453.svg rename to smileys/Universe/1f453.svg diff --git a/smileys/TwitterEmojiSVG/1f454.svg b/smileys/Universe/1f454.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f454.svg rename to smileys/Universe/1f454.svg diff --git a/smileys/TwitterEmojiSVG/1f455.svg b/smileys/Universe/1f455.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f455.svg rename to smileys/Universe/1f455.svg diff --git a/smileys/TwitterEmojiSVG/1f456.svg b/smileys/Universe/1f456.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f456.svg rename to smileys/Universe/1f456.svg diff --git a/smileys/TwitterEmojiSVG/1f457.svg b/smileys/Universe/1f457.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f457.svg rename to smileys/Universe/1f457.svg diff --git a/smileys/TwitterEmojiSVG/1f458.svg b/smileys/Universe/1f458.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f458.svg rename to smileys/Universe/1f458.svg diff --git a/smileys/TwitterEmojiSVG/1f459.svg b/smileys/Universe/1f459.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f459.svg rename to smileys/Universe/1f459.svg diff --git a/smileys/TwitterEmojiSVG/1f45a.svg b/smileys/Universe/1f45a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f45a.svg rename to smileys/Universe/1f45a.svg diff --git a/smileys/TwitterEmojiSVG/1f45b.svg b/smileys/Universe/1f45b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f45b.svg rename to smileys/Universe/1f45b.svg diff --git a/smileys/TwitterEmojiSVG/1f45c.svg b/smileys/Universe/1f45c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f45c.svg rename to smileys/Universe/1f45c.svg diff --git a/smileys/TwitterEmojiSVG/1f45d.svg b/smileys/Universe/1f45d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f45d.svg rename to smileys/Universe/1f45d.svg diff --git a/smileys/TwitterEmojiSVG/1f45e.svg b/smileys/Universe/1f45e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f45e.svg rename to smileys/Universe/1f45e.svg diff --git a/smileys/TwitterEmojiSVG/1f45f.svg b/smileys/Universe/1f45f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f45f.svg rename to smileys/Universe/1f45f.svg diff --git a/smileys/TwitterEmojiSVG/1f460.svg b/smileys/Universe/1f460.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f460.svg rename to smileys/Universe/1f460.svg diff --git a/smileys/TwitterEmojiSVG/1f461.svg b/smileys/Universe/1f461.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f461.svg rename to smileys/Universe/1f461.svg diff --git a/smileys/TwitterEmojiSVG/1f462.svg b/smileys/Universe/1f462.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f462.svg rename to smileys/Universe/1f462.svg diff --git a/smileys/TwitterEmojiSVG/1f463.svg b/smileys/Universe/1f463.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f463.svg rename to smileys/Universe/1f463.svg diff --git a/smileys/TwitterEmojiSVG/1f464.svg b/smileys/Universe/1f464.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f464.svg rename to smileys/Universe/1f464.svg diff --git a/smileys/TwitterEmojiSVG/1f465.svg b/smileys/Universe/1f465.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f465.svg rename to smileys/Universe/1f465.svg diff --git a/smileys/TwitterEmojiSVG/1f466.svg b/smileys/Universe/1f466.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f466.svg rename to smileys/Universe/1f466.svg diff --git a/smileys/TwitterEmojiSVG/1f467.svg b/smileys/Universe/1f467.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f467.svg rename to smileys/Universe/1f467.svg diff --git a/smileys/TwitterEmojiSVG/1f468.svg b/smileys/Universe/1f468.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f468.svg rename to smileys/Universe/1f468.svg diff --git a/smileys/TwitterEmojiSVG/1f469.svg b/smileys/Universe/1f469.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f469.svg rename to smileys/Universe/1f469.svg diff --git a/smileys/TwitterEmojiSVG/1f46a.svg b/smileys/Universe/1f46a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f46a.svg rename to smileys/Universe/1f46a.svg diff --git a/smileys/TwitterEmojiSVG/1f46b.svg b/smileys/Universe/1f46b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f46b.svg rename to smileys/Universe/1f46b.svg diff --git a/smileys/TwitterEmojiSVG/1f46c.svg b/smileys/Universe/1f46c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f46c.svg rename to smileys/Universe/1f46c.svg diff --git a/smileys/TwitterEmojiSVG/1f46d.svg b/smileys/Universe/1f46d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f46d.svg rename to smileys/Universe/1f46d.svg diff --git a/smileys/TwitterEmojiSVG/1f46e.svg b/smileys/Universe/1f46e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f46e.svg rename to smileys/Universe/1f46e.svg diff --git a/smileys/TwitterEmojiSVG/1f46f.svg b/smileys/Universe/1f46f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f46f.svg rename to smileys/Universe/1f46f.svg diff --git a/smileys/TwitterEmojiSVG/1f470.svg b/smileys/Universe/1f470.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f470.svg rename to smileys/Universe/1f470.svg diff --git a/smileys/TwitterEmojiSVG/1f471.svg b/smileys/Universe/1f471.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f471.svg rename to smileys/Universe/1f471.svg diff --git a/smileys/TwitterEmojiSVG/1f472.svg b/smileys/Universe/1f472.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f472.svg rename to smileys/Universe/1f472.svg diff --git a/smileys/TwitterEmojiSVG/1f473.svg b/smileys/Universe/1f473.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f473.svg rename to smileys/Universe/1f473.svg diff --git a/smileys/TwitterEmojiSVG/1f474.svg b/smileys/Universe/1f474.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f474.svg rename to smileys/Universe/1f474.svg diff --git a/smileys/TwitterEmojiSVG/1f475.svg b/smileys/Universe/1f475.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f475.svg rename to smileys/Universe/1f475.svg diff --git a/smileys/TwitterEmojiSVG/1f476.svg b/smileys/Universe/1f476.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f476.svg rename to smileys/Universe/1f476.svg diff --git a/smileys/TwitterEmojiSVG/1f477.svg b/smileys/Universe/1f477.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f477.svg rename to smileys/Universe/1f477.svg diff --git a/smileys/TwitterEmojiSVG/1f478.svg b/smileys/Universe/1f478.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f478.svg rename to smileys/Universe/1f478.svg diff --git a/smileys/TwitterEmojiSVG/1f479.svg b/smileys/Universe/1f479.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f479.svg rename to smileys/Universe/1f479.svg diff --git a/smileys/TwitterEmojiSVG/1f47a.svg b/smileys/Universe/1f47a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f47a.svg rename to smileys/Universe/1f47a.svg diff --git a/smileys/TwitterEmojiSVG/1f47b.svg b/smileys/Universe/1f47b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f47b.svg rename to smileys/Universe/1f47b.svg diff --git a/smileys/TwitterEmojiSVG/1f47c.svg b/smileys/Universe/1f47c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f47c.svg rename to smileys/Universe/1f47c.svg diff --git a/smileys/TwitterEmojiSVG/1f47d.svg b/smileys/Universe/1f47d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f47d.svg rename to smileys/Universe/1f47d.svg diff --git a/smileys/TwitterEmojiSVG/1f47e.svg b/smileys/Universe/1f47e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f47e.svg rename to smileys/Universe/1f47e.svg diff --git a/smileys/TwitterEmojiSVG/1f47f.svg b/smileys/Universe/1f47f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f47f.svg rename to smileys/Universe/1f47f.svg diff --git a/smileys/TwitterEmojiSVG/1f480.svg b/smileys/Universe/1f480.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f480.svg rename to smileys/Universe/1f480.svg diff --git a/smileys/TwitterEmojiSVG/1f481.svg b/smileys/Universe/1f481.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f481.svg rename to smileys/Universe/1f481.svg diff --git a/smileys/TwitterEmojiSVG/1f482.svg b/smileys/Universe/1f482.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f482.svg rename to smileys/Universe/1f482.svg diff --git a/smileys/TwitterEmojiSVG/1f483.svg b/smileys/Universe/1f483.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f483.svg rename to smileys/Universe/1f483.svg diff --git a/smileys/TwitterEmojiSVG/1f484.svg b/smileys/Universe/1f484.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f484.svg rename to smileys/Universe/1f484.svg diff --git a/smileys/TwitterEmojiSVG/1f485.svg b/smileys/Universe/1f485.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f485.svg rename to smileys/Universe/1f485.svg diff --git a/smileys/TwitterEmojiSVG/1f486.svg b/smileys/Universe/1f486.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f486.svg rename to smileys/Universe/1f486.svg diff --git a/smileys/TwitterEmojiSVG/1f487.svg b/smileys/Universe/1f487.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f487.svg rename to smileys/Universe/1f487.svg diff --git a/smileys/TwitterEmojiSVG/1f488.svg b/smileys/Universe/1f488.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f488.svg rename to smileys/Universe/1f488.svg diff --git a/smileys/TwitterEmojiSVG/1f489.svg b/smileys/Universe/1f489.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f489.svg rename to smileys/Universe/1f489.svg diff --git a/smileys/TwitterEmojiSVG/1f48a.svg b/smileys/Universe/1f48a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f48a.svg rename to smileys/Universe/1f48a.svg diff --git a/smileys/TwitterEmojiSVG/1f48b.svg b/smileys/Universe/1f48b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f48b.svg rename to smileys/Universe/1f48b.svg diff --git a/smileys/TwitterEmojiSVG/1f48c.svg b/smileys/Universe/1f48c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f48c.svg rename to smileys/Universe/1f48c.svg diff --git a/smileys/TwitterEmojiSVG/1f48d.svg b/smileys/Universe/1f48d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f48d.svg rename to smileys/Universe/1f48d.svg diff --git a/smileys/TwitterEmojiSVG/1f48e.svg b/smileys/Universe/1f48e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f48e.svg rename to smileys/Universe/1f48e.svg diff --git a/smileys/TwitterEmojiSVG/1f48f.svg b/smileys/Universe/1f48f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f48f.svg rename to smileys/Universe/1f48f.svg diff --git a/smileys/TwitterEmojiSVG/1f490.svg b/smileys/Universe/1f490.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f490.svg rename to smileys/Universe/1f490.svg diff --git a/smileys/TwitterEmojiSVG/1f491.svg b/smileys/Universe/1f491.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f491.svg rename to smileys/Universe/1f491.svg diff --git a/smileys/TwitterEmojiSVG/1f492.svg b/smileys/Universe/1f492.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f492.svg rename to smileys/Universe/1f492.svg diff --git a/smileys/TwitterEmojiSVG/1f493.svg b/smileys/Universe/1f493.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f493.svg rename to smileys/Universe/1f493.svg diff --git a/smileys/TwitterEmojiSVG/1f494.svg b/smileys/Universe/1f494.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f494.svg rename to smileys/Universe/1f494.svg diff --git a/smileys/TwitterEmojiSVG/1f495.svg b/smileys/Universe/1f495.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f495.svg rename to smileys/Universe/1f495.svg diff --git a/smileys/TwitterEmojiSVG/1f496.svg b/smileys/Universe/1f496.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f496.svg rename to smileys/Universe/1f496.svg diff --git a/smileys/TwitterEmojiSVG/1f497.svg b/smileys/Universe/1f497.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f497.svg rename to smileys/Universe/1f497.svg diff --git a/smileys/TwitterEmojiSVG/1f498.svg b/smileys/Universe/1f498.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f498.svg rename to smileys/Universe/1f498.svg diff --git a/smileys/TwitterEmojiSVG/1f499.svg b/smileys/Universe/1f499.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f499.svg rename to smileys/Universe/1f499.svg diff --git a/smileys/TwitterEmojiSVG/1f49a.svg b/smileys/Universe/1f49a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f49a.svg rename to smileys/Universe/1f49a.svg diff --git a/smileys/TwitterEmojiSVG/1f49b.svg b/smileys/Universe/1f49b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f49b.svg rename to smileys/Universe/1f49b.svg diff --git a/smileys/TwitterEmojiSVG/1f49c.svg b/smileys/Universe/1f49c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f49c.svg rename to smileys/Universe/1f49c.svg diff --git a/smileys/TwitterEmojiSVG/1f49d.svg b/smileys/Universe/1f49d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f49d.svg rename to smileys/Universe/1f49d.svg diff --git a/smileys/TwitterEmojiSVG/1f49e.svg b/smileys/Universe/1f49e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f49e.svg rename to smileys/Universe/1f49e.svg diff --git a/smileys/TwitterEmojiSVG/1f49f.svg b/smileys/Universe/1f49f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f49f.svg rename to smileys/Universe/1f49f.svg diff --git a/smileys/TwitterEmojiSVG/1f4a0.svg b/smileys/Universe/1f4a0.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4a0.svg rename to smileys/Universe/1f4a0.svg diff --git a/smileys/TwitterEmojiSVG/1f4a1.svg b/smileys/Universe/1f4a1.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4a1.svg rename to smileys/Universe/1f4a1.svg diff --git a/smileys/TwitterEmojiSVG/1f4a2.svg b/smileys/Universe/1f4a2.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4a2.svg rename to smileys/Universe/1f4a2.svg diff --git a/smileys/TwitterEmojiSVG/1f4a3.svg b/smileys/Universe/1f4a3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4a3.svg rename to smileys/Universe/1f4a3.svg diff --git a/smileys/TwitterEmojiSVG/1f4a4.svg b/smileys/Universe/1f4a4.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4a4.svg rename to smileys/Universe/1f4a4.svg diff --git a/smileys/TwitterEmojiSVG/1f4a5.svg b/smileys/Universe/1f4a5.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4a5.svg rename to smileys/Universe/1f4a5.svg diff --git a/smileys/TwitterEmojiSVG/1f4a6.svg b/smileys/Universe/1f4a6.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4a6.svg rename to smileys/Universe/1f4a6.svg diff --git a/smileys/TwitterEmojiSVG/1f4a7.svg b/smileys/Universe/1f4a7.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4a7.svg rename to smileys/Universe/1f4a7.svg diff --git a/smileys/TwitterEmojiSVG/1f4a8.svg b/smileys/Universe/1f4a8.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4a8.svg rename to smileys/Universe/1f4a8.svg diff --git a/smileys/TwitterEmojiSVG/1f4a9.svg b/smileys/Universe/1f4a9.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4a9.svg rename to smileys/Universe/1f4a9.svg diff --git a/smileys/TwitterEmojiSVG/1f4aa.svg b/smileys/Universe/1f4aa.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4aa.svg rename to smileys/Universe/1f4aa.svg diff --git a/smileys/TwitterEmojiSVG/1f4ab.svg b/smileys/Universe/1f4ab.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4ab.svg rename to smileys/Universe/1f4ab.svg diff --git a/smileys/TwitterEmojiSVG/1f4ac.svg b/smileys/Universe/1f4ac.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4ac.svg rename to smileys/Universe/1f4ac.svg diff --git a/smileys/TwitterEmojiSVG/1f4ad.svg b/smileys/Universe/1f4ad.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4ad.svg rename to smileys/Universe/1f4ad.svg diff --git a/smileys/TwitterEmojiSVG/1f4ae.svg b/smileys/Universe/1f4ae.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4ae.svg rename to smileys/Universe/1f4ae.svg diff --git a/smileys/TwitterEmojiSVG/1f4af.svg b/smileys/Universe/1f4af.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4af.svg rename to smileys/Universe/1f4af.svg diff --git a/smileys/TwitterEmojiSVG/1f4b0.svg b/smileys/Universe/1f4b0.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4b0.svg rename to smileys/Universe/1f4b0.svg diff --git a/smileys/TwitterEmojiSVG/1f4b1.svg b/smileys/Universe/1f4b1.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4b1.svg rename to smileys/Universe/1f4b1.svg diff --git a/smileys/TwitterEmojiSVG/1f4b2.svg b/smileys/Universe/1f4b2.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4b2.svg rename to smileys/Universe/1f4b2.svg diff --git a/smileys/TwitterEmojiSVG/1f4b3.svg b/smileys/Universe/1f4b3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4b3.svg rename to smileys/Universe/1f4b3.svg diff --git a/smileys/TwitterEmojiSVG/1f4b4.svg b/smileys/Universe/1f4b4.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4b4.svg rename to smileys/Universe/1f4b4.svg diff --git a/smileys/TwitterEmojiSVG/1f4b5.svg b/smileys/Universe/1f4b5.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4b5.svg rename to smileys/Universe/1f4b5.svg diff --git a/smileys/TwitterEmojiSVG/1f4b6.svg b/smileys/Universe/1f4b6.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4b6.svg rename to smileys/Universe/1f4b6.svg diff --git a/smileys/TwitterEmojiSVG/1f4b7.svg b/smileys/Universe/1f4b7.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4b7.svg rename to smileys/Universe/1f4b7.svg diff --git a/smileys/TwitterEmojiSVG/1f4b8.svg b/smileys/Universe/1f4b8.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4b8.svg rename to smileys/Universe/1f4b8.svg diff --git a/smileys/TwitterEmojiSVG/1f4b9.svg b/smileys/Universe/1f4b9.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4b9.svg rename to smileys/Universe/1f4b9.svg diff --git a/smileys/TwitterEmojiSVG/1f4ba.svg b/smileys/Universe/1f4ba.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4ba.svg rename to smileys/Universe/1f4ba.svg diff --git a/smileys/TwitterEmojiSVG/1f4bb.svg b/smileys/Universe/1f4bb.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4bb.svg rename to smileys/Universe/1f4bb.svg diff --git a/smileys/TwitterEmojiSVG/1f4bc.svg b/smileys/Universe/1f4bc.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4bc.svg rename to smileys/Universe/1f4bc.svg diff --git a/smileys/TwitterEmojiSVG/1f4bd.svg b/smileys/Universe/1f4bd.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4bd.svg rename to smileys/Universe/1f4bd.svg diff --git a/smileys/TwitterEmojiSVG/1f4be.svg b/smileys/Universe/1f4be.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4be.svg rename to smileys/Universe/1f4be.svg diff --git a/smileys/TwitterEmojiSVG/1f4bf.svg b/smileys/Universe/1f4bf.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4bf.svg rename to smileys/Universe/1f4bf.svg diff --git a/smileys/TwitterEmojiSVG/1f4c0.svg b/smileys/Universe/1f4c0.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4c0.svg rename to smileys/Universe/1f4c0.svg diff --git a/smileys/TwitterEmojiSVG/1f4c1.svg b/smileys/Universe/1f4c1.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4c1.svg rename to smileys/Universe/1f4c1.svg diff --git a/smileys/TwitterEmojiSVG/1f4c2.svg b/smileys/Universe/1f4c2.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4c2.svg rename to smileys/Universe/1f4c2.svg diff --git a/smileys/TwitterEmojiSVG/1f4c3.svg b/smileys/Universe/1f4c3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4c3.svg rename to smileys/Universe/1f4c3.svg diff --git a/smileys/TwitterEmojiSVG/1f4c4.svg b/smileys/Universe/1f4c4.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4c4.svg rename to smileys/Universe/1f4c4.svg diff --git a/smileys/TwitterEmojiSVG/1f4c5.svg b/smileys/Universe/1f4c5.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4c5.svg rename to smileys/Universe/1f4c5.svg diff --git a/smileys/TwitterEmojiSVG/1f4c6.svg b/smileys/Universe/1f4c6.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4c6.svg rename to smileys/Universe/1f4c6.svg diff --git a/smileys/TwitterEmojiSVG/1f4c7.svg b/smileys/Universe/1f4c7.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4c7.svg rename to smileys/Universe/1f4c7.svg diff --git a/smileys/TwitterEmojiSVG/1f4c8.svg b/smileys/Universe/1f4c8.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4c8.svg rename to smileys/Universe/1f4c8.svg diff --git a/smileys/TwitterEmojiSVG/1f4c9.svg b/smileys/Universe/1f4c9.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4c9.svg rename to smileys/Universe/1f4c9.svg diff --git a/smileys/TwitterEmojiSVG/1f4ca.svg b/smileys/Universe/1f4ca.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4ca.svg rename to smileys/Universe/1f4ca.svg diff --git a/smileys/TwitterEmojiSVG/1f4cb.svg b/smileys/Universe/1f4cb.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4cb.svg rename to smileys/Universe/1f4cb.svg diff --git a/smileys/TwitterEmojiSVG/1f4cc.svg b/smileys/Universe/1f4cc.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4cc.svg rename to smileys/Universe/1f4cc.svg diff --git a/smileys/TwitterEmojiSVG/1f4cd.svg b/smileys/Universe/1f4cd.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4cd.svg rename to smileys/Universe/1f4cd.svg diff --git a/smileys/TwitterEmojiSVG/1f4ce.svg b/smileys/Universe/1f4ce.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4ce.svg rename to smileys/Universe/1f4ce.svg diff --git a/smileys/TwitterEmojiSVG/1f4cf.svg b/smileys/Universe/1f4cf.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4cf.svg rename to smileys/Universe/1f4cf.svg diff --git a/smileys/TwitterEmojiSVG/1f4d0.svg b/smileys/Universe/1f4d0.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4d0.svg rename to smileys/Universe/1f4d0.svg diff --git a/smileys/TwitterEmojiSVG/1f4d1.svg b/smileys/Universe/1f4d1.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4d1.svg rename to smileys/Universe/1f4d1.svg diff --git a/smileys/TwitterEmojiSVG/1f4d2.svg b/smileys/Universe/1f4d2.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4d2.svg rename to smileys/Universe/1f4d2.svg diff --git a/smileys/TwitterEmojiSVG/1f4d3.svg b/smileys/Universe/1f4d3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4d3.svg rename to smileys/Universe/1f4d3.svg diff --git a/smileys/TwitterEmojiSVG/1f4d4.svg b/smileys/Universe/1f4d4.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4d4.svg rename to smileys/Universe/1f4d4.svg diff --git a/smileys/TwitterEmojiSVG/1f4d5.svg b/smileys/Universe/1f4d5.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4d5.svg rename to smileys/Universe/1f4d5.svg diff --git a/smileys/TwitterEmojiSVG/1f4d6.svg b/smileys/Universe/1f4d6.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4d6.svg rename to smileys/Universe/1f4d6.svg diff --git a/smileys/TwitterEmojiSVG/1f4d7.svg b/smileys/Universe/1f4d7.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4d7.svg rename to smileys/Universe/1f4d7.svg diff --git a/smileys/TwitterEmojiSVG/1f4d8.svg b/smileys/Universe/1f4d8.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4d8.svg rename to smileys/Universe/1f4d8.svg diff --git a/smileys/TwitterEmojiSVG/1f4d9.svg b/smileys/Universe/1f4d9.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4d9.svg rename to smileys/Universe/1f4d9.svg diff --git a/smileys/TwitterEmojiSVG/1f4da.svg b/smileys/Universe/1f4da.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4da.svg rename to smileys/Universe/1f4da.svg diff --git a/smileys/TwitterEmojiSVG/1f4db.svg b/smileys/Universe/1f4db.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4db.svg rename to smileys/Universe/1f4db.svg diff --git a/smileys/TwitterEmojiSVG/1f4dc.svg b/smileys/Universe/1f4dc.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4dc.svg rename to smileys/Universe/1f4dc.svg diff --git a/smileys/TwitterEmojiSVG/1f4dd.svg b/smileys/Universe/1f4dd.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4dd.svg rename to smileys/Universe/1f4dd.svg diff --git a/smileys/TwitterEmojiSVG/1f4de.svg b/smileys/Universe/1f4de.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4de.svg rename to smileys/Universe/1f4de.svg diff --git a/smileys/TwitterEmojiSVG/1f4df.svg b/smileys/Universe/1f4df.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4df.svg rename to smileys/Universe/1f4df.svg diff --git a/smileys/TwitterEmojiSVG/1f4e0.svg b/smileys/Universe/1f4e0.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4e0.svg rename to smileys/Universe/1f4e0.svg diff --git a/smileys/TwitterEmojiSVG/1f4e1.svg b/smileys/Universe/1f4e1.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4e1.svg rename to smileys/Universe/1f4e1.svg diff --git a/smileys/TwitterEmojiSVG/1f4e2.svg b/smileys/Universe/1f4e2.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4e2.svg rename to smileys/Universe/1f4e2.svg diff --git a/smileys/TwitterEmojiSVG/1f4e3.svg b/smileys/Universe/1f4e3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4e3.svg rename to smileys/Universe/1f4e3.svg diff --git a/smileys/TwitterEmojiSVG/1f4e4.svg b/smileys/Universe/1f4e4.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4e4.svg rename to smileys/Universe/1f4e4.svg diff --git a/smileys/TwitterEmojiSVG/1f4e5.svg b/smileys/Universe/1f4e5.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4e5.svg rename to smileys/Universe/1f4e5.svg diff --git a/smileys/TwitterEmojiSVG/1f4e6.svg b/smileys/Universe/1f4e6.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4e6.svg rename to smileys/Universe/1f4e6.svg diff --git a/smileys/TwitterEmojiSVG/1f4e7.svg b/smileys/Universe/1f4e7.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4e7.svg rename to smileys/Universe/1f4e7.svg diff --git a/smileys/TwitterEmojiSVG/1f4e8.svg b/smileys/Universe/1f4e8.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4e8.svg rename to smileys/Universe/1f4e8.svg diff --git a/smileys/TwitterEmojiSVG/1f4e9.svg b/smileys/Universe/1f4e9.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4e9.svg rename to smileys/Universe/1f4e9.svg diff --git a/smileys/TwitterEmojiSVG/1f4ea.svg b/smileys/Universe/1f4ea.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4ea.svg rename to smileys/Universe/1f4ea.svg diff --git a/smileys/TwitterEmojiSVG/1f4eb.svg b/smileys/Universe/1f4eb.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4eb.svg rename to smileys/Universe/1f4eb.svg diff --git a/smileys/TwitterEmojiSVG/1f4ec.svg b/smileys/Universe/1f4ec.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4ec.svg rename to smileys/Universe/1f4ec.svg diff --git a/smileys/TwitterEmojiSVG/1f4ed.svg b/smileys/Universe/1f4ed.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4ed.svg rename to smileys/Universe/1f4ed.svg diff --git a/smileys/TwitterEmojiSVG/1f4ee.svg b/smileys/Universe/1f4ee.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4ee.svg rename to smileys/Universe/1f4ee.svg diff --git a/smileys/TwitterEmojiSVG/1f4ef.svg b/smileys/Universe/1f4ef.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4ef.svg rename to smileys/Universe/1f4ef.svg diff --git a/smileys/TwitterEmojiSVG/1f4f0.svg b/smileys/Universe/1f4f0.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4f0.svg rename to smileys/Universe/1f4f0.svg diff --git a/smileys/TwitterEmojiSVG/1f4f1.svg b/smileys/Universe/1f4f1.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4f1.svg rename to smileys/Universe/1f4f1.svg diff --git a/smileys/TwitterEmojiSVG/1f4f2.svg b/smileys/Universe/1f4f2.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4f2.svg rename to smileys/Universe/1f4f2.svg diff --git a/smileys/TwitterEmojiSVG/1f4f3.svg b/smileys/Universe/1f4f3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4f3.svg rename to smileys/Universe/1f4f3.svg diff --git a/smileys/TwitterEmojiSVG/1f4f4.svg b/smileys/Universe/1f4f4.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4f4.svg rename to smileys/Universe/1f4f4.svg diff --git a/smileys/TwitterEmojiSVG/1f4f5.svg b/smileys/Universe/1f4f5.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4f5.svg rename to smileys/Universe/1f4f5.svg diff --git a/smileys/TwitterEmojiSVG/1f4f6.svg b/smileys/Universe/1f4f6.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4f6.svg rename to smileys/Universe/1f4f6.svg diff --git a/smileys/TwitterEmojiSVG/1f4f7.svg b/smileys/Universe/1f4f7.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4f7.svg rename to smileys/Universe/1f4f7.svg diff --git a/smileys/TwitterEmojiSVG/1f4f9.svg b/smileys/Universe/1f4f9.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4f9.svg rename to smileys/Universe/1f4f9.svg diff --git a/smileys/TwitterEmojiSVG/1f4fa.svg b/smileys/Universe/1f4fa.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4fa.svg rename to smileys/Universe/1f4fa.svg diff --git a/smileys/TwitterEmojiSVG/1f4fb.svg b/smileys/Universe/1f4fb.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4fb.svg rename to smileys/Universe/1f4fb.svg diff --git a/smileys/TwitterEmojiSVG/1f4fc.svg b/smileys/Universe/1f4fc.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f4fc.svg rename to smileys/Universe/1f4fc.svg diff --git a/smileys/TwitterEmojiSVG/1f500.svg b/smileys/Universe/1f500.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f500.svg rename to smileys/Universe/1f500.svg diff --git a/smileys/TwitterEmojiSVG/1f501.svg b/smileys/Universe/1f501.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f501.svg rename to smileys/Universe/1f501.svg diff --git a/smileys/TwitterEmojiSVG/1f502.svg b/smileys/Universe/1f502.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f502.svg rename to smileys/Universe/1f502.svg diff --git a/smileys/TwitterEmojiSVG/1f503.svg b/smileys/Universe/1f503.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f503.svg rename to smileys/Universe/1f503.svg diff --git a/smileys/TwitterEmojiSVG/1f504.svg b/smileys/Universe/1f504.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f504.svg rename to smileys/Universe/1f504.svg diff --git a/smileys/TwitterEmojiSVG/1f505.svg b/smileys/Universe/1f505.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f505.svg rename to smileys/Universe/1f505.svg diff --git a/smileys/TwitterEmojiSVG/1f506.svg b/smileys/Universe/1f506.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f506.svg rename to smileys/Universe/1f506.svg diff --git a/smileys/TwitterEmojiSVG/1f507.svg b/smileys/Universe/1f507.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f507.svg rename to smileys/Universe/1f507.svg diff --git a/smileys/TwitterEmojiSVG/1f508.svg b/smileys/Universe/1f508.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f508.svg rename to smileys/Universe/1f508.svg diff --git a/smileys/TwitterEmojiSVG/1f509.svg b/smileys/Universe/1f509.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f509.svg rename to smileys/Universe/1f509.svg diff --git a/smileys/TwitterEmojiSVG/1f50a.svg b/smileys/Universe/1f50a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f50a.svg rename to smileys/Universe/1f50a.svg diff --git a/smileys/TwitterEmojiSVG/1f50b.svg b/smileys/Universe/1f50b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f50b.svg rename to smileys/Universe/1f50b.svg diff --git a/smileys/TwitterEmojiSVG/1f50c.svg b/smileys/Universe/1f50c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f50c.svg rename to smileys/Universe/1f50c.svg diff --git a/smileys/TwitterEmojiSVG/1f50d.svg b/smileys/Universe/1f50d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f50d.svg rename to smileys/Universe/1f50d.svg diff --git a/smileys/TwitterEmojiSVG/1f50e.svg b/smileys/Universe/1f50e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f50e.svg rename to smileys/Universe/1f50e.svg diff --git a/smileys/TwitterEmojiSVG/1f50f.svg b/smileys/Universe/1f50f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f50f.svg rename to smileys/Universe/1f50f.svg diff --git a/smileys/TwitterEmojiSVG/1f510.svg b/smileys/Universe/1f510.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f510.svg rename to smileys/Universe/1f510.svg diff --git a/smileys/TwitterEmojiSVG/1f511.svg b/smileys/Universe/1f511.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f511.svg rename to smileys/Universe/1f511.svg diff --git a/smileys/TwitterEmojiSVG/1f512.svg b/smileys/Universe/1f512.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f512.svg rename to smileys/Universe/1f512.svg diff --git a/smileys/TwitterEmojiSVG/1f513.svg b/smileys/Universe/1f513.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f513.svg rename to smileys/Universe/1f513.svg diff --git a/smileys/TwitterEmojiSVG/1f514.svg b/smileys/Universe/1f514.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f514.svg rename to smileys/Universe/1f514.svg diff --git a/smileys/TwitterEmojiSVG/1f515.svg b/smileys/Universe/1f515.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f515.svg rename to smileys/Universe/1f515.svg diff --git a/smileys/TwitterEmojiSVG/1f516.svg b/smileys/Universe/1f516.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f516.svg rename to smileys/Universe/1f516.svg diff --git a/smileys/TwitterEmojiSVG/1f517.svg b/smileys/Universe/1f517.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f517.svg rename to smileys/Universe/1f517.svg diff --git a/smileys/TwitterEmojiSVG/1f518.svg b/smileys/Universe/1f518.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f518.svg rename to smileys/Universe/1f518.svg diff --git a/smileys/TwitterEmojiSVG/1f519.svg b/smileys/Universe/1f519.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f519.svg rename to smileys/Universe/1f519.svg diff --git a/smileys/TwitterEmojiSVG/1f51a.svg b/smileys/Universe/1f51a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f51a.svg rename to smileys/Universe/1f51a.svg diff --git a/smileys/TwitterEmojiSVG/1f51b.svg b/smileys/Universe/1f51b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f51b.svg rename to smileys/Universe/1f51b.svg diff --git a/smileys/TwitterEmojiSVG/1f51c.svg b/smileys/Universe/1f51c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f51c.svg rename to smileys/Universe/1f51c.svg diff --git a/smileys/TwitterEmojiSVG/1f51d.svg b/smileys/Universe/1f51d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f51d.svg rename to smileys/Universe/1f51d.svg diff --git a/smileys/TwitterEmojiSVG/1f51e.svg b/smileys/Universe/1f51e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f51e.svg rename to smileys/Universe/1f51e.svg diff --git a/smileys/TwitterEmojiSVG/1f51f.svg b/smileys/Universe/1f51f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f51f.svg rename to smileys/Universe/1f51f.svg diff --git a/smileys/TwitterEmojiSVG/1f520.svg b/smileys/Universe/1f520.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f520.svg rename to smileys/Universe/1f520.svg diff --git a/smileys/TwitterEmojiSVG/1f521.svg b/smileys/Universe/1f521.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f521.svg rename to smileys/Universe/1f521.svg diff --git a/smileys/TwitterEmojiSVG/1f522.svg b/smileys/Universe/1f522.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f522.svg rename to smileys/Universe/1f522.svg diff --git a/smileys/TwitterEmojiSVG/1f523.svg b/smileys/Universe/1f523.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f523.svg rename to smileys/Universe/1f523.svg diff --git a/smileys/TwitterEmojiSVG/1f524.svg b/smileys/Universe/1f524.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f524.svg rename to smileys/Universe/1f524.svg diff --git a/smileys/TwitterEmojiSVG/1f525.svg b/smileys/Universe/1f525.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f525.svg rename to smileys/Universe/1f525.svg diff --git a/smileys/TwitterEmojiSVG/1f526.svg b/smileys/Universe/1f526.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f526.svg rename to smileys/Universe/1f526.svg diff --git a/smileys/TwitterEmojiSVG/1f527.svg b/smileys/Universe/1f527.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f527.svg rename to smileys/Universe/1f527.svg diff --git a/smileys/TwitterEmojiSVG/1f528.svg b/smileys/Universe/1f528.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f528.svg rename to smileys/Universe/1f528.svg diff --git a/smileys/TwitterEmojiSVG/1f529.svg b/smileys/Universe/1f529.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f529.svg rename to smileys/Universe/1f529.svg diff --git a/smileys/TwitterEmojiSVG/1f52a.svg b/smileys/Universe/1f52a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f52a.svg rename to smileys/Universe/1f52a.svg diff --git a/smileys/TwitterEmojiSVG/1f52b.svg b/smileys/Universe/1f52b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f52b.svg rename to smileys/Universe/1f52b.svg diff --git a/smileys/TwitterEmojiSVG/1f52c.svg b/smileys/Universe/1f52c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f52c.svg rename to smileys/Universe/1f52c.svg diff --git a/smileys/TwitterEmojiSVG/1f52d.svg b/smileys/Universe/1f52d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f52d.svg rename to smileys/Universe/1f52d.svg diff --git a/smileys/TwitterEmojiSVG/1f52e.svg b/smileys/Universe/1f52e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f52e.svg rename to smileys/Universe/1f52e.svg diff --git a/smileys/TwitterEmojiSVG/1f52f.svg b/smileys/Universe/1f52f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f52f.svg rename to smileys/Universe/1f52f.svg diff --git a/smileys/TwitterEmojiSVG/1f530.svg b/smileys/Universe/1f530.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f530.svg rename to smileys/Universe/1f530.svg diff --git a/smileys/TwitterEmojiSVG/1f531.svg b/smileys/Universe/1f531.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f531.svg rename to smileys/Universe/1f531.svg diff --git a/smileys/TwitterEmojiSVG/1f532.svg b/smileys/Universe/1f532.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f532.svg rename to smileys/Universe/1f532.svg diff --git a/smileys/TwitterEmojiSVG/1f533.svg b/smileys/Universe/1f533.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f533.svg rename to smileys/Universe/1f533.svg diff --git a/smileys/TwitterEmojiSVG/1f534.svg b/smileys/Universe/1f534.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f534.svg rename to smileys/Universe/1f534.svg diff --git a/smileys/TwitterEmojiSVG/1f535.svg b/smileys/Universe/1f535.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f535.svg rename to smileys/Universe/1f535.svg diff --git a/smileys/TwitterEmojiSVG/1f536.svg b/smileys/Universe/1f536.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f536.svg rename to smileys/Universe/1f536.svg diff --git a/smileys/TwitterEmojiSVG/1f537.svg b/smileys/Universe/1f537.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f537.svg rename to smileys/Universe/1f537.svg diff --git a/smileys/TwitterEmojiSVG/1f538.svg b/smileys/Universe/1f538.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f538.svg rename to smileys/Universe/1f538.svg diff --git a/smileys/TwitterEmojiSVG/1f539.svg b/smileys/Universe/1f539.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f539.svg rename to smileys/Universe/1f539.svg diff --git a/smileys/TwitterEmojiSVG/1f53a.svg b/smileys/Universe/1f53a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f53a.svg rename to smileys/Universe/1f53a.svg diff --git a/smileys/TwitterEmojiSVG/1f53b.svg b/smileys/Universe/1f53b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f53b.svg rename to smileys/Universe/1f53b.svg diff --git a/smileys/TwitterEmojiSVG/1f53c.svg b/smileys/Universe/1f53c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f53c.svg rename to smileys/Universe/1f53c.svg diff --git a/smileys/TwitterEmojiSVG/1f53d.svg b/smileys/Universe/1f53d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f53d.svg rename to smileys/Universe/1f53d.svg diff --git a/smileys/TwitterEmojiSVG/1f550.svg b/smileys/Universe/1f550.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f550.svg rename to smileys/Universe/1f550.svg diff --git a/smileys/TwitterEmojiSVG/1f551.svg b/smileys/Universe/1f551.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f551.svg rename to smileys/Universe/1f551.svg diff --git a/smileys/TwitterEmojiSVG/1f552.svg b/smileys/Universe/1f552.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f552.svg rename to smileys/Universe/1f552.svg diff --git a/smileys/TwitterEmojiSVG/1f553.svg b/smileys/Universe/1f553.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f553.svg rename to smileys/Universe/1f553.svg diff --git a/smileys/TwitterEmojiSVG/1f554.svg b/smileys/Universe/1f554.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f554.svg rename to smileys/Universe/1f554.svg diff --git a/smileys/TwitterEmojiSVG/1f555.svg b/smileys/Universe/1f555.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f555.svg rename to smileys/Universe/1f555.svg diff --git a/smileys/TwitterEmojiSVG/1f556.svg b/smileys/Universe/1f556.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f556.svg rename to smileys/Universe/1f556.svg diff --git a/smileys/TwitterEmojiSVG/1f557.svg b/smileys/Universe/1f557.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f557.svg rename to smileys/Universe/1f557.svg diff --git a/smileys/TwitterEmojiSVG/1f558.svg b/smileys/Universe/1f558.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f558.svg rename to smileys/Universe/1f558.svg diff --git a/smileys/TwitterEmojiSVG/1f559.svg b/smileys/Universe/1f559.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f559.svg rename to smileys/Universe/1f559.svg diff --git a/smileys/TwitterEmojiSVG/1f55a.svg b/smileys/Universe/1f55a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f55a.svg rename to smileys/Universe/1f55a.svg diff --git a/smileys/TwitterEmojiSVG/1f55b.svg b/smileys/Universe/1f55b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f55b.svg rename to smileys/Universe/1f55b.svg diff --git a/smileys/TwitterEmojiSVG/1f55c.svg b/smileys/Universe/1f55c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f55c.svg rename to smileys/Universe/1f55c.svg diff --git a/smileys/TwitterEmojiSVG/1f55d.svg b/smileys/Universe/1f55d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f55d.svg rename to smileys/Universe/1f55d.svg diff --git a/smileys/TwitterEmojiSVG/1f55e.svg b/smileys/Universe/1f55e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f55e.svg rename to smileys/Universe/1f55e.svg diff --git a/smileys/TwitterEmojiSVG/1f55f.svg b/smileys/Universe/1f55f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f55f.svg rename to smileys/Universe/1f55f.svg diff --git a/smileys/TwitterEmojiSVG/1f560.svg b/smileys/Universe/1f560.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f560.svg rename to smileys/Universe/1f560.svg diff --git a/smileys/TwitterEmojiSVG/1f561.svg b/smileys/Universe/1f561.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f561.svg rename to smileys/Universe/1f561.svg diff --git a/smileys/TwitterEmojiSVG/1f562.svg b/smileys/Universe/1f562.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f562.svg rename to smileys/Universe/1f562.svg diff --git a/smileys/TwitterEmojiSVG/1f563.svg b/smileys/Universe/1f563.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f563.svg rename to smileys/Universe/1f563.svg diff --git a/smileys/TwitterEmojiSVG/1f564.svg b/smileys/Universe/1f564.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f564.svg rename to smileys/Universe/1f564.svg diff --git a/smileys/TwitterEmojiSVG/1f565.svg b/smileys/Universe/1f565.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f565.svg rename to smileys/Universe/1f565.svg diff --git a/smileys/TwitterEmojiSVG/1f566.svg b/smileys/Universe/1f566.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f566.svg rename to smileys/Universe/1f566.svg diff --git a/smileys/TwitterEmojiSVG/1f567.svg b/smileys/Universe/1f567.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f567.svg rename to smileys/Universe/1f567.svg diff --git a/smileys/TwitterEmojiSVG/1f595.svg b/smileys/Universe/1f595.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f595.svg rename to smileys/Universe/1f595.svg diff --git a/smileys/TwitterEmojiSVG/1f5fb.svg b/smileys/Universe/1f5fb.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f5fb.svg rename to smileys/Universe/1f5fb.svg diff --git a/smileys/TwitterEmojiSVG/1f5fc.svg b/smileys/Universe/1f5fc.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f5fc.svg rename to smileys/Universe/1f5fc.svg diff --git a/smileys/TwitterEmojiSVG/1f5fd.svg b/smileys/Universe/1f5fd.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f5fd.svg rename to smileys/Universe/1f5fd.svg diff --git a/smileys/TwitterEmojiSVG/1f5fe.svg b/smileys/Universe/1f5fe.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f5fe.svg rename to smileys/Universe/1f5fe.svg diff --git a/smileys/TwitterEmojiSVG/1f5ff.svg b/smileys/Universe/1f5ff.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f5ff.svg rename to smileys/Universe/1f5ff.svg diff --git a/smileys/TwitterEmojiSVG/1f600.svg b/smileys/Universe/1f600.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f600.svg rename to smileys/Universe/1f600.svg diff --git a/smileys/TwitterEmojiSVG/1f601.svg b/smileys/Universe/1f601.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f601.svg rename to smileys/Universe/1f601.svg diff --git a/smileys/TwitterEmojiSVG/1f602.svg b/smileys/Universe/1f602.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f602.svg rename to smileys/Universe/1f602.svg diff --git a/smileys/TwitterEmojiSVG/1f603.svg b/smileys/Universe/1f603.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f603.svg rename to smileys/Universe/1f603.svg diff --git a/smileys/TwitterEmojiSVG/1f604.svg b/smileys/Universe/1f604.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f604.svg rename to smileys/Universe/1f604.svg diff --git a/smileys/TwitterEmojiSVG/1f605.svg b/smileys/Universe/1f605.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f605.svg rename to smileys/Universe/1f605.svg diff --git a/smileys/TwitterEmojiSVG/1f606.svg b/smileys/Universe/1f606.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f606.svg rename to smileys/Universe/1f606.svg diff --git a/smileys/TwitterEmojiSVG/1f607.svg b/smileys/Universe/1f607.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f607.svg rename to smileys/Universe/1f607.svg diff --git a/smileys/TwitterEmojiSVG/1f608.svg b/smileys/Universe/1f608.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f608.svg rename to smileys/Universe/1f608.svg diff --git a/smileys/TwitterEmojiSVG/1f609.svg b/smileys/Universe/1f609.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f609.svg rename to smileys/Universe/1f609.svg diff --git a/smileys/TwitterEmojiSVG/1f60a.svg b/smileys/Universe/1f60a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f60a.svg rename to smileys/Universe/1f60a.svg diff --git a/smileys/TwitterEmojiSVG/1f60b.svg b/smileys/Universe/1f60b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f60b.svg rename to smileys/Universe/1f60b.svg diff --git a/smileys/TwitterEmojiSVG/1f60c.svg b/smileys/Universe/1f60c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f60c.svg rename to smileys/Universe/1f60c.svg diff --git a/smileys/TwitterEmojiSVG/1f60d.svg b/smileys/Universe/1f60d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f60d.svg rename to smileys/Universe/1f60d.svg diff --git a/smileys/TwitterEmojiSVG/1f60e.svg b/smileys/Universe/1f60e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f60e.svg rename to smileys/Universe/1f60e.svg diff --git a/smileys/TwitterEmojiSVG/1f60f.svg b/smileys/Universe/1f60f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f60f.svg rename to smileys/Universe/1f60f.svg diff --git a/smileys/TwitterEmojiSVG/1f610.svg b/smileys/Universe/1f610.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f610.svg rename to smileys/Universe/1f610.svg diff --git a/smileys/TwitterEmojiSVG/1f611.svg b/smileys/Universe/1f611.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f611.svg rename to smileys/Universe/1f611.svg diff --git a/smileys/TwitterEmojiSVG/1f612.svg b/smileys/Universe/1f612.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f612.svg rename to smileys/Universe/1f612.svg diff --git a/smileys/TwitterEmojiSVG/1f613.svg b/smileys/Universe/1f613.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f613.svg rename to smileys/Universe/1f613.svg diff --git a/smileys/TwitterEmojiSVG/1f614.svg b/smileys/Universe/1f614.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f614.svg rename to smileys/Universe/1f614.svg diff --git a/smileys/TwitterEmojiSVG/1f615.svg b/smileys/Universe/1f615.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f615.svg rename to smileys/Universe/1f615.svg diff --git a/smileys/TwitterEmojiSVG/1f616.svg b/smileys/Universe/1f616.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f616.svg rename to smileys/Universe/1f616.svg diff --git a/smileys/TwitterEmojiSVG/1f617.svg b/smileys/Universe/1f617.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f617.svg rename to smileys/Universe/1f617.svg diff --git a/smileys/TwitterEmojiSVG/1f618.svg b/smileys/Universe/1f618.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f618.svg rename to smileys/Universe/1f618.svg diff --git a/smileys/TwitterEmojiSVG/1f619.svg b/smileys/Universe/1f619.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f619.svg rename to smileys/Universe/1f619.svg diff --git a/smileys/TwitterEmojiSVG/1f61a.svg b/smileys/Universe/1f61a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f61a.svg rename to smileys/Universe/1f61a.svg diff --git a/smileys/TwitterEmojiSVG/1f61b.svg b/smileys/Universe/1f61b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f61b.svg rename to smileys/Universe/1f61b.svg diff --git a/smileys/TwitterEmojiSVG/1f61c.svg b/smileys/Universe/1f61c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f61c.svg rename to smileys/Universe/1f61c.svg diff --git a/smileys/TwitterEmojiSVG/1f61d.svg b/smileys/Universe/1f61d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f61d.svg rename to smileys/Universe/1f61d.svg diff --git a/smileys/TwitterEmojiSVG/1f61e.svg b/smileys/Universe/1f61e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f61e.svg rename to smileys/Universe/1f61e.svg diff --git a/smileys/TwitterEmojiSVG/1f61f.svg b/smileys/Universe/1f61f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f61f.svg rename to smileys/Universe/1f61f.svg diff --git a/smileys/TwitterEmojiSVG/1f620.svg b/smileys/Universe/1f620.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f620.svg rename to smileys/Universe/1f620.svg diff --git a/smileys/TwitterEmojiSVG/1f621.svg b/smileys/Universe/1f621.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f621.svg rename to smileys/Universe/1f621.svg diff --git a/smileys/TwitterEmojiSVG/1f622.svg b/smileys/Universe/1f622.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f622.svg rename to smileys/Universe/1f622.svg diff --git a/smileys/TwitterEmojiSVG/1f623.svg b/smileys/Universe/1f623.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f623.svg rename to smileys/Universe/1f623.svg diff --git a/smileys/TwitterEmojiSVG/1f624.svg b/smileys/Universe/1f624.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f624.svg rename to smileys/Universe/1f624.svg diff --git a/smileys/TwitterEmojiSVG/1f625.svg b/smileys/Universe/1f625.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f625.svg rename to smileys/Universe/1f625.svg diff --git a/smileys/TwitterEmojiSVG/1f626.svg b/smileys/Universe/1f626.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f626.svg rename to smileys/Universe/1f626.svg diff --git a/smileys/TwitterEmojiSVG/1f627.svg b/smileys/Universe/1f627.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f627.svg rename to smileys/Universe/1f627.svg diff --git a/smileys/TwitterEmojiSVG/1f628.svg b/smileys/Universe/1f628.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f628.svg rename to smileys/Universe/1f628.svg diff --git a/smileys/TwitterEmojiSVG/1f629.svg b/smileys/Universe/1f629.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f629.svg rename to smileys/Universe/1f629.svg diff --git a/smileys/TwitterEmojiSVG/1f62a.svg b/smileys/Universe/1f62a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f62a.svg rename to smileys/Universe/1f62a.svg diff --git a/smileys/TwitterEmojiSVG/1f62b.svg b/smileys/Universe/1f62b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f62b.svg rename to smileys/Universe/1f62b.svg diff --git a/smileys/TwitterEmojiSVG/1f62c.svg b/smileys/Universe/1f62c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f62c.svg rename to smileys/Universe/1f62c.svg diff --git a/smileys/TwitterEmojiSVG/1f62d.svg b/smileys/Universe/1f62d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f62d.svg rename to smileys/Universe/1f62d.svg diff --git a/smileys/TwitterEmojiSVG/1f62e.svg b/smileys/Universe/1f62e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f62e.svg rename to smileys/Universe/1f62e.svg diff --git a/smileys/TwitterEmojiSVG/1f62f.svg b/smileys/Universe/1f62f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f62f.svg rename to smileys/Universe/1f62f.svg diff --git a/smileys/TwitterEmojiSVG/1f630.svg b/smileys/Universe/1f630.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f630.svg rename to smileys/Universe/1f630.svg diff --git a/smileys/TwitterEmojiSVG/1f631.svg b/smileys/Universe/1f631.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f631.svg rename to smileys/Universe/1f631.svg diff --git a/smileys/TwitterEmojiSVG/1f632.svg b/smileys/Universe/1f632.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f632.svg rename to smileys/Universe/1f632.svg diff --git a/smileys/TwitterEmojiSVG/1f633.svg b/smileys/Universe/1f633.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f633.svg rename to smileys/Universe/1f633.svg diff --git a/smileys/TwitterEmojiSVG/1f634.svg b/smileys/Universe/1f634.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f634.svg rename to smileys/Universe/1f634.svg diff --git a/smileys/TwitterEmojiSVG/1f635.svg b/smileys/Universe/1f635.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f635.svg rename to smileys/Universe/1f635.svg diff --git a/smileys/TwitterEmojiSVG/1f636.svg b/smileys/Universe/1f636.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f636.svg rename to smileys/Universe/1f636.svg diff --git a/smileys/TwitterEmojiSVG/1f637.svg b/smileys/Universe/1f637.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f637.svg rename to smileys/Universe/1f637.svg diff --git a/smileys/TwitterEmojiSVG/1f638.svg b/smileys/Universe/1f638.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f638.svg rename to smileys/Universe/1f638.svg diff --git a/smileys/TwitterEmojiSVG/1f639.svg b/smileys/Universe/1f639.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f639.svg rename to smileys/Universe/1f639.svg diff --git a/smileys/TwitterEmojiSVG/1f63a.svg b/smileys/Universe/1f63a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f63a.svg rename to smileys/Universe/1f63a.svg diff --git a/smileys/TwitterEmojiSVG/1f63b.svg b/smileys/Universe/1f63b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f63b.svg rename to smileys/Universe/1f63b.svg diff --git a/smileys/TwitterEmojiSVG/1f63c.svg b/smileys/Universe/1f63c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f63c.svg rename to smileys/Universe/1f63c.svg diff --git a/smileys/TwitterEmojiSVG/1f63d.svg b/smileys/Universe/1f63d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f63d.svg rename to smileys/Universe/1f63d.svg diff --git a/smileys/TwitterEmojiSVG/1f63e.svg b/smileys/Universe/1f63e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f63e.svg rename to smileys/Universe/1f63e.svg diff --git a/smileys/TwitterEmojiSVG/1f63f.svg b/smileys/Universe/1f63f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f63f.svg rename to smileys/Universe/1f63f.svg diff --git a/smileys/TwitterEmojiSVG/1f640.svg b/smileys/Universe/1f640.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f640.svg rename to smileys/Universe/1f640.svg diff --git a/smileys/TwitterEmojiSVG/1f645.svg b/smileys/Universe/1f645.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f645.svg rename to smileys/Universe/1f645.svg diff --git a/smileys/TwitterEmojiSVG/1f646.svg b/smileys/Universe/1f646.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f646.svg rename to smileys/Universe/1f646.svg diff --git a/smileys/TwitterEmojiSVG/1f647.svg b/smileys/Universe/1f647.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f647.svg rename to smileys/Universe/1f647.svg diff --git a/smileys/TwitterEmojiSVG/1f648.svg b/smileys/Universe/1f648.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f648.svg rename to smileys/Universe/1f648.svg diff --git a/smileys/TwitterEmojiSVG/1f649.svg b/smileys/Universe/1f649.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f649.svg rename to smileys/Universe/1f649.svg diff --git a/smileys/TwitterEmojiSVG/1f64a.svg b/smileys/Universe/1f64a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f64a.svg rename to smileys/Universe/1f64a.svg diff --git a/smileys/TwitterEmojiSVG/1f64b.svg b/smileys/Universe/1f64b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f64b.svg rename to smileys/Universe/1f64b.svg diff --git a/smileys/TwitterEmojiSVG/1f64c.svg b/smileys/Universe/1f64c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f64c.svg rename to smileys/Universe/1f64c.svg diff --git a/smileys/TwitterEmojiSVG/1f64d.svg b/smileys/Universe/1f64d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f64d.svg rename to smileys/Universe/1f64d.svg diff --git a/smileys/TwitterEmojiSVG/1f64e.svg b/smileys/Universe/1f64e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f64e.svg rename to smileys/Universe/1f64e.svg diff --git a/smileys/TwitterEmojiSVG/1f64f.svg b/smileys/Universe/1f64f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f64f.svg rename to smileys/Universe/1f64f.svg diff --git a/smileys/TwitterEmojiSVG/1f680.svg b/smileys/Universe/1f680.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f680.svg rename to smileys/Universe/1f680.svg diff --git a/smileys/TwitterEmojiSVG/1f681.svg b/smileys/Universe/1f681.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f681.svg rename to smileys/Universe/1f681.svg diff --git a/smileys/TwitterEmojiSVG/1f682.svg b/smileys/Universe/1f682.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f682.svg rename to smileys/Universe/1f682.svg diff --git a/smileys/TwitterEmojiSVG/1f683.svg b/smileys/Universe/1f683.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f683.svg rename to smileys/Universe/1f683.svg diff --git a/smileys/TwitterEmojiSVG/1f684.svg b/smileys/Universe/1f684.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f684.svg rename to smileys/Universe/1f684.svg diff --git a/smileys/TwitterEmojiSVG/1f685.svg b/smileys/Universe/1f685.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f685.svg rename to smileys/Universe/1f685.svg diff --git a/smileys/TwitterEmojiSVG/1f686.svg b/smileys/Universe/1f686.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f686.svg rename to smileys/Universe/1f686.svg diff --git a/smileys/TwitterEmojiSVG/1f687.svg b/smileys/Universe/1f687.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f687.svg rename to smileys/Universe/1f687.svg diff --git a/smileys/TwitterEmojiSVG/1f688.svg b/smileys/Universe/1f688.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f688.svg rename to smileys/Universe/1f688.svg diff --git a/smileys/TwitterEmojiSVG/1f689.svg b/smileys/Universe/1f689.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f689.svg rename to smileys/Universe/1f689.svg diff --git a/smileys/TwitterEmojiSVG/1f68a.svg b/smileys/Universe/1f68a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f68a.svg rename to smileys/Universe/1f68a.svg diff --git a/smileys/TwitterEmojiSVG/1f68b.svg b/smileys/Universe/1f68b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f68b.svg rename to smileys/Universe/1f68b.svg diff --git a/smileys/TwitterEmojiSVG/1f68c.svg b/smileys/Universe/1f68c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f68c.svg rename to smileys/Universe/1f68c.svg diff --git a/smileys/TwitterEmojiSVG/1f68d.svg b/smileys/Universe/1f68d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f68d.svg rename to smileys/Universe/1f68d.svg diff --git a/smileys/TwitterEmojiSVG/1f68e.svg b/smileys/Universe/1f68e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f68e.svg rename to smileys/Universe/1f68e.svg diff --git a/smileys/TwitterEmojiSVG/1f68f.svg b/smileys/Universe/1f68f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f68f.svg rename to smileys/Universe/1f68f.svg diff --git a/smileys/TwitterEmojiSVG/1f690.svg b/smileys/Universe/1f690.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f690.svg rename to smileys/Universe/1f690.svg diff --git a/smileys/TwitterEmojiSVG/1f691.svg b/smileys/Universe/1f691.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f691.svg rename to smileys/Universe/1f691.svg diff --git a/smileys/TwitterEmojiSVG/1f692.svg b/smileys/Universe/1f692.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f692.svg rename to smileys/Universe/1f692.svg diff --git a/smileys/TwitterEmojiSVG/1f693.svg b/smileys/Universe/1f693.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f693.svg rename to smileys/Universe/1f693.svg diff --git a/smileys/TwitterEmojiSVG/1f694.svg b/smileys/Universe/1f694.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f694.svg rename to smileys/Universe/1f694.svg diff --git a/smileys/TwitterEmojiSVG/1f695.svg b/smileys/Universe/1f695.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f695.svg rename to smileys/Universe/1f695.svg diff --git a/smileys/TwitterEmojiSVG/1f696.svg b/smileys/Universe/1f696.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f696.svg rename to smileys/Universe/1f696.svg diff --git a/smileys/TwitterEmojiSVG/1f697.svg b/smileys/Universe/1f697.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f697.svg rename to smileys/Universe/1f697.svg diff --git a/smileys/TwitterEmojiSVG/1f698.svg b/smileys/Universe/1f698.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f698.svg rename to smileys/Universe/1f698.svg diff --git a/smileys/TwitterEmojiSVG/1f699.svg b/smileys/Universe/1f699.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f699.svg rename to smileys/Universe/1f699.svg diff --git a/smileys/TwitterEmojiSVG/1f69a.svg b/smileys/Universe/1f69a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f69a.svg rename to smileys/Universe/1f69a.svg diff --git a/smileys/TwitterEmojiSVG/1f69b.svg b/smileys/Universe/1f69b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f69b.svg rename to smileys/Universe/1f69b.svg diff --git a/smileys/TwitterEmojiSVG/1f69c.svg b/smileys/Universe/1f69c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f69c.svg rename to smileys/Universe/1f69c.svg diff --git a/smileys/TwitterEmojiSVG/1f69d.svg b/smileys/Universe/1f69d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f69d.svg rename to smileys/Universe/1f69d.svg diff --git a/smileys/TwitterEmojiSVG/1f69e.svg b/smileys/Universe/1f69e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f69e.svg rename to smileys/Universe/1f69e.svg diff --git a/smileys/TwitterEmojiSVG/1f69f.svg b/smileys/Universe/1f69f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f69f.svg rename to smileys/Universe/1f69f.svg diff --git a/smileys/TwitterEmojiSVG/1f6a0.svg b/smileys/Universe/1f6a0.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6a0.svg rename to smileys/Universe/1f6a0.svg diff --git a/smileys/TwitterEmojiSVG/1f6a1.svg b/smileys/Universe/1f6a1.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6a1.svg rename to smileys/Universe/1f6a1.svg diff --git a/smileys/TwitterEmojiSVG/1f6a2.svg b/smileys/Universe/1f6a2.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6a2.svg rename to smileys/Universe/1f6a2.svg diff --git a/smileys/TwitterEmojiSVG/1f6a3.svg b/smileys/Universe/1f6a3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6a3.svg rename to smileys/Universe/1f6a3.svg diff --git a/smileys/TwitterEmojiSVG/1f6a4.svg b/smileys/Universe/1f6a4.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6a4.svg rename to smileys/Universe/1f6a4.svg diff --git a/smileys/TwitterEmojiSVG/1f6a5.svg b/smileys/Universe/1f6a5.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6a5.svg rename to smileys/Universe/1f6a5.svg diff --git a/smileys/TwitterEmojiSVG/1f6a6.svg b/smileys/Universe/1f6a6.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6a6.svg rename to smileys/Universe/1f6a6.svg diff --git a/smileys/TwitterEmojiSVG/1f6a7.svg b/smileys/Universe/1f6a7.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6a7.svg rename to smileys/Universe/1f6a7.svg diff --git a/smileys/TwitterEmojiSVG/1f6a8.svg b/smileys/Universe/1f6a8.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6a8.svg rename to smileys/Universe/1f6a8.svg diff --git a/smileys/TwitterEmojiSVG/1f6a9.svg b/smileys/Universe/1f6a9.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6a9.svg rename to smileys/Universe/1f6a9.svg diff --git a/smileys/TwitterEmojiSVG/1f6aa.svg b/smileys/Universe/1f6aa.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6aa.svg rename to smileys/Universe/1f6aa.svg diff --git a/smileys/TwitterEmojiSVG/1f6ab.svg b/smileys/Universe/1f6ab.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6ab.svg rename to smileys/Universe/1f6ab.svg diff --git a/smileys/TwitterEmojiSVG/1f6ac.svg b/smileys/Universe/1f6ac.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6ac.svg rename to smileys/Universe/1f6ac.svg diff --git a/smileys/TwitterEmojiSVG/1f6ad.svg b/smileys/Universe/1f6ad.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6ad.svg rename to smileys/Universe/1f6ad.svg diff --git a/smileys/TwitterEmojiSVG/1f6ae.svg b/smileys/Universe/1f6ae.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6ae.svg rename to smileys/Universe/1f6ae.svg diff --git a/smileys/TwitterEmojiSVG/1f6af.svg b/smileys/Universe/1f6af.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6af.svg rename to smileys/Universe/1f6af.svg diff --git a/smileys/TwitterEmojiSVG/1f6b0.svg b/smileys/Universe/1f6b0.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6b0.svg rename to smileys/Universe/1f6b0.svg diff --git a/smileys/TwitterEmojiSVG/1f6b1.svg b/smileys/Universe/1f6b1.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6b1.svg rename to smileys/Universe/1f6b1.svg diff --git a/smileys/TwitterEmojiSVG/1f6b2.svg b/smileys/Universe/1f6b2.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6b2.svg rename to smileys/Universe/1f6b2.svg diff --git a/smileys/TwitterEmojiSVG/1f6b3.svg b/smileys/Universe/1f6b3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6b3.svg rename to smileys/Universe/1f6b3.svg diff --git a/smileys/TwitterEmojiSVG/1f6b4.svg b/smileys/Universe/1f6b4.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6b4.svg rename to smileys/Universe/1f6b4.svg diff --git a/smileys/TwitterEmojiSVG/1f6b5.svg b/smileys/Universe/1f6b5.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6b5.svg rename to smileys/Universe/1f6b5.svg diff --git a/smileys/TwitterEmojiSVG/1f6b6.svg b/smileys/Universe/1f6b6.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6b6.svg rename to smileys/Universe/1f6b6.svg diff --git a/smileys/TwitterEmojiSVG/1f6b7.svg b/smileys/Universe/1f6b7.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6b7.svg rename to smileys/Universe/1f6b7.svg diff --git a/smileys/TwitterEmojiSVG/1f6b8.svg b/smileys/Universe/1f6b8.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6b8.svg rename to smileys/Universe/1f6b8.svg diff --git a/smileys/TwitterEmojiSVG/1f6b9.svg b/smileys/Universe/1f6b9.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6b9.svg rename to smileys/Universe/1f6b9.svg diff --git a/smileys/TwitterEmojiSVG/1f6ba.svg b/smileys/Universe/1f6ba.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6ba.svg rename to smileys/Universe/1f6ba.svg diff --git a/smileys/TwitterEmojiSVG/1f6bb.svg b/smileys/Universe/1f6bb.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6bb.svg rename to smileys/Universe/1f6bb.svg diff --git a/smileys/TwitterEmojiSVG/1f6bc.svg b/smileys/Universe/1f6bc.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6bc.svg rename to smileys/Universe/1f6bc.svg diff --git a/smileys/TwitterEmojiSVG/1f6bd.svg b/smileys/Universe/1f6bd.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6bd.svg rename to smileys/Universe/1f6bd.svg diff --git a/smileys/TwitterEmojiSVG/1f6be.svg b/smileys/Universe/1f6be.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6be.svg rename to smileys/Universe/1f6be.svg diff --git a/smileys/TwitterEmojiSVG/1f6bf.svg b/smileys/Universe/1f6bf.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6bf.svg rename to smileys/Universe/1f6bf.svg diff --git a/smileys/TwitterEmojiSVG/1f6c0.svg b/smileys/Universe/1f6c0.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6c0.svg rename to smileys/Universe/1f6c0.svg diff --git a/smileys/TwitterEmojiSVG/1f6c1.svg b/smileys/Universe/1f6c1.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6c1.svg rename to smileys/Universe/1f6c1.svg diff --git a/smileys/TwitterEmojiSVG/1f6c2.svg b/smileys/Universe/1f6c2.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6c2.svg rename to smileys/Universe/1f6c2.svg diff --git a/smileys/TwitterEmojiSVG/1f6c3.svg b/smileys/Universe/1f6c3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6c3.svg rename to smileys/Universe/1f6c3.svg diff --git a/smileys/TwitterEmojiSVG/1f6c4.svg b/smileys/Universe/1f6c4.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6c4.svg rename to smileys/Universe/1f6c4.svg diff --git a/smileys/TwitterEmojiSVG/1f6c5.svg b/smileys/Universe/1f6c5.svg similarity index 100% rename from smileys/TwitterEmojiSVG/1f6c5.svg rename to smileys/Universe/1f6c5.svg diff --git a/smileys/TwitterEmojiSVG/203c.svg b/smileys/Universe/203c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/203c.svg rename to smileys/Universe/203c.svg diff --git a/smileys/TwitterEmojiSVG/2049.svg b/smileys/Universe/2049.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2049.svg rename to smileys/Universe/2049.svg diff --git a/smileys/TwitterEmojiSVG/2122.svg b/smileys/Universe/2122.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2122.svg rename to smileys/Universe/2122.svg diff --git a/smileys/TwitterEmojiSVG/2139.svg b/smileys/Universe/2139.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2139.svg rename to smileys/Universe/2139.svg diff --git a/smileys/TwitterEmojiSVG/2194.svg b/smileys/Universe/2194.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2194.svg rename to smileys/Universe/2194.svg diff --git a/smileys/TwitterEmojiSVG/2195.svg b/smileys/Universe/2195.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2195.svg rename to smileys/Universe/2195.svg diff --git a/smileys/TwitterEmojiSVG/2196.svg b/smileys/Universe/2196.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2196.svg rename to smileys/Universe/2196.svg diff --git a/smileys/TwitterEmojiSVG/2197.svg b/smileys/Universe/2197.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2197.svg rename to smileys/Universe/2197.svg diff --git a/smileys/TwitterEmojiSVG/2198.svg b/smileys/Universe/2198.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2198.svg rename to smileys/Universe/2198.svg diff --git a/smileys/TwitterEmojiSVG/2199.svg b/smileys/Universe/2199.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2199.svg rename to smileys/Universe/2199.svg diff --git a/smileys/TwitterEmojiSVG/21a9.svg b/smileys/Universe/21a9.svg similarity index 100% rename from smileys/TwitterEmojiSVG/21a9.svg rename to smileys/Universe/21a9.svg diff --git a/smileys/TwitterEmojiSVG/21aa.svg b/smileys/Universe/21aa.svg similarity index 100% rename from smileys/TwitterEmojiSVG/21aa.svg rename to smileys/Universe/21aa.svg diff --git a/smileys/TwitterEmojiSVG/23-20e3.svg b/smileys/Universe/23-20e3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/23-20e3.svg rename to smileys/Universe/23-20e3.svg diff --git a/smileys/TwitterEmojiSVG/231a.svg b/smileys/Universe/231a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/231a.svg rename to smileys/Universe/231a.svg diff --git a/smileys/TwitterEmojiSVG/231b.svg b/smileys/Universe/231b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/231b.svg rename to smileys/Universe/231b.svg diff --git a/smileys/TwitterEmojiSVG/23e9.svg b/smileys/Universe/23e9.svg similarity index 100% rename from smileys/TwitterEmojiSVG/23e9.svg rename to smileys/Universe/23e9.svg diff --git a/smileys/TwitterEmojiSVG/23ea.svg b/smileys/Universe/23ea.svg similarity index 100% rename from smileys/TwitterEmojiSVG/23ea.svg rename to smileys/Universe/23ea.svg diff --git a/smileys/TwitterEmojiSVG/23eb.svg b/smileys/Universe/23eb.svg similarity index 100% rename from smileys/TwitterEmojiSVG/23eb.svg rename to smileys/Universe/23eb.svg diff --git a/smileys/TwitterEmojiSVG/23ec.svg b/smileys/Universe/23ec.svg similarity index 100% rename from smileys/TwitterEmojiSVG/23ec.svg rename to smileys/Universe/23ec.svg diff --git a/smileys/TwitterEmojiSVG/23f0.svg b/smileys/Universe/23f0.svg similarity index 100% rename from smileys/TwitterEmojiSVG/23f0.svg rename to smileys/Universe/23f0.svg diff --git a/smileys/TwitterEmojiSVG/23f3.svg b/smileys/Universe/23f3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/23f3.svg rename to smileys/Universe/23f3.svg diff --git a/smileys/TwitterEmojiSVG/24c2.svg b/smileys/Universe/24c2.svg similarity index 100% rename from smileys/TwitterEmojiSVG/24c2.svg rename to smileys/Universe/24c2.svg diff --git a/smileys/TwitterEmojiSVG/25aa.svg b/smileys/Universe/25aa.svg similarity index 100% rename from smileys/TwitterEmojiSVG/25aa.svg rename to smileys/Universe/25aa.svg diff --git a/smileys/TwitterEmojiSVG/25ab.svg b/smileys/Universe/25ab.svg similarity index 100% rename from smileys/TwitterEmojiSVG/25ab.svg rename to smileys/Universe/25ab.svg diff --git a/smileys/TwitterEmojiSVG/25b6.svg b/smileys/Universe/25b6.svg similarity index 100% rename from smileys/TwitterEmojiSVG/25b6.svg rename to smileys/Universe/25b6.svg diff --git a/smileys/TwitterEmojiSVG/25c0.svg b/smileys/Universe/25c0.svg similarity index 100% rename from smileys/TwitterEmojiSVG/25c0.svg rename to smileys/Universe/25c0.svg diff --git a/smileys/TwitterEmojiSVG/25fb.svg b/smileys/Universe/25fb.svg similarity index 100% rename from smileys/TwitterEmojiSVG/25fb.svg rename to smileys/Universe/25fb.svg diff --git a/smileys/TwitterEmojiSVG/25fc.svg b/smileys/Universe/25fc.svg similarity index 100% rename from smileys/TwitterEmojiSVG/25fc.svg rename to smileys/Universe/25fc.svg diff --git a/smileys/TwitterEmojiSVG/25fd.svg b/smileys/Universe/25fd.svg similarity index 100% rename from smileys/TwitterEmojiSVG/25fd.svg rename to smileys/Universe/25fd.svg diff --git a/smileys/TwitterEmojiSVG/25fe.svg b/smileys/Universe/25fe.svg similarity index 100% rename from smileys/TwitterEmojiSVG/25fe.svg rename to smileys/Universe/25fe.svg diff --git a/smileys/TwitterEmojiSVG/2600.svg b/smileys/Universe/2600.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2600.svg rename to smileys/Universe/2600.svg diff --git a/smileys/TwitterEmojiSVG/2601.svg b/smileys/Universe/2601.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2601.svg rename to smileys/Universe/2601.svg diff --git a/smileys/TwitterEmojiSVG/260e.svg b/smileys/Universe/260e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/260e.svg rename to smileys/Universe/260e.svg diff --git a/smileys/TwitterEmojiSVG/2611.svg b/smileys/Universe/2611.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2611.svg rename to smileys/Universe/2611.svg diff --git a/smileys/TwitterEmojiSVG/2614.svg b/smileys/Universe/2614.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2614.svg rename to smileys/Universe/2614.svg diff --git a/smileys/TwitterEmojiSVG/2615.svg b/smileys/Universe/2615.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2615.svg rename to smileys/Universe/2615.svg diff --git a/smileys/TwitterEmojiSVG/261d.svg b/smileys/Universe/261d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/261d.svg rename to smileys/Universe/261d.svg diff --git a/smileys/TwitterEmojiSVG/263a.svg b/smileys/Universe/263a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/263a.svg rename to smileys/Universe/263a.svg diff --git a/smileys/TwitterEmojiSVG/2648.svg b/smileys/Universe/2648.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2648.svg rename to smileys/Universe/2648.svg diff --git a/smileys/TwitterEmojiSVG/2649.svg b/smileys/Universe/2649.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2649.svg rename to smileys/Universe/2649.svg diff --git a/smileys/TwitterEmojiSVG/264a.svg b/smileys/Universe/264a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/264a.svg rename to smileys/Universe/264a.svg diff --git a/smileys/TwitterEmojiSVG/264b.svg b/smileys/Universe/264b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/264b.svg rename to smileys/Universe/264b.svg diff --git a/smileys/TwitterEmojiSVG/264c.svg b/smileys/Universe/264c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/264c.svg rename to smileys/Universe/264c.svg diff --git a/smileys/TwitterEmojiSVG/264d.svg b/smileys/Universe/264d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/264d.svg rename to smileys/Universe/264d.svg diff --git a/smileys/TwitterEmojiSVG/264e.svg b/smileys/Universe/264e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/264e.svg rename to smileys/Universe/264e.svg diff --git a/smileys/TwitterEmojiSVG/264f.svg b/smileys/Universe/264f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/264f.svg rename to smileys/Universe/264f.svg diff --git a/smileys/TwitterEmojiSVG/2650.svg b/smileys/Universe/2650.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2650.svg rename to smileys/Universe/2650.svg diff --git a/smileys/TwitterEmojiSVG/2651.svg b/smileys/Universe/2651.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2651.svg rename to smileys/Universe/2651.svg diff --git a/smileys/TwitterEmojiSVG/2652.svg b/smileys/Universe/2652.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2652.svg rename to smileys/Universe/2652.svg diff --git a/smileys/TwitterEmojiSVG/2653.svg b/smileys/Universe/2653.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2653.svg rename to smileys/Universe/2653.svg diff --git a/smileys/TwitterEmojiSVG/2660.svg b/smileys/Universe/2660.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2660.svg rename to smileys/Universe/2660.svg diff --git a/smileys/TwitterEmojiSVG/2663.svg b/smileys/Universe/2663.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2663.svg rename to smileys/Universe/2663.svg diff --git a/smileys/TwitterEmojiSVG/2665.svg b/smileys/Universe/2665.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2665.svg rename to smileys/Universe/2665.svg diff --git a/smileys/TwitterEmojiSVG/2666.svg b/smileys/Universe/2666.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2666.svg rename to smileys/Universe/2666.svg diff --git a/smileys/TwitterEmojiSVG/2668.svg b/smileys/Universe/2668.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2668.svg rename to smileys/Universe/2668.svg diff --git a/smileys/TwitterEmojiSVG/267b.svg b/smileys/Universe/267b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/267b.svg rename to smileys/Universe/267b.svg diff --git a/smileys/TwitterEmojiSVG/267f.svg b/smileys/Universe/267f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/267f.svg rename to smileys/Universe/267f.svg diff --git a/smileys/TwitterEmojiSVG/2693.svg b/smileys/Universe/2693.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2693.svg rename to smileys/Universe/2693.svg diff --git a/smileys/TwitterEmojiSVG/26a0.svg b/smileys/Universe/26a0.svg similarity index 100% rename from smileys/TwitterEmojiSVG/26a0.svg rename to smileys/Universe/26a0.svg diff --git a/smileys/TwitterEmojiSVG/26a1.svg b/smileys/Universe/26a1.svg similarity index 100% rename from smileys/TwitterEmojiSVG/26a1.svg rename to smileys/Universe/26a1.svg diff --git a/smileys/TwitterEmojiSVG/26aa.svg b/smileys/Universe/26aa.svg similarity index 100% rename from smileys/TwitterEmojiSVG/26aa.svg rename to smileys/Universe/26aa.svg diff --git a/smileys/TwitterEmojiSVG/26ab.svg b/smileys/Universe/26ab.svg similarity index 100% rename from smileys/TwitterEmojiSVG/26ab.svg rename to smileys/Universe/26ab.svg diff --git a/smileys/TwitterEmojiSVG/26bd.svg b/smileys/Universe/26bd.svg similarity index 100% rename from smileys/TwitterEmojiSVG/26bd.svg rename to smileys/Universe/26bd.svg diff --git a/smileys/TwitterEmojiSVG/26be.svg b/smileys/Universe/26be.svg similarity index 100% rename from smileys/TwitterEmojiSVG/26be.svg rename to smileys/Universe/26be.svg diff --git a/smileys/TwitterEmojiSVG/26c4.svg b/smileys/Universe/26c4.svg similarity index 100% rename from smileys/TwitterEmojiSVG/26c4.svg rename to smileys/Universe/26c4.svg diff --git a/smileys/TwitterEmojiSVG/26c5.svg b/smileys/Universe/26c5.svg similarity index 100% rename from smileys/TwitterEmojiSVG/26c5.svg rename to smileys/Universe/26c5.svg diff --git a/smileys/TwitterEmojiSVG/26ce.svg b/smileys/Universe/26ce.svg similarity index 100% rename from smileys/TwitterEmojiSVG/26ce.svg rename to smileys/Universe/26ce.svg diff --git a/smileys/TwitterEmojiSVG/26d4.svg b/smileys/Universe/26d4.svg similarity index 100% rename from smileys/TwitterEmojiSVG/26d4.svg rename to smileys/Universe/26d4.svg diff --git a/smileys/TwitterEmojiSVG/26ea.svg b/smileys/Universe/26ea.svg similarity index 100% rename from smileys/TwitterEmojiSVG/26ea.svg rename to smileys/Universe/26ea.svg diff --git a/smileys/TwitterEmojiSVG/26f2.svg b/smileys/Universe/26f2.svg similarity index 100% rename from smileys/TwitterEmojiSVG/26f2.svg rename to smileys/Universe/26f2.svg diff --git a/smileys/TwitterEmojiSVG/26f3.svg b/smileys/Universe/26f3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/26f3.svg rename to smileys/Universe/26f3.svg diff --git a/smileys/TwitterEmojiSVG/26f5.svg b/smileys/Universe/26f5.svg similarity index 100% rename from smileys/TwitterEmojiSVG/26f5.svg rename to smileys/Universe/26f5.svg diff --git a/smileys/TwitterEmojiSVG/26fa.svg b/smileys/Universe/26fa.svg similarity index 100% rename from smileys/TwitterEmojiSVG/26fa.svg rename to smileys/Universe/26fa.svg diff --git a/smileys/TwitterEmojiSVG/26fd.svg b/smileys/Universe/26fd.svg similarity index 100% rename from smileys/TwitterEmojiSVG/26fd.svg rename to smileys/Universe/26fd.svg diff --git a/smileys/TwitterEmojiSVG/2702.svg b/smileys/Universe/2702.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2702.svg rename to smileys/Universe/2702.svg diff --git a/smileys/TwitterEmojiSVG/2705.svg b/smileys/Universe/2705.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2705.svg rename to smileys/Universe/2705.svg diff --git a/smileys/TwitterEmojiSVG/2708.svg b/smileys/Universe/2708.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2708.svg rename to smileys/Universe/2708.svg diff --git a/smileys/TwitterEmojiSVG/2709.svg b/smileys/Universe/2709.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2709.svg rename to smileys/Universe/2709.svg diff --git a/smileys/TwitterEmojiSVG/270a.svg b/smileys/Universe/270a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/270a.svg rename to smileys/Universe/270a.svg diff --git a/smileys/TwitterEmojiSVG/270b.svg b/smileys/Universe/270b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/270b.svg rename to smileys/Universe/270b.svg diff --git a/smileys/TwitterEmojiSVG/270c.svg b/smileys/Universe/270c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/270c.svg rename to smileys/Universe/270c.svg diff --git a/smileys/TwitterEmojiSVG/270f.svg b/smileys/Universe/270f.svg similarity index 100% rename from smileys/TwitterEmojiSVG/270f.svg rename to smileys/Universe/270f.svg diff --git a/smileys/TwitterEmojiSVG/2712.svg b/smileys/Universe/2712.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2712.svg rename to smileys/Universe/2712.svg diff --git a/smileys/TwitterEmojiSVG/2714.svg b/smileys/Universe/2714.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2714.svg rename to smileys/Universe/2714.svg diff --git a/smileys/TwitterEmojiSVG/2716.svg b/smileys/Universe/2716.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2716.svg rename to smileys/Universe/2716.svg diff --git a/smileys/TwitterEmojiSVG/2728.svg b/smileys/Universe/2728.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2728.svg rename to smileys/Universe/2728.svg diff --git a/smileys/TwitterEmojiSVG/2733.svg b/smileys/Universe/2733.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2733.svg rename to smileys/Universe/2733.svg diff --git a/smileys/TwitterEmojiSVG/2734.svg b/smileys/Universe/2734.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2734.svg rename to smileys/Universe/2734.svg diff --git a/smileys/TwitterEmojiSVG/2744.svg b/smileys/Universe/2744.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2744.svg rename to smileys/Universe/2744.svg diff --git a/smileys/TwitterEmojiSVG/2747.svg b/smileys/Universe/2747.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2747.svg rename to smileys/Universe/2747.svg diff --git a/smileys/TwitterEmojiSVG/274c.svg b/smileys/Universe/274c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/274c.svg rename to smileys/Universe/274c.svg diff --git a/smileys/TwitterEmojiSVG/274e.svg b/smileys/Universe/274e.svg similarity index 100% rename from smileys/TwitterEmojiSVG/274e.svg rename to smileys/Universe/274e.svg diff --git a/smileys/TwitterEmojiSVG/2753.svg b/smileys/Universe/2753.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2753.svg rename to smileys/Universe/2753.svg diff --git a/smileys/TwitterEmojiSVG/2754.svg b/smileys/Universe/2754.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2754.svg rename to smileys/Universe/2754.svg diff --git a/smileys/TwitterEmojiSVG/2755.svg b/smileys/Universe/2755.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2755.svg rename to smileys/Universe/2755.svg diff --git a/smileys/TwitterEmojiSVG/2757.svg b/smileys/Universe/2757.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2757.svg rename to smileys/Universe/2757.svg diff --git a/smileys/TwitterEmojiSVG/2764.svg b/smileys/Universe/2764.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2764.svg rename to smileys/Universe/2764.svg diff --git a/smileys/TwitterEmojiSVG/2795.svg b/smileys/Universe/2795.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2795.svg rename to smileys/Universe/2795.svg diff --git a/smileys/TwitterEmojiSVG/2796.svg b/smileys/Universe/2796.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2796.svg rename to smileys/Universe/2796.svg diff --git a/smileys/TwitterEmojiSVG/2797.svg b/smileys/Universe/2797.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2797.svg rename to smileys/Universe/2797.svg diff --git a/smileys/TwitterEmojiSVG/27a1.svg b/smileys/Universe/27a1.svg similarity index 100% rename from smileys/TwitterEmojiSVG/27a1.svg rename to smileys/Universe/27a1.svg diff --git a/smileys/TwitterEmojiSVG/27b0.svg b/smileys/Universe/27b0.svg similarity index 100% rename from smileys/TwitterEmojiSVG/27b0.svg rename to smileys/Universe/27b0.svg diff --git a/smileys/TwitterEmojiSVG/27bf.svg b/smileys/Universe/27bf.svg similarity index 100% rename from smileys/TwitterEmojiSVG/27bf.svg rename to smileys/Universe/27bf.svg diff --git a/smileys/TwitterEmojiSVG/2934.svg b/smileys/Universe/2934.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2934.svg rename to smileys/Universe/2934.svg diff --git a/smileys/TwitterEmojiSVG/2935.svg b/smileys/Universe/2935.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2935.svg rename to smileys/Universe/2935.svg diff --git a/smileys/TwitterEmojiSVG/2b05.svg b/smileys/Universe/2b05.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2b05.svg rename to smileys/Universe/2b05.svg diff --git a/smileys/TwitterEmojiSVG/2b06.svg b/smileys/Universe/2b06.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2b06.svg rename to smileys/Universe/2b06.svg diff --git a/smileys/TwitterEmojiSVG/2b07.svg b/smileys/Universe/2b07.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2b07.svg rename to smileys/Universe/2b07.svg diff --git a/smileys/TwitterEmojiSVG/2b1b.svg b/smileys/Universe/2b1b.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2b1b.svg rename to smileys/Universe/2b1b.svg diff --git a/smileys/TwitterEmojiSVG/2b1c.svg b/smileys/Universe/2b1c.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2b1c.svg rename to smileys/Universe/2b1c.svg diff --git a/smileys/TwitterEmojiSVG/2b50.svg b/smileys/Universe/2b50.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2b50.svg rename to smileys/Universe/2b50.svg diff --git a/smileys/TwitterEmojiSVG/2b55.svg b/smileys/Universe/2b55.svg similarity index 100% rename from smileys/TwitterEmojiSVG/2b55.svg rename to smileys/Universe/2b55.svg diff --git a/smileys/TwitterEmojiSVG/30-20e3.svg b/smileys/Universe/30-20e3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/30-20e3.svg rename to smileys/Universe/30-20e3.svg diff --git a/smileys/TwitterEmojiSVG/3030.svg b/smileys/Universe/3030.svg similarity index 100% rename from smileys/TwitterEmojiSVG/3030.svg rename to smileys/Universe/3030.svg diff --git a/smileys/TwitterEmojiSVG/303d.svg b/smileys/Universe/303d.svg similarity index 100% rename from smileys/TwitterEmojiSVG/303d.svg rename to smileys/Universe/303d.svg diff --git a/smileys/TwitterEmojiSVG/31-20e3.svg b/smileys/Universe/31-20e3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/31-20e3.svg rename to smileys/Universe/31-20e3.svg diff --git a/smileys/TwitterEmojiSVG/32-20e3.svg b/smileys/Universe/32-20e3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/32-20e3.svg rename to smileys/Universe/32-20e3.svg diff --git a/smileys/TwitterEmojiSVG/3297.svg b/smileys/Universe/3297.svg similarity index 100% rename from smileys/TwitterEmojiSVG/3297.svg rename to smileys/Universe/3297.svg diff --git a/smileys/TwitterEmojiSVG/3299.svg b/smileys/Universe/3299.svg similarity index 100% rename from smileys/TwitterEmojiSVG/3299.svg rename to smileys/Universe/3299.svg diff --git a/smileys/TwitterEmojiSVG/33-20e3.svg b/smileys/Universe/33-20e3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/33-20e3.svg rename to smileys/Universe/33-20e3.svg diff --git a/smileys/TwitterEmojiSVG/34-20e3.svg b/smileys/Universe/34-20e3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/34-20e3.svg rename to smileys/Universe/34-20e3.svg diff --git a/smileys/TwitterEmojiSVG/35-20e3.svg b/smileys/Universe/35-20e3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/35-20e3.svg rename to smileys/Universe/35-20e3.svg diff --git a/smileys/TwitterEmojiSVG/36-20e3.svg b/smileys/Universe/36-20e3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/36-20e3.svg rename to smileys/Universe/36-20e3.svg diff --git a/smileys/TwitterEmojiSVG/37-20e3.svg b/smileys/Universe/37-20e3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/37-20e3.svg rename to smileys/Universe/37-20e3.svg diff --git a/smileys/TwitterEmojiSVG/38-20e3.svg b/smileys/Universe/38-20e3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/38-20e3.svg rename to smileys/Universe/38-20e3.svg diff --git a/smileys/TwitterEmojiSVG/39-20e3.svg b/smileys/Universe/39-20e3.svg similarity index 100% rename from smileys/TwitterEmojiSVG/39-20e3.svg rename to smileys/Universe/39-20e3.svg diff --git a/smileys/TwitterEmojiSVG/LICENSE b/smileys/Universe/LICENSE similarity index 100% rename from smileys/TwitterEmojiSVG/LICENSE rename to smileys/Universe/LICENSE diff --git a/smileys/TwitterEmojiSimple/LICENSE-GRAPHICS b/smileys/Universe/LICENSE-GRAPHICS similarity index 100% rename from smileys/TwitterEmojiSimple/LICENSE-GRAPHICS rename to smileys/Universe/LICENSE-GRAPHICS diff --git a/smileys/TwitterEmojiSimple/README.md b/smileys/Universe/README.md similarity index 100% rename from smileys/TwitterEmojiSimple/README.md rename to smileys/Universe/README.md diff --git a/smileys/TwitterEmojiSVG/a9.svg b/smileys/Universe/a9.svg similarity index 100% rename from smileys/TwitterEmojiSVG/a9.svg rename to smileys/Universe/a9.svg diff --git a/smileys/TwitterEmojiSVG/ae.svg b/smileys/Universe/ae.svg similarity index 100% rename from smileys/TwitterEmojiSVG/ae.svg rename to smileys/Universe/ae.svg diff --git a/smileys/TwitterEmojiSVG/e50a.svg b/smileys/Universe/e50a.svg similarity index 100% rename from smileys/TwitterEmojiSVG/e50a.svg rename to smileys/Universe/e50a.svg diff --git a/smileys/TwitterEmojiSVG/emoticons.xml b/smileys/Universe/emoticons.xml similarity index 100% rename from smileys/TwitterEmojiSVG/emoticons.xml rename to smileys/Universe/emoticons.xml diff --git a/smileys/smileys.qrc b/smileys/smileys.qrc index dece158e0..37389d377 100644 --- a/smileys/smileys.qrc +++ b/smileys/smileys.qrc @@ -1,902 +1,902 @@ - cylgom/angel.png - cylgom/angry.png - cylgom/beer.png - cylgom/bomb.png - cylgom/bored.png - cylgom/cookie.png - cylgom/cool.png - cylgom/crossing.png - cylgom/crying.png - cylgom/devil.png - cylgom/diamond.png - cylgom/doh.png - cylgom/emoticons.xml - cylgom/evil.png - cylgom/eye.png - cylgom/facepalm.png - cylgom/finger.png - cylgom/hacker_terminal.png - cylgom/happysmile.png - cylgom/heart.png - cylgom/hi.png - cylgom/highfive.png - cylgom/hot.png - cylgom/impressed.png - cylgom/inlove.png - cylgom/jealous.png - cylgom/kiss.png - cylgom/lol.png - cylgom/moustache.png - cylgom/MrSmith.png - cylgom/nerd.png - cylgom/nospeak.png - cylgom/oops.png - cylgom/party.png - cylgom/pressed.png - cylgom/rain.png - cylgom/rocknroll.png - cylgom/sad.png - cylgom/shy.png - cylgom/sleeping.png - cylgom/smile.png - cylgom/sniggering.png - cylgom/suspicious.png - cylgom/syringe.png - cylgom/tongue.png - cylgom/toxlocker.png - cylgom/vomit.png - cylgom/wasntme.png - cylgom/whew.png - cylgom/wink.png - cylgom/wondering.png - cylgom/X(.png - cylgom/XD.png - cylgom/XP.png - cylgom/yawn.png - krepa098/angry.png - krepa098/cool.png - krepa098/crying.png - krepa098/emoticons.xml - krepa098/happy.png - krepa098/Kappa.png - krepa098/laugh_closed_eyes.png - krepa098/laugh.png - krepa098/plain.png - krepa098/raw.svg - krepa098/sad.png - krepa098/scared.png - krepa098/smile.png - krepa098/stunned.png - krepa098/tongue.png - krepa098/uncertain.png - krepa098/wink.png - TwitterEmojiSVG/263a.svg - TwitterEmojiSVG/1f600.svg - TwitterEmojiSVG/1f601.svg - TwitterEmojiSVG/1f602.svg - TwitterEmojiSVG/1f603.svg - TwitterEmojiSVG/1f604.svg - TwitterEmojiSVG/1f605.svg - TwitterEmojiSVG/1f606.svg - TwitterEmojiSVG/1f607.svg - TwitterEmojiSVG/1f608.svg - TwitterEmojiSVG/1f609.svg - TwitterEmojiSVG/1f60a.svg - TwitterEmojiSVG/1f60b.svg - TwitterEmojiSVG/1f60c.svg - TwitterEmojiSVG/1f60d.svg - TwitterEmojiSVG/1f60e.svg - TwitterEmojiSVG/1f60f.svg - TwitterEmojiSVG/1f610.svg - TwitterEmojiSVG/1f611.svg - TwitterEmojiSVG/1f612.svg - TwitterEmojiSVG/1f613.svg - TwitterEmojiSVG/1f614.svg - TwitterEmojiSVG/1f615.svg - TwitterEmojiSVG/1f616.svg - TwitterEmojiSVG/1f617.svg - TwitterEmojiSVG/1f618.svg - TwitterEmojiSVG/1f619.svg - TwitterEmojiSVG/1f61a.svg - TwitterEmojiSVG/1f61b.svg - TwitterEmojiSVG/1f61c.svg - TwitterEmojiSVG/1f61d.svg - TwitterEmojiSVG/1f61e.svg - TwitterEmojiSVG/1f61f.svg - TwitterEmojiSVG/1f620.svg - TwitterEmojiSVG/1f621.svg - TwitterEmojiSVG/1f622.svg - TwitterEmojiSVG/1f623.svg - TwitterEmojiSVG/1f624.svg - TwitterEmojiSVG/1f625.svg - TwitterEmojiSVG/1f626.svg - TwitterEmojiSVG/1f627.svg - TwitterEmojiSVG/1f628.svg - TwitterEmojiSVG/1f629.svg - TwitterEmojiSVG/1f62a.svg - TwitterEmojiSVG/1f62b.svg - TwitterEmojiSVG/1f62c.svg - TwitterEmojiSVG/1f62d.svg - TwitterEmojiSVG/1f62e.svg - TwitterEmojiSVG/1f62f.svg - TwitterEmojiSVG/1f630.svg - TwitterEmojiSVG/1f631.svg - TwitterEmojiSVG/1f632.svg - TwitterEmojiSVG/1f633.svg - TwitterEmojiSVG/1f634.svg - TwitterEmojiSVG/1f635.svg - TwitterEmojiSVG/1f636.svg - TwitterEmojiSVG/1f637.svg - TwitterEmojiSVG/1f638.svg - TwitterEmojiSVG/1f639.svg - TwitterEmojiSVG/1f63a.svg - TwitterEmojiSVG/1f63b.svg - TwitterEmojiSVG/1f63c.svg - TwitterEmojiSVG/1f63d.svg - TwitterEmojiSVG/1f63e.svg - TwitterEmojiSVG/1f63f.svg - TwitterEmojiSVG/1f640.svg - TwitterEmojiSVG/1f645.svg - TwitterEmojiSVG/1f646.svg - TwitterEmojiSVG/1f647.svg - TwitterEmojiSVG/1f648.svg - TwitterEmojiSVG/1f649.svg - TwitterEmojiSVG/1f64a.svg - TwitterEmojiSVG/1f64b.svg - TwitterEmojiSVG/1f64c.svg - TwitterEmojiSVG/1f64d.svg - TwitterEmojiSVG/1f64e.svg - TwitterEmojiSVG/1f64f.svg - TwitterEmojiSVG/1f4a9.svg - TwitterEmojiSVG/1f300.svg - TwitterEmojiSVG/1f301.svg - TwitterEmojiSVG/1f302.svg - TwitterEmojiSVG/1f303.svg - TwitterEmojiSVG/1f304.svg - TwitterEmojiSVG/1f305.svg - TwitterEmojiSVG/1f306.svg - TwitterEmojiSVG/1f307.svg - TwitterEmojiSVG/1f308.svg - TwitterEmojiSVG/1f309.svg - TwitterEmojiSVG/1f30a.svg - TwitterEmojiSVG/1f30b.svg - TwitterEmojiSVG/1f30c.svg - TwitterEmojiSVG/1f30d.svg - TwitterEmojiSVG/1f30e.svg - TwitterEmojiSVG/1f30f.svg - TwitterEmojiSVG/1f310.svg - TwitterEmojiSVG/1f311.svg - TwitterEmojiSVG/1f312.svg - TwitterEmojiSVG/1f313.svg - TwitterEmojiSVG/1f314.svg - TwitterEmojiSVG/1f315.svg - TwitterEmojiSVG/1f316.svg - TwitterEmojiSVG/1f317.svg - TwitterEmojiSVG/1f318.svg - TwitterEmojiSVG/1f319.svg - TwitterEmojiSVG/1f31a.svg - TwitterEmojiSVG/1f31b.svg - TwitterEmojiSVG/1f31c.svg - TwitterEmojiSVG/1f31d.svg - TwitterEmojiSVG/1f31e.svg - TwitterEmojiSVG/1f31f.svg - TwitterEmojiSVG/1f320.svg - TwitterEmojiSVG/1f330.svg - TwitterEmojiSVG/1f331.svg - TwitterEmojiSVG/1f332.svg - TwitterEmojiSVG/1f333.svg - TwitterEmojiSVG/1f334.svg - TwitterEmojiSVG/1f335.svg - TwitterEmojiSVG/1f337.svg - TwitterEmojiSVG/1f338.svg - TwitterEmojiSVG/1f339.svg - TwitterEmojiSVG/1f33a.svg - TwitterEmojiSVG/1f33b.svg - TwitterEmojiSVG/1f33c.svg - TwitterEmojiSVG/1f33d.svg - TwitterEmojiSVG/1f33e.svg - TwitterEmojiSVG/1f33f.svg - TwitterEmojiSVG/1f340.svg - TwitterEmojiSVG/1f341.svg - TwitterEmojiSVG/1f342.svg - TwitterEmojiSVG/1f343.svg - TwitterEmojiSVG/1f344.svg - TwitterEmojiSVG/1f345.svg - TwitterEmojiSVG/1f346.svg - TwitterEmojiSVG/1f347.svg - TwitterEmojiSVG/1f348.svg - TwitterEmojiSVG/1f349.svg - TwitterEmojiSVG/1f34a.svg - TwitterEmojiSVG/1f34b.svg - TwitterEmojiSVG/1f34c.svg - TwitterEmojiSVG/1f34d.svg - TwitterEmojiSVG/1f34e.svg - TwitterEmojiSVG/1f34f.svg - TwitterEmojiSVG/1f350.svg - TwitterEmojiSVG/1f351.svg - TwitterEmojiSVG/1f352.svg - TwitterEmojiSVG/1f353.svg - TwitterEmojiSVG/1f354.svg - TwitterEmojiSVG/1f355.svg - TwitterEmojiSVG/1f356.svg - TwitterEmojiSVG/1f357.svg - TwitterEmojiSVG/1f358.svg - TwitterEmojiSVG/1f359.svg - TwitterEmojiSVG/1f35a.svg - TwitterEmojiSVG/1f35b.svg - TwitterEmojiSVG/1f35c.svg - TwitterEmojiSVG/1f35d.svg - TwitterEmojiSVG/1f35e.svg - TwitterEmojiSVG/1f35f.svg - TwitterEmojiSVG/1f360.svg - TwitterEmojiSVG/1f361.svg - TwitterEmojiSVG/1f362.svg - TwitterEmojiSVG/1f363.svg - TwitterEmojiSVG/1f364.svg - TwitterEmojiSVG/1f365.svg - TwitterEmojiSVG/1f366.svg - TwitterEmojiSVG/1f367.svg - TwitterEmojiSVG/1f368.svg - TwitterEmojiSVG/1f369.svg - TwitterEmojiSVG/1f36a.svg - TwitterEmojiSVG/1f36b.svg - TwitterEmojiSVG/1f36c.svg - TwitterEmojiSVG/1f36d.svg - TwitterEmojiSVG/1f36e.svg - TwitterEmojiSVG/1f36f.svg - TwitterEmojiSVG/1f370.svg - TwitterEmojiSVG/1f371.svg - TwitterEmojiSVG/1f372.svg - TwitterEmojiSVG/1f373.svg - TwitterEmojiSVG/1f374.svg - TwitterEmojiSVG/1f375.svg - TwitterEmojiSVG/1f376.svg - TwitterEmojiSVG/1f377.svg - TwitterEmojiSVG/1f378.svg - TwitterEmojiSVG/1f379.svg - TwitterEmojiSVG/1f37a.svg - TwitterEmojiSVG/1f37b.svg - TwitterEmojiSVG/1f37c.svg - TwitterEmojiSVG/1f380.svg - TwitterEmojiSVG/1f381.svg - TwitterEmojiSVG/1f382.svg - TwitterEmojiSVG/1f383.svg - TwitterEmojiSVG/1f384.svg - TwitterEmojiSVG/1f385.svg - TwitterEmojiSVG/1f386.svg - TwitterEmojiSVG/1f387.svg - TwitterEmojiSVG/1f388.svg - TwitterEmojiSVG/1f389.svg - TwitterEmojiSVG/1f38a.svg - TwitterEmojiSVG/1f38b.svg - TwitterEmojiSVG/1f38c.svg - TwitterEmojiSVG/1f38d.svg - TwitterEmojiSVG/1f38e.svg - TwitterEmojiSVG/1f38f.svg - TwitterEmojiSVG/1f390.svg - TwitterEmojiSVG/1f391.svg - TwitterEmojiSVG/1f392.svg - TwitterEmojiSVG/1f393.svg - TwitterEmojiSVG/1f3a0.svg - TwitterEmojiSVG/1f3a1.svg - TwitterEmojiSVG/1f3a2.svg - TwitterEmojiSVG/1f3a3.svg - TwitterEmojiSVG/1f3a4.svg - TwitterEmojiSVG/1f3a5.svg - TwitterEmojiSVG/1f3a6.svg - TwitterEmojiSVG/1f3a7.svg - TwitterEmojiSVG/1f3a8.svg - TwitterEmojiSVG/1f3a9.svg - TwitterEmojiSVG/1f3aa.svg - TwitterEmojiSVG/1f3ab.svg - TwitterEmojiSVG/1f3ac.svg - TwitterEmojiSVG/1f3ad.svg - TwitterEmojiSVG/1f3ae.svg - TwitterEmojiSVG/1f3af.svg - TwitterEmojiSVG/1f3b0.svg - TwitterEmojiSVG/1f3b1.svg - TwitterEmojiSVG/1f3b2.svg - TwitterEmojiSVG/1f3b3.svg - TwitterEmojiSVG/1f3b4.svg - TwitterEmojiSVG/1f3b5.svg - TwitterEmojiSVG/1f3b6.svg - TwitterEmojiSVG/1f3b7.svg - TwitterEmojiSVG/1f3b8.svg - TwitterEmojiSVG/1f3b9.svg - TwitterEmojiSVG/1f3ba.svg - TwitterEmojiSVG/1f3bb.svg - TwitterEmojiSVG/1f3bc.svg - TwitterEmojiSVG/1f3bd.svg - TwitterEmojiSVG/1f3be.svg - TwitterEmojiSVG/1f3bf.svg - TwitterEmojiSVG/1f3c0.svg - TwitterEmojiSVG/1f3c1.svg - TwitterEmojiSVG/1f3c2.svg - TwitterEmojiSVG/1f3c3.svg - TwitterEmojiSVG/1f3c4.svg - TwitterEmojiSVG/1f3c6.svg - TwitterEmojiSVG/1f3c7.svg - TwitterEmojiSVG/1f3c8.svg - TwitterEmojiSVG/1f3c9.svg - TwitterEmojiSVG/1f3ca.svg - TwitterEmojiSVG/1f3e0.svg - TwitterEmojiSVG/1f3e1.svg - TwitterEmojiSVG/1f3e2.svg - TwitterEmojiSVG/1f3e3.svg - TwitterEmojiSVG/1f3e4.svg - TwitterEmojiSVG/1f3e5.svg - TwitterEmojiSVG/1f3e6.svg - TwitterEmojiSVG/1f3e7.svg - TwitterEmojiSVG/1f3e8.svg - TwitterEmojiSVG/1f3e9.svg - TwitterEmojiSVG/1f3ea.svg - TwitterEmojiSVG/1f3eb.svg - TwitterEmojiSVG/1f3ec.svg - TwitterEmojiSVG/1f3ed.svg - TwitterEmojiSVG/1f3ee.svg - TwitterEmojiSVG/1f3ef.svg - TwitterEmojiSVG/1f3f0.svg - TwitterEmojiSVG/1f400.svg - TwitterEmojiSVG/1f401.svg - TwitterEmojiSVG/1f402.svg - TwitterEmojiSVG/1f403.svg - TwitterEmojiSVG/1f404.svg - TwitterEmojiSVG/1f405.svg - TwitterEmojiSVG/1f406.svg - TwitterEmojiSVG/1f407.svg - TwitterEmojiSVG/1f408.svg - TwitterEmojiSVG/1f409.svg - TwitterEmojiSVG/1f40a.svg - TwitterEmojiSVG/1f40b.svg - TwitterEmojiSVG/1f40c.svg - TwitterEmojiSVG/1f40d.svg - TwitterEmojiSVG/1f40e.svg - TwitterEmojiSVG/1f40f.svg - TwitterEmojiSVG/1f410.svg - TwitterEmojiSVG/1f411.svg - TwitterEmojiSVG/1f412.svg - TwitterEmojiSVG/1f413.svg - TwitterEmojiSVG/1f414.svg - TwitterEmojiSVG/1f415.svg - TwitterEmojiSVG/1f416.svg - TwitterEmojiSVG/1f417.svg - TwitterEmojiSVG/1f418.svg - TwitterEmojiSVG/1f419.svg - TwitterEmojiSVG/1f41a.svg - TwitterEmojiSVG/1f41b.svg - TwitterEmojiSVG/1f41c.svg - TwitterEmojiSVG/1f41d.svg - TwitterEmojiSVG/1f41e.svg - TwitterEmojiSVG/1f41f.svg - TwitterEmojiSVG/1f420.svg - TwitterEmojiSVG/1f421.svg - TwitterEmojiSVG/1f422.svg - TwitterEmojiSVG/1f423.svg - TwitterEmojiSVG/1f424.svg - TwitterEmojiSVG/1f425.svg - TwitterEmojiSVG/1f426.svg - TwitterEmojiSVG/1f427.svg - TwitterEmojiSVG/1f428.svg - TwitterEmojiSVG/1f429.svg - TwitterEmojiSVG/1f42a.svg - TwitterEmojiSVG/1f42b.svg - TwitterEmojiSVG/1f42c.svg - TwitterEmojiSVG/1f42d.svg - TwitterEmojiSVG/1f42e.svg - TwitterEmojiSVG/1f42f.svg - TwitterEmojiSVG/1f430.svg - TwitterEmojiSVG/1f431.svg - TwitterEmojiSVG/1f432.svg - TwitterEmojiSVG/1f433.svg - TwitterEmojiSVG/1f434.svg - TwitterEmojiSVG/1f435.svg - TwitterEmojiSVG/1f436.svg - TwitterEmojiSVG/1f437.svg - TwitterEmojiSVG/1f438.svg - TwitterEmojiSVG/1f439.svg - TwitterEmojiSVG/1f43a.svg - TwitterEmojiSVG/1f43b.svg - TwitterEmojiSVG/1f43c.svg - TwitterEmojiSVG/1f43d.svg - TwitterEmojiSVG/1f43e.svg - TwitterEmojiSVG/1f440.svg - TwitterEmojiSVG/1f442.svg - TwitterEmojiSVG/1f443.svg - TwitterEmojiSVG/1f444.svg - TwitterEmojiSVG/1f445.svg - TwitterEmojiSVG/1f446.svg - TwitterEmojiSVG/1f447.svg - TwitterEmojiSVG/1f448.svg - TwitterEmojiSVG/1f449.svg - TwitterEmojiSVG/1f44a.svg - TwitterEmojiSVG/1f44b.svg - TwitterEmojiSVG/1f44c.svg - TwitterEmojiSVG/1f44d.svg - TwitterEmojiSVG/1f44e.svg - TwitterEmojiSVG/1f44f.svg - TwitterEmojiSVG/1f450.svg - TwitterEmojiSVG/1f451.svg - TwitterEmojiSVG/1f452.svg - TwitterEmojiSVG/1f453.svg - TwitterEmojiSVG/1f454.svg - TwitterEmojiSVG/1f455.svg - TwitterEmojiSVG/1f456.svg - TwitterEmojiSVG/1f457.svg - TwitterEmojiSVG/1f458.svg - TwitterEmojiSVG/1f459.svg - TwitterEmojiSVG/1f45a.svg - TwitterEmojiSVG/1f45b.svg - TwitterEmojiSVG/1f45c.svg - TwitterEmojiSVG/1f45d.svg - TwitterEmojiSVG/1f45e.svg - TwitterEmojiSVG/1f45f.svg - TwitterEmojiSVG/1f460.svg - TwitterEmojiSVG/1f461.svg - TwitterEmojiSVG/1f462.svg - TwitterEmojiSVG/1f463.svg - TwitterEmojiSVG/1f464.svg - TwitterEmojiSVG/1f465.svg - TwitterEmojiSVG/1f466.svg - TwitterEmojiSVG/1f467.svg - TwitterEmojiSVG/1f468.svg - TwitterEmojiSVG/1f469.svg - TwitterEmojiSVG/1f46a.svg - TwitterEmojiSVG/1f46b.svg - TwitterEmojiSVG/1f46c.svg - TwitterEmojiSVG/1f46d.svg - TwitterEmojiSVG/1f46e.svg - TwitterEmojiSVG/1f46f.svg - TwitterEmojiSVG/1f470.svg - TwitterEmojiSVG/1f471.svg - TwitterEmojiSVG/1f472.svg - TwitterEmojiSVG/1f473.svg - TwitterEmojiSVG/1f474.svg - TwitterEmojiSVG/1f475.svg - TwitterEmojiSVG/1f476.svg - TwitterEmojiSVG/1f477.svg - TwitterEmojiSVG/1f478.svg - TwitterEmojiSVG/1f479.svg - TwitterEmojiSVG/1f47a.svg - TwitterEmojiSVG/1f47b.svg - TwitterEmojiSVG/1f47c.svg - TwitterEmojiSVG/1f47d.svg - TwitterEmojiSVG/1f47e.svg - TwitterEmojiSVG/1f47f.svg - TwitterEmojiSVG/1f480.svg - TwitterEmojiSVG/1f481.svg - TwitterEmojiSVG/1f482.svg - TwitterEmojiSVG/1f483.svg - TwitterEmojiSVG/1f484.svg - TwitterEmojiSVG/1f485.svg - TwitterEmojiSVG/1f486.svg - TwitterEmojiSVG/1f487.svg - TwitterEmojiSVG/1f488.svg - TwitterEmojiSVG/1f489.svg - TwitterEmojiSVG/1f48a.svg - TwitterEmojiSVG/1f48b.svg - TwitterEmojiSVG/1f48c.svg - TwitterEmojiSVG/1f48d.svg - TwitterEmojiSVG/1f48e.svg - TwitterEmojiSVG/1f48f.svg - TwitterEmojiSVG/1f490.svg - TwitterEmojiSVG/1f491.svg - TwitterEmojiSVG/1f492.svg - TwitterEmojiSVG/1f493.svg - TwitterEmojiSVG/1f494.svg - TwitterEmojiSVG/1f495.svg - TwitterEmojiSVG/1f496.svg - TwitterEmojiSVG/1f497.svg - TwitterEmojiSVG/1f498.svg - TwitterEmojiSVG/1f499.svg - TwitterEmojiSVG/1f49a.svg - TwitterEmojiSVG/1f49b.svg - TwitterEmojiSVG/1f49c.svg - TwitterEmojiSVG/1f49d.svg - TwitterEmojiSVG/1f49e.svg - TwitterEmojiSVG/1f49f.svg - TwitterEmojiSVG/1f4a0.svg - TwitterEmojiSVG/1f4a1.svg - TwitterEmojiSVG/1f4a2.svg - TwitterEmojiSVG/1f4a3.svg - TwitterEmojiSVG/1f4a4.svg - TwitterEmojiSVG/1f4a5.svg - TwitterEmojiSVG/1f4a6.svg - TwitterEmojiSVG/1f4a7.svg - TwitterEmojiSVG/1f4a8.svg - TwitterEmojiSVG/1f4aa.svg - TwitterEmojiSVG/1f4ab.svg - TwitterEmojiSVG/1f4ac.svg - TwitterEmojiSVG/1f4ad.svg - TwitterEmojiSVG/1f4ae.svg - TwitterEmojiSVG/1f4af.svg - TwitterEmojiSVG/1f4b0.svg - TwitterEmojiSVG/1f4b1.svg - TwitterEmojiSVG/1f4b2.svg - TwitterEmojiSVG/1f4b3.svg - TwitterEmojiSVG/1f4b4.svg - TwitterEmojiSVG/1f4b5.svg - TwitterEmojiSVG/1f4b6.svg - TwitterEmojiSVG/1f4b7.svg - TwitterEmojiSVG/1f4b8.svg - TwitterEmojiSVG/1f4b9.svg - TwitterEmojiSVG/1f4ba.svg - TwitterEmojiSVG/1f4bb.svg - TwitterEmojiSVG/1f4bc.svg - TwitterEmojiSVG/1f4bd.svg - TwitterEmojiSVG/1f4be.svg - TwitterEmojiSVG/1f4bf.svg - TwitterEmojiSVG/1f4c0.svg - TwitterEmojiSVG/1f4c1.svg - TwitterEmojiSVG/1f4c2.svg - TwitterEmojiSVG/1f4c3.svg - TwitterEmojiSVG/1f4c4.svg - TwitterEmojiSVG/1f4c5.svg - TwitterEmojiSVG/1f4c6.svg - TwitterEmojiSVG/1f4c7.svg - TwitterEmojiSVG/1f4c8.svg - TwitterEmojiSVG/1f4c9.svg - TwitterEmojiSVG/1f4ca.svg - TwitterEmojiSVG/1f4cb.svg - TwitterEmojiSVG/1f4cc.svg - TwitterEmojiSVG/1f4cd.svg - TwitterEmojiSVG/1f4ce.svg - TwitterEmojiSVG/1f4cf.svg - TwitterEmojiSVG/1f4d0.svg - TwitterEmojiSVG/1f4d1.svg - TwitterEmojiSVG/1f4d2.svg - TwitterEmojiSVG/1f4d3.svg - TwitterEmojiSVG/1f4d4.svg - TwitterEmojiSVG/1f4d5.svg - TwitterEmojiSVG/1f4d6.svg - TwitterEmojiSVG/1f4d7.svg - TwitterEmojiSVG/1f4d8.svg - TwitterEmojiSVG/1f4d9.svg - TwitterEmojiSVG/1f4da.svg - TwitterEmojiSVG/1f4db.svg - TwitterEmojiSVG/1f4dc.svg - TwitterEmojiSVG/1f4dd.svg - TwitterEmojiSVG/1f4de.svg - TwitterEmojiSVG/1f4df.svg - TwitterEmojiSVG/1f4e0.svg - TwitterEmojiSVG/1f4e1.svg - TwitterEmojiSVG/1f4e2.svg - TwitterEmojiSVG/1f4e3.svg - TwitterEmojiSVG/1f4e4.svg - TwitterEmojiSVG/1f4e5.svg - TwitterEmojiSVG/1f4e6.svg - TwitterEmojiSVG/1f4e7.svg - TwitterEmojiSVG/1f4e8.svg - TwitterEmojiSVG/1f4e9.svg - TwitterEmojiSVG/1f4ea.svg - TwitterEmojiSVG/1f4eb.svg - TwitterEmojiSVG/1f4ec.svg - TwitterEmojiSVG/1f4ed.svg - TwitterEmojiSVG/1f4ee.svg - TwitterEmojiSVG/1f4ef.svg - TwitterEmojiSVG/1f4f0.svg - TwitterEmojiSVG/1f4f1.svg - TwitterEmojiSVG/1f4f2.svg - TwitterEmojiSVG/1f4f3.svg - TwitterEmojiSVG/1f4f4.svg - TwitterEmojiSVG/1f4f5.svg - TwitterEmojiSVG/1f4f6.svg - TwitterEmojiSVG/1f4f7.svg - TwitterEmojiSVG/1f4f9.svg - TwitterEmojiSVG/1f4fa.svg - TwitterEmojiSVG/1f4fb.svg - TwitterEmojiSVG/1f4fc.svg - TwitterEmojiSVG/1f500.svg - TwitterEmojiSVG/1f501.svg - TwitterEmojiSVG/1f502.svg - TwitterEmojiSVG/1f503.svg - TwitterEmojiSVG/1f504.svg - TwitterEmojiSVG/1f505.svg - TwitterEmojiSVG/1f506.svg - TwitterEmojiSVG/1f507.svg - TwitterEmojiSVG/1f508.svg - TwitterEmojiSVG/1f509.svg - TwitterEmojiSVG/1f50a.svg - TwitterEmojiSVG/1f50b.svg - TwitterEmojiSVG/1f50c.svg - TwitterEmojiSVG/1f50d.svg - TwitterEmojiSVG/1f50e.svg - TwitterEmojiSVG/1f50f.svg - TwitterEmojiSVG/1f510.svg - TwitterEmojiSVG/1f511.svg - TwitterEmojiSVG/1f512.svg - TwitterEmojiSVG/1f513.svg - TwitterEmojiSVG/1f514.svg - TwitterEmojiSVG/1f515.svg - TwitterEmojiSVG/1f516.svg - TwitterEmojiSVG/1f517.svg - TwitterEmojiSVG/1f518.svg - TwitterEmojiSVG/1f519.svg - TwitterEmojiSVG/1f51a.svg - TwitterEmojiSVG/1f51b.svg - TwitterEmojiSVG/1f51c.svg - TwitterEmojiSVG/1f51d.svg - TwitterEmojiSVG/1f51e.svg - TwitterEmojiSVG/1f51f.svg - TwitterEmojiSVG/1f520.svg - TwitterEmojiSVG/1f521.svg - TwitterEmojiSVG/1f522.svg - TwitterEmojiSVG/1f523.svg - TwitterEmojiSVG/1f524.svg - TwitterEmojiSVG/1f525.svg - TwitterEmojiSVG/1f526.svg - TwitterEmojiSVG/1f527.svg - TwitterEmojiSVG/1f528.svg - TwitterEmojiSVG/1f529.svg - TwitterEmojiSVG/1f52a.svg - TwitterEmojiSVG/1f52b.svg - TwitterEmojiSVG/1f52c.svg - TwitterEmojiSVG/1f52d.svg - TwitterEmojiSVG/1f52e.svg - TwitterEmojiSVG/1f52f.svg - TwitterEmojiSVG/1f530.svg - TwitterEmojiSVG/1f531.svg - TwitterEmojiSVG/1f532.svg - TwitterEmojiSVG/1f533.svg - TwitterEmojiSVG/1f534.svg - TwitterEmojiSVG/1f535.svg - TwitterEmojiSVG/1f536.svg - TwitterEmojiSVG/1f537.svg - TwitterEmojiSVG/1f538.svg - TwitterEmojiSVG/1f539.svg - TwitterEmojiSVG/1f53a.svg - TwitterEmojiSVG/1f53b.svg - TwitterEmojiSVG/1f53c.svg - TwitterEmojiSVG/1f53d.svg - TwitterEmojiSVG/1f550.svg - TwitterEmojiSVG/1f551.svg - TwitterEmojiSVG/1f552.svg - TwitterEmojiSVG/1f553.svg - TwitterEmojiSVG/1f554.svg - TwitterEmojiSVG/1f555.svg - TwitterEmojiSVG/1f556.svg - TwitterEmojiSVG/1f557.svg - TwitterEmojiSVG/1f558.svg - TwitterEmojiSVG/1f559.svg - TwitterEmojiSVG/1f55a.svg - TwitterEmojiSVG/1f55b.svg - TwitterEmojiSVG/1f55c.svg - TwitterEmojiSVG/1f55d.svg - TwitterEmojiSVG/1f55e.svg - TwitterEmojiSVG/1f55f.svg - TwitterEmojiSVG/1f560.svg - TwitterEmojiSVG/1f561.svg - TwitterEmojiSVG/1f562.svg - TwitterEmojiSVG/1f563.svg - TwitterEmojiSVG/1f564.svg - TwitterEmojiSVG/1f565.svg - TwitterEmojiSVG/1f566.svg - TwitterEmojiSVG/1f567.svg - TwitterEmojiSVG/1f595.svg - TwitterEmojiSVG/1f5fb.svg - TwitterEmojiSVG/1f5fc.svg - TwitterEmojiSVG/1f5fd.svg - TwitterEmojiSVG/1f5fe.svg - TwitterEmojiSVG/1f5ff.svg - TwitterEmojiSVG/1f004.svg - TwitterEmojiSVG/1f0cf.svg - TwitterEmojiSVG/2600.svg - TwitterEmojiSVG/2601.svg - TwitterEmojiSVG/260e.svg - TwitterEmojiSVG/2611.svg - TwitterEmojiSVG/2614.svg - TwitterEmojiSVG/2615.svg - TwitterEmojiSVG/261d.svg - TwitterEmojiSVG/2648.svg - TwitterEmojiSVG/2649.svg - TwitterEmojiSVG/264a.svg - TwitterEmojiSVG/264b.svg - TwitterEmojiSVG/264c.svg - TwitterEmojiSVG/264d.svg - TwitterEmojiSVG/264e.svg - TwitterEmojiSVG/264f.svg - TwitterEmojiSVG/2650.svg - TwitterEmojiSVG/2651.svg - TwitterEmojiSVG/2652.svg - TwitterEmojiSVG/2653.svg - TwitterEmojiSVG/2660.svg - TwitterEmojiSVG/2663.svg - TwitterEmojiSVG/2665.svg - TwitterEmojiSVG/2666.svg - TwitterEmojiSVG/2668.svg - TwitterEmojiSVG/267b.svg - TwitterEmojiSVG/267f.svg - TwitterEmojiSVG/2693.svg - TwitterEmojiSVG/26a0.svg - TwitterEmojiSVG/26a1.svg - TwitterEmojiSVG/26aa.svg - TwitterEmojiSVG/26ab.svg - TwitterEmojiSVG/26bd.svg - TwitterEmojiSVG/26be.svg - TwitterEmojiSVG/26c4.svg - TwitterEmojiSVG/26c5.svg - TwitterEmojiSVG/26ce.svg - TwitterEmojiSVG/26d4.svg - TwitterEmojiSVG/26ea.svg - TwitterEmojiSVG/26f2.svg - TwitterEmojiSVG/26f3.svg - TwitterEmojiSVG/26f5.svg - TwitterEmojiSVG/26fa.svg - TwitterEmojiSVG/26fd.svg - TwitterEmojiSVG/1f680.svg - TwitterEmojiSVG/1f681.svg - TwitterEmojiSVG/1f682.svg - TwitterEmojiSVG/1f683.svg - TwitterEmojiSVG/1f684.svg - TwitterEmojiSVG/1f685.svg - TwitterEmojiSVG/1f686.svg - TwitterEmojiSVG/1f687.svg - TwitterEmojiSVG/1f688.svg - TwitterEmojiSVG/1f689.svg - TwitterEmojiSVG/1f68a.svg - TwitterEmojiSVG/1f68b.svg - TwitterEmojiSVG/1f68c.svg - TwitterEmojiSVG/1f68d.svg - TwitterEmojiSVG/1f68e.svg - TwitterEmojiSVG/1f68f.svg - TwitterEmojiSVG/1f690.svg - TwitterEmojiSVG/1f691.svg - TwitterEmojiSVG/1f692.svg - TwitterEmojiSVG/1f693.svg - TwitterEmojiSVG/1f694.svg - TwitterEmojiSVG/1f695.svg - TwitterEmojiSVG/1f696.svg - TwitterEmojiSVG/1f697.svg - TwitterEmojiSVG/1f698.svg - TwitterEmojiSVG/1f699.svg - TwitterEmojiSVG/1f69a.svg - TwitterEmojiSVG/1f69b.svg - TwitterEmojiSVG/1f69c.svg - TwitterEmojiSVG/1f69d.svg - TwitterEmojiSVG/1f69e.svg - TwitterEmojiSVG/1f69f.svg - TwitterEmojiSVG/1f6a0.svg - TwitterEmojiSVG/1f6a1.svg - TwitterEmojiSVG/1f6a2.svg - TwitterEmojiSVG/1f6a3.svg - TwitterEmojiSVG/1f6a4.svg - TwitterEmojiSVG/1f6a5.svg - TwitterEmojiSVG/1f6a6.svg - TwitterEmojiSVG/1f6a7.svg - TwitterEmojiSVG/1f6a8.svg - TwitterEmojiSVG/1f6a9.svg - TwitterEmojiSVG/1f6aa.svg - TwitterEmojiSVG/1f6ab.svg - TwitterEmojiSVG/1f6ac.svg - TwitterEmojiSVG/1f6ad.svg - TwitterEmojiSVG/1f6ae.svg - TwitterEmojiSVG/1f6af.svg - TwitterEmojiSVG/1f6b0.svg - TwitterEmojiSVG/1f6b1.svg - TwitterEmojiSVG/1f6b2.svg - TwitterEmojiSVG/1f6b3.svg - TwitterEmojiSVG/1f6b4.svg - TwitterEmojiSVG/1f6b5.svg - TwitterEmojiSVG/1f6b6.svg - TwitterEmojiSVG/1f6b7.svg - TwitterEmojiSVG/1f6b8.svg - TwitterEmojiSVG/1f6b9.svg - TwitterEmojiSVG/1f6ba.svg - TwitterEmojiSVG/1f6bb.svg - TwitterEmojiSVG/1f6bc.svg - TwitterEmojiSVG/1f6bd.svg - TwitterEmojiSVG/1f6be.svg - TwitterEmojiSVG/1f6bf.svg - TwitterEmojiSVG/1f6c0.svg - TwitterEmojiSVG/1f6c1.svg - TwitterEmojiSVG/1f6c2.svg - TwitterEmojiSVG/1f6c3.svg - TwitterEmojiSVG/1f6c4.svg - TwitterEmojiSVG/1f6c5.svg - TwitterEmojiSVG/2702.svg - TwitterEmojiSVG/2705.svg - TwitterEmojiSVG/2708.svg - TwitterEmojiSVG/2709.svg - TwitterEmojiSVG/270a.svg - TwitterEmojiSVG/270b.svg - TwitterEmojiSVG/270c.svg - TwitterEmojiSVG/270f.svg - TwitterEmojiSVG/2712.svg - TwitterEmojiSVG/2714.svg - TwitterEmojiSVG/2716.svg - TwitterEmojiSVG/2728.svg - TwitterEmojiSVG/2733.svg - TwitterEmojiSVG/2734.svg - TwitterEmojiSVG/2744.svg - TwitterEmojiSVG/2747.svg - TwitterEmojiSVG/274c.svg - TwitterEmojiSVG/274e.svg - TwitterEmojiSVG/2753.svg - TwitterEmojiSVG/2754.svg - TwitterEmojiSVG/2755.svg - TwitterEmojiSVG/2757.svg - TwitterEmojiSVG/2764.svg - TwitterEmojiSVG/2795.svg - TwitterEmojiSVG/2796.svg - TwitterEmojiSVG/2797.svg - TwitterEmojiSVG/27a1.svg - TwitterEmojiSVG/27b0.svg - TwitterEmojiSVG/27bf.svg - TwitterEmojiSVG/2934.svg - TwitterEmojiSVG/2935.svg - TwitterEmojiSVG/3030.svg - TwitterEmojiSVG/3297.svg - TwitterEmojiSVG/3299.svg - TwitterEmojiSVG/a9.svg - TwitterEmojiSVG/ae.svg - TwitterEmojiSVG/1f21a.svg - TwitterEmojiSVG/1f22f.svg - TwitterEmojiSVG/1f23a.svg - TwitterEmojiSVG/1f201.svg - TwitterEmojiSVG/1f202.svg - TwitterEmojiSVG/1f232.svg - TwitterEmojiSVG/1f233.svg - TwitterEmojiSVG/1f234.svg - TwitterEmojiSVG/1f235.svg - TwitterEmojiSVG/1f236.svg - TwitterEmojiSVG/1f237.svg - TwitterEmojiSVG/1f238.svg - TwitterEmojiSVG/1f239.svg - TwitterEmojiSVG/1f250.svg - TwitterEmojiSVG/1f251.svg - TwitterEmojiSVG/1f170.svg - TwitterEmojiSVG/1f171.svg - TwitterEmojiSVG/1f17e.svg - TwitterEmojiSVG/1f17f.svg - TwitterEmojiSVG/1f18e.svg - TwitterEmojiSVG/1f191.svg - TwitterEmojiSVG/1f192.svg - TwitterEmojiSVG/1f193.svg - TwitterEmojiSVG/1f194.svg - TwitterEmojiSVG/1f195.svg - TwitterEmojiSVG/1f196.svg - TwitterEmojiSVG/1f197.svg - TwitterEmojiSVG/1f198.svg - TwitterEmojiSVG/1f199.svg - TwitterEmojiSVG/1f19a.svg - TwitterEmojiSVG/1f1e6.svg - TwitterEmojiSVG/1f1e7.svg - TwitterEmojiSVG/1f1e8.svg - TwitterEmojiSVG/1f1e9.svg - TwitterEmojiSVG/1f1ea.svg - TwitterEmojiSVG/1f1eb.svg - TwitterEmojiSVG/1f1ec.svg - TwitterEmojiSVG/1f1ed.svg - TwitterEmojiSVG/1f1ee.svg - TwitterEmojiSVG/1f1ef.svg - TwitterEmojiSVG/1f1f0.svg - TwitterEmojiSVG/1f1f1.svg - TwitterEmojiSVG/1f1f2.svg - TwitterEmojiSVG/1f1f3.svg - TwitterEmojiSVG/1f1f4.svg - TwitterEmojiSVG/1f1f5.svg - TwitterEmojiSVG/1f1f6.svg - TwitterEmojiSVG/1f1f7.svg - TwitterEmojiSVG/1f1f8.svg - TwitterEmojiSVG/1f1f9.svg - TwitterEmojiSVG/1f1fa.svg - TwitterEmojiSVG/1f1fb.svg - TwitterEmojiSVG/1f1fc.svg - TwitterEmojiSVG/1f1fd.svg - TwitterEmojiSVG/1f1fe.svg - TwitterEmojiSVG/1f1ff.svg - TwitterEmojiSVG/1f1e8-1f1f3.svg - TwitterEmojiSVG/1f1e9-1f1ea.svg - TwitterEmojiSVG/1f1ea-1f1f8.svg - TwitterEmojiSVG/1f1eb-1f1f7.svg - TwitterEmojiSVG/1f1ec-1f1e7.svg - TwitterEmojiSVG/1f1ee-1f1f9.svg - TwitterEmojiSVG/1f1ef-1f1f5.svg - TwitterEmojiSVG/1f1f0-1f1f7.svg - TwitterEmojiSVG/1f1f7-1f1fa.svg - TwitterEmojiSVG/1f1fa-1f1f8.svg - TwitterEmojiSVG/emoticons.xml - TwitterEmojiSimple/emoticons.xml + Basic/angel.png + Basic/angry.png + Basic/beer.png + Basic/bomb.png + Basic/bored.png + Basic/cookie.png + Basic/cool.png + Basic/crossing.png + Basic/crying.png + Basic/devil.png + Basic/diamond.png + Basic/doh.png + Basic/emoticons.xml + Basic/evil.png + Basic/eye.png + Basic/facepalm.png + Basic/finger.png + Basic/hacker_terminal.png + Basic/happysmile.png + Basic/heart.png + Basic/hi.png + Basic/highfive.png + Basic/hot.png + Basic/impressed.png + Basic/inlove.png + Basic/jealous.png + Basic/kiss.png + Basic/lol.png + Basic/moustache.png + Basic/MrSmith.png + Basic/nerd.png + Basic/nospeak.png + Basic/oops.png + Basic/party.png + Basic/pressed.png + Basic/rain.png + Basic/rocknroll.png + Basic/sad.png + Basic/shy.png + Basic/sleeping.png + Basic/smile.png + Basic/sniggering.png + Basic/suspicious.png + Basic/syringe.png + Basic/tongue.png + Basic/toxlocker.png + Basic/vomit.png + Basic/wasntme.png + Basic/whew.png + Basic/wink.png + Basic/wondering.png + Basic/X(.png + Basic/XD.png + Basic/XP.png + Basic/yawn.png + Classic/angry.png + Classic/cool.png + Classic/crying.png + Classic/emoticons.xml + Classic/happy.png + Classic/Kappa.png + Classic/laugh_closed_eyes.png + Classic/laugh.png + Classic/plain.png + Classic/raw.svg + Classic/sad.png + Classic/scared.png + Classic/smile.png + Classic/stunned.png + Classic/tongue.png + Classic/uncertain.png + Classic/wink.png + Universe/263a.svg + Universe/1f600.svg + Universe/1f601.svg + Universe/1f602.svg + Universe/1f603.svg + Universe/1f604.svg + Universe/1f605.svg + Universe/1f606.svg + Universe/1f607.svg + Universe/1f608.svg + Universe/1f609.svg + Universe/1f60a.svg + Universe/1f60b.svg + Universe/1f60c.svg + Universe/1f60d.svg + Universe/1f60e.svg + Universe/1f60f.svg + Universe/1f610.svg + Universe/1f611.svg + Universe/1f612.svg + Universe/1f613.svg + Universe/1f614.svg + Universe/1f615.svg + Universe/1f616.svg + Universe/1f617.svg + Universe/1f618.svg + Universe/1f619.svg + Universe/1f61a.svg + Universe/1f61b.svg + Universe/1f61c.svg + Universe/1f61d.svg + Universe/1f61e.svg + Universe/1f61f.svg + Universe/1f620.svg + Universe/1f621.svg + Universe/1f622.svg + Universe/1f623.svg + Universe/1f624.svg + Universe/1f625.svg + Universe/1f626.svg + Universe/1f627.svg + Universe/1f628.svg + Universe/1f629.svg + Universe/1f62a.svg + Universe/1f62b.svg + Universe/1f62c.svg + Universe/1f62d.svg + Universe/1f62e.svg + Universe/1f62f.svg + Universe/1f630.svg + Universe/1f631.svg + Universe/1f632.svg + Universe/1f633.svg + Universe/1f634.svg + Universe/1f635.svg + Universe/1f636.svg + Universe/1f637.svg + Universe/1f638.svg + Universe/1f639.svg + Universe/1f63a.svg + Universe/1f63b.svg + Universe/1f63c.svg + Universe/1f63d.svg + Universe/1f63e.svg + Universe/1f63f.svg + Universe/1f640.svg + Universe/1f645.svg + Universe/1f646.svg + Universe/1f647.svg + Universe/1f648.svg + Universe/1f649.svg + Universe/1f64a.svg + Universe/1f64b.svg + Universe/1f64c.svg + Universe/1f64d.svg + Universe/1f64e.svg + Universe/1f64f.svg + Universe/1f4a9.svg + Universe/1f300.svg + Universe/1f301.svg + Universe/1f302.svg + Universe/1f303.svg + Universe/1f304.svg + Universe/1f305.svg + Universe/1f306.svg + Universe/1f307.svg + Universe/1f308.svg + Universe/1f309.svg + Universe/1f30a.svg + Universe/1f30b.svg + Universe/1f30c.svg + Universe/1f30d.svg + Universe/1f30e.svg + Universe/1f30f.svg + Universe/1f310.svg + Universe/1f311.svg + Universe/1f312.svg + Universe/1f313.svg + Universe/1f314.svg + Universe/1f315.svg + Universe/1f316.svg + Universe/1f317.svg + Universe/1f318.svg + Universe/1f319.svg + Universe/1f31a.svg + Universe/1f31b.svg + Universe/1f31c.svg + Universe/1f31d.svg + Universe/1f31e.svg + Universe/1f31f.svg + Universe/1f320.svg + Universe/1f330.svg + Universe/1f331.svg + Universe/1f332.svg + Universe/1f333.svg + Universe/1f334.svg + Universe/1f335.svg + Universe/1f337.svg + Universe/1f338.svg + Universe/1f339.svg + Universe/1f33a.svg + Universe/1f33b.svg + Universe/1f33c.svg + Universe/1f33d.svg + Universe/1f33e.svg + Universe/1f33f.svg + Universe/1f340.svg + Universe/1f341.svg + Universe/1f342.svg + Universe/1f343.svg + Universe/1f344.svg + Universe/1f345.svg + Universe/1f346.svg + Universe/1f347.svg + Universe/1f348.svg + Universe/1f349.svg + Universe/1f34a.svg + Universe/1f34b.svg + Universe/1f34c.svg + Universe/1f34d.svg + Universe/1f34e.svg + Universe/1f34f.svg + Universe/1f350.svg + Universe/1f351.svg + Universe/1f352.svg + Universe/1f353.svg + Universe/1f354.svg + Universe/1f355.svg + Universe/1f356.svg + Universe/1f357.svg + Universe/1f358.svg + Universe/1f359.svg + Universe/1f35a.svg + Universe/1f35b.svg + Universe/1f35c.svg + Universe/1f35d.svg + Universe/1f35e.svg + Universe/1f35f.svg + Universe/1f360.svg + Universe/1f361.svg + Universe/1f362.svg + Universe/1f363.svg + Universe/1f364.svg + Universe/1f365.svg + Universe/1f366.svg + Universe/1f367.svg + Universe/1f368.svg + Universe/1f369.svg + Universe/1f36a.svg + Universe/1f36b.svg + Universe/1f36c.svg + Universe/1f36d.svg + Universe/1f36e.svg + Universe/1f36f.svg + Universe/1f370.svg + Universe/1f371.svg + Universe/1f372.svg + Universe/1f373.svg + Universe/1f374.svg + Universe/1f375.svg + Universe/1f376.svg + Universe/1f377.svg + Universe/1f378.svg + Universe/1f379.svg + Universe/1f37a.svg + Universe/1f37b.svg + Universe/1f37c.svg + Universe/1f380.svg + Universe/1f381.svg + Universe/1f382.svg + Universe/1f383.svg + Universe/1f384.svg + Universe/1f385.svg + Universe/1f386.svg + Universe/1f387.svg + Universe/1f388.svg + Universe/1f389.svg + Universe/1f38a.svg + Universe/1f38b.svg + Universe/1f38c.svg + Universe/1f38d.svg + Universe/1f38e.svg + Universe/1f38f.svg + Universe/1f390.svg + Universe/1f391.svg + Universe/1f392.svg + Universe/1f393.svg + Universe/1f3a0.svg + Universe/1f3a1.svg + Universe/1f3a2.svg + Universe/1f3a3.svg + Universe/1f3a4.svg + Universe/1f3a5.svg + Universe/1f3a6.svg + Universe/1f3a7.svg + Universe/1f3a8.svg + Universe/1f3a9.svg + Universe/1f3aa.svg + Universe/1f3ab.svg + Universe/1f3ac.svg + Universe/1f3ad.svg + Universe/1f3ae.svg + Universe/1f3af.svg + Universe/1f3b0.svg + Universe/1f3b1.svg + Universe/1f3b2.svg + Universe/1f3b3.svg + Universe/1f3b4.svg + Universe/1f3b5.svg + Universe/1f3b6.svg + Universe/1f3b7.svg + Universe/1f3b8.svg + Universe/1f3b9.svg + Universe/1f3ba.svg + Universe/1f3bb.svg + Universe/1f3bc.svg + Universe/1f3bd.svg + Universe/1f3be.svg + Universe/1f3bf.svg + Universe/1f3c0.svg + Universe/1f3c1.svg + Universe/1f3c2.svg + Universe/1f3c3.svg + Universe/1f3c4.svg + Universe/1f3c6.svg + Universe/1f3c7.svg + Universe/1f3c8.svg + Universe/1f3c9.svg + Universe/1f3ca.svg + Universe/1f3e0.svg + Universe/1f3e1.svg + Universe/1f3e2.svg + Universe/1f3e3.svg + Universe/1f3e4.svg + Universe/1f3e5.svg + Universe/1f3e6.svg + Universe/1f3e7.svg + Universe/1f3e8.svg + Universe/1f3e9.svg + Universe/1f3ea.svg + Universe/1f3eb.svg + Universe/1f3ec.svg + Universe/1f3ed.svg + Universe/1f3ee.svg + Universe/1f3ef.svg + Universe/1f3f0.svg + Universe/1f400.svg + Universe/1f401.svg + Universe/1f402.svg + Universe/1f403.svg + Universe/1f404.svg + Universe/1f405.svg + Universe/1f406.svg + Universe/1f407.svg + Universe/1f408.svg + Universe/1f409.svg + Universe/1f40a.svg + Universe/1f40b.svg + Universe/1f40c.svg + Universe/1f40d.svg + Universe/1f40e.svg + Universe/1f40f.svg + Universe/1f410.svg + Universe/1f411.svg + Universe/1f412.svg + Universe/1f413.svg + Universe/1f414.svg + Universe/1f415.svg + Universe/1f416.svg + Universe/1f417.svg + Universe/1f418.svg + Universe/1f419.svg + Universe/1f41a.svg + Universe/1f41b.svg + Universe/1f41c.svg + Universe/1f41d.svg + Universe/1f41e.svg + Universe/1f41f.svg + Universe/1f420.svg + Universe/1f421.svg + Universe/1f422.svg + Universe/1f423.svg + Universe/1f424.svg + Universe/1f425.svg + Universe/1f426.svg + Universe/1f427.svg + Universe/1f428.svg + Universe/1f429.svg + Universe/1f42a.svg + Universe/1f42b.svg + Universe/1f42c.svg + Universe/1f42d.svg + Universe/1f42e.svg + Universe/1f42f.svg + Universe/1f430.svg + Universe/1f431.svg + Universe/1f432.svg + Universe/1f433.svg + Universe/1f434.svg + Universe/1f435.svg + Universe/1f436.svg + Universe/1f437.svg + Universe/1f438.svg + Universe/1f439.svg + Universe/1f43a.svg + Universe/1f43b.svg + Universe/1f43c.svg + Universe/1f43d.svg + Universe/1f43e.svg + Universe/1f440.svg + Universe/1f442.svg + Universe/1f443.svg + Universe/1f444.svg + Universe/1f445.svg + Universe/1f446.svg + Universe/1f447.svg + Universe/1f448.svg + Universe/1f449.svg + Universe/1f44a.svg + Universe/1f44b.svg + Universe/1f44c.svg + Universe/1f44d.svg + Universe/1f44e.svg + Universe/1f44f.svg + Universe/1f450.svg + Universe/1f451.svg + Universe/1f452.svg + Universe/1f453.svg + Universe/1f454.svg + Universe/1f455.svg + Universe/1f456.svg + Universe/1f457.svg + Universe/1f458.svg + Universe/1f459.svg + Universe/1f45a.svg + Universe/1f45b.svg + Universe/1f45c.svg + Universe/1f45d.svg + Universe/1f45e.svg + Universe/1f45f.svg + Universe/1f460.svg + Universe/1f461.svg + Universe/1f462.svg + Universe/1f463.svg + Universe/1f464.svg + Universe/1f465.svg + Universe/1f466.svg + Universe/1f467.svg + Universe/1f468.svg + Universe/1f469.svg + Universe/1f46a.svg + Universe/1f46b.svg + Universe/1f46c.svg + Universe/1f46d.svg + Universe/1f46e.svg + Universe/1f46f.svg + Universe/1f470.svg + Universe/1f471.svg + Universe/1f472.svg + Universe/1f473.svg + Universe/1f474.svg + Universe/1f475.svg + Universe/1f476.svg + Universe/1f477.svg + Universe/1f478.svg + Universe/1f479.svg + Universe/1f47a.svg + Universe/1f47b.svg + Universe/1f47c.svg + Universe/1f47d.svg + Universe/1f47e.svg + Universe/1f47f.svg + Universe/1f480.svg + Universe/1f481.svg + Universe/1f482.svg + Universe/1f483.svg + Universe/1f484.svg + Universe/1f485.svg + Universe/1f486.svg + Universe/1f487.svg + Universe/1f488.svg + Universe/1f489.svg + Universe/1f48a.svg + Universe/1f48b.svg + Universe/1f48c.svg + Universe/1f48d.svg + Universe/1f48e.svg + Universe/1f48f.svg + Universe/1f490.svg + Universe/1f491.svg + Universe/1f492.svg + Universe/1f493.svg + Universe/1f494.svg + Universe/1f495.svg + Universe/1f496.svg + Universe/1f497.svg + Universe/1f498.svg + Universe/1f499.svg + Universe/1f49a.svg + Universe/1f49b.svg + Universe/1f49c.svg + Universe/1f49d.svg + Universe/1f49e.svg + Universe/1f49f.svg + Universe/1f4a0.svg + Universe/1f4a1.svg + Universe/1f4a2.svg + Universe/1f4a3.svg + Universe/1f4a4.svg + Universe/1f4a5.svg + Universe/1f4a6.svg + Universe/1f4a7.svg + Universe/1f4a8.svg + Universe/1f4aa.svg + Universe/1f4ab.svg + Universe/1f4ac.svg + Universe/1f4ad.svg + Universe/1f4ae.svg + Universe/1f4af.svg + Universe/1f4b0.svg + Universe/1f4b1.svg + Universe/1f4b2.svg + Universe/1f4b3.svg + Universe/1f4b4.svg + Universe/1f4b5.svg + Universe/1f4b6.svg + Universe/1f4b7.svg + Universe/1f4b8.svg + Universe/1f4b9.svg + Universe/1f4ba.svg + Universe/1f4bb.svg + Universe/1f4bc.svg + Universe/1f4bd.svg + Universe/1f4be.svg + Universe/1f4bf.svg + Universe/1f4c0.svg + Universe/1f4c1.svg + Universe/1f4c2.svg + Universe/1f4c3.svg + Universe/1f4c4.svg + Universe/1f4c5.svg + Universe/1f4c6.svg + Universe/1f4c7.svg + Universe/1f4c8.svg + Universe/1f4c9.svg + Universe/1f4ca.svg + Universe/1f4cb.svg + Universe/1f4cc.svg + Universe/1f4cd.svg + Universe/1f4ce.svg + Universe/1f4cf.svg + Universe/1f4d0.svg + Universe/1f4d1.svg + Universe/1f4d2.svg + Universe/1f4d3.svg + Universe/1f4d4.svg + Universe/1f4d5.svg + Universe/1f4d6.svg + Universe/1f4d7.svg + Universe/1f4d8.svg + Universe/1f4d9.svg + Universe/1f4da.svg + Universe/1f4db.svg + Universe/1f4dc.svg + Universe/1f4dd.svg + Universe/1f4de.svg + Universe/1f4df.svg + Universe/1f4e0.svg + Universe/1f4e1.svg + Universe/1f4e2.svg + Universe/1f4e3.svg + Universe/1f4e4.svg + Universe/1f4e5.svg + Universe/1f4e6.svg + Universe/1f4e7.svg + Universe/1f4e8.svg + Universe/1f4e9.svg + Universe/1f4ea.svg + Universe/1f4eb.svg + Universe/1f4ec.svg + Universe/1f4ed.svg + Universe/1f4ee.svg + Universe/1f4ef.svg + Universe/1f4f0.svg + Universe/1f4f1.svg + Universe/1f4f2.svg + Universe/1f4f3.svg + Universe/1f4f4.svg + Universe/1f4f5.svg + Universe/1f4f6.svg + Universe/1f4f7.svg + Universe/1f4f9.svg + Universe/1f4fa.svg + Universe/1f4fb.svg + Universe/1f4fc.svg + Universe/1f500.svg + Universe/1f501.svg + Universe/1f502.svg + Universe/1f503.svg + Universe/1f504.svg + Universe/1f505.svg + Universe/1f506.svg + Universe/1f507.svg + Universe/1f508.svg + Universe/1f509.svg + Universe/1f50a.svg + Universe/1f50b.svg + Universe/1f50c.svg + Universe/1f50d.svg + Universe/1f50e.svg + Universe/1f50f.svg + Universe/1f510.svg + Universe/1f511.svg + Universe/1f512.svg + Universe/1f513.svg + Universe/1f514.svg + Universe/1f515.svg + Universe/1f516.svg + Universe/1f517.svg + Universe/1f518.svg + Universe/1f519.svg + Universe/1f51a.svg + Universe/1f51b.svg + Universe/1f51c.svg + Universe/1f51d.svg + Universe/1f51e.svg + Universe/1f51f.svg + Universe/1f520.svg + Universe/1f521.svg + Universe/1f522.svg + Universe/1f523.svg + Universe/1f524.svg + Universe/1f525.svg + Universe/1f526.svg + Universe/1f527.svg + Universe/1f528.svg + Universe/1f529.svg + Universe/1f52a.svg + Universe/1f52b.svg + Universe/1f52c.svg + Universe/1f52d.svg + Universe/1f52e.svg + Universe/1f52f.svg + Universe/1f530.svg + Universe/1f531.svg + Universe/1f532.svg + Universe/1f533.svg + Universe/1f534.svg + Universe/1f535.svg + Universe/1f536.svg + Universe/1f537.svg + Universe/1f538.svg + Universe/1f539.svg + Universe/1f53a.svg + Universe/1f53b.svg + Universe/1f53c.svg + Universe/1f53d.svg + Universe/1f550.svg + Universe/1f551.svg + Universe/1f552.svg + Universe/1f553.svg + Universe/1f554.svg + Universe/1f555.svg + Universe/1f556.svg + Universe/1f557.svg + Universe/1f558.svg + Universe/1f559.svg + Universe/1f55a.svg + Universe/1f55b.svg + Universe/1f55c.svg + Universe/1f55d.svg + Universe/1f55e.svg + Universe/1f55f.svg + Universe/1f560.svg + Universe/1f561.svg + Universe/1f562.svg + Universe/1f563.svg + Universe/1f564.svg + Universe/1f565.svg + Universe/1f566.svg + Universe/1f567.svg + Universe/1f595.svg + Universe/1f5fb.svg + Universe/1f5fc.svg + Universe/1f5fd.svg + Universe/1f5fe.svg + Universe/1f5ff.svg + Universe/1f004.svg + Universe/1f0cf.svg + Universe/2600.svg + Universe/2601.svg + Universe/260e.svg + Universe/2611.svg + Universe/2614.svg + Universe/2615.svg + Universe/261d.svg + Universe/2648.svg + Universe/2649.svg + Universe/264a.svg + Universe/264b.svg + Universe/264c.svg + Universe/264d.svg + Universe/264e.svg + Universe/264f.svg + Universe/2650.svg + Universe/2651.svg + Universe/2652.svg + Universe/2653.svg + Universe/2660.svg + Universe/2663.svg + Universe/2665.svg + Universe/2666.svg + Universe/2668.svg + Universe/267b.svg + Universe/267f.svg + Universe/2693.svg + Universe/26a0.svg + Universe/26a1.svg + Universe/26aa.svg + Universe/26ab.svg + Universe/26bd.svg + Universe/26be.svg + Universe/26c4.svg + Universe/26c5.svg + Universe/26ce.svg + Universe/26d4.svg + Universe/26ea.svg + Universe/26f2.svg + Universe/26f3.svg + Universe/26f5.svg + Universe/26fa.svg + Universe/26fd.svg + Universe/1f680.svg + Universe/1f681.svg + Universe/1f682.svg + Universe/1f683.svg + Universe/1f684.svg + Universe/1f685.svg + Universe/1f686.svg + Universe/1f687.svg + Universe/1f688.svg + Universe/1f689.svg + Universe/1f68a.svg + Universe/1f68b.svg + Universe/1f68c.svg + Universe/1f68d.svg + Universe/1f68e.svg + Universe/1f68f.svg + Universe/1f690.svg + Universe/1f691.svg + Universe/1f692.svg + Universe/1f693.svg + Universe/1f694.svg + Universe/1f695.svg + Universe/1f696.svg + Universe/1f697.svg + Universe/1f698.svg + Universe/1f699.svg + Universe/1f69a.svg + Universe/1f69b.svg + Universe/1f69c.svg + Universe/1f69d.svg + Universe/1f69e.svg + Universe/1f69f.svg + Universe/1f6a0.svg + Universe/1f6a1.svg + Universe/1f6a2.svg + Universe/1f6a3.svg + Universe/1f6a4.svg + Universe/1f6a5.svg + Universe/1f6a6.svg + Universe/1f6a7.svg + Universe/1f6a8.svg + Universe/1f6a9.svg + Universe/1f6aa.svg + Universe/1f6ab.svg + Universe/1f6ac.svg + Universe/1f6ad.svg + Universe/1f6ae.svg + Universe/1f6af.svg + Universe/1f6b0.svg + Universe/1f6b1.svg + Universe/1f6b2.svg + Universe/1f6b3.svg + Universe/1f6b4.svg + Universe/1f6b5.svg + Universe/1f6b6.svg + Universe/1f6b7.svg + Universe/1f6b8.svg + Universe/1f6b9.svg + Universe/1f6ba.svg + Universe/1f6bb.svg + Universe/1f6bc.svg + Universe/1f6bd.svg + Universe/1f6be.svg + Universe/1f6bf.svg + Universe/1f6c0.svg + Universe/1f6c1.svg + Universe/1f6c2.svg + Universe/1f6c3.svg + Universe/1f6c4.svg + Universe/1f6c5.svg + Universe/2702.svg + Universe/2705.svg + Universe/2708.svg + Universe/2709.svg + Universe/270a.svg + Universe/270b.svg + Universe/270c.svg + Universe/270f.svg + Universe/2712.svg + Universe/2714.svg + Universe/2716.svg + Universe/2728.svg + Universe/2733.svg + Universe/2734.svg + Universe/2744.svg + Universe/2747.svg + Universe/274c.svg + Universe/274e.svg + Universe/2753.svg + Universe/2754.svg + Universe/2755.svg + Universe/2757.svg + Universe/2764.svg + Universe/2795.svg + Universe/2796.svg + Universe/2797.svg + Universe/27a1.svg + Universe/27b0.svg + Universe/27bf.svg + Universe/2934.svg + Universe/2935.svg + Universe/3030.svg + Universe/3297.svg + Universe/3299.svg + Universe/a9.svg + Universe/ae.svg + Universe/1f21a.svg + Universe/1f22f.svg + Universe/1f23a.svg + Universe/1f201.svg + Universe/1f202.svg + Universe/1f232.svg + Universe/1f233.svg + Universe/1f234.svg + Universe/1f235.svg + Universe/1f236.svg + Universe/1f237.svg + Universe/1f238.svg + Universe/1f239.svg + Universe/1f250.svg + Universe/1f251.svg + Universe/1f170.svg + Universe/1f171.svg + Universe/1f17e.svg + Universe/1f17f.svg + Universe/1f18e.svg + Universe/1f191.svg + Universe/1f192.svg + Universe/1f193.svg + Universe/1f194.svg + Universe/1f195.svg + Universe/1f196.svg + Universe/1f197.svg + Universe/1f198.svg + Universe/1f199.svg + Universe/1f19a.svg + Universe/1f1e6.svg + Universe/1f1e7.svg + Universe/1f1e8.svg + Universe/1f1e9.svg + Universe/1f1ea.svg + Universe/1f1eb.svg + Universe/1f1ec.svg + Universe/1f1ed.svg + Universe/1f1ee.svg + Universe/1f1ef.svg + Universe/1f1f0.svg + Universe/1f1f1.svg + Universe/1f1f2.svg + Universe/1f1f3.svg + Universe/1f1f4.svg + Universe/1f1f5.svg + Universe/1f1f6.svg + Universe/1f1f7.svg + Universe/1f1f8.svg + Universe/1f1f9.svg + Universe/1f1fa.svg + Universe/1f1fb.svg + Universe/1f1fc.svg + Universe/1f1fd.svg + Universe/1f1fe.svg + Universe/1f1ff.svg + Universe/1f1e8-1f1f3.svg + Universe/1f1e9-1f1ea.svg + Universe/1f1ea-1f1f8.svg + Universe/1f1eb-1f1f7.svg + Universe/1f1ec-1f1e7.svg + Universe/1f1ee-1f1f9.svg + Universe/1f1ef-1f1f5.svg + Universe/1f1f0-1f1f7.svg + Universe/1f1f7-1f1fa.svg + Universe/1f1fa-1f1f8.svg + Universe/emoticons.xml + ASCII+Universe/emoticons.xml From 26a3384f5a13820cc351c8ed06ce3530e86ab7ff Mon Sep 17 00:00:00 2001 From: ovalseven8 Date: Sun, 20 Dec 2015 14:28:53 +0100 Subject: [PATCH 040/210] Change order so that there are less problems with displaying unicode characters --- smileys/Basic/emoticons.xml | 50 +++++++++++++++++------------------ smileys/Classic/emoticons.xml | 28 ++++++++++---------- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/smileys/Basic/emoticons.xml b/smileys/Basic/emoticons.xml index 17b5f3bc1..33b2c0682 100644 --- a/smileys/Basic/emoticons.xml +++ b/smileys/Basic/emoticons.xml @@ -3,17 +3,17 @@ - 😇 :angel: 0:) O:) 0:-) O:-) + 😇 - 🍺 :beer: + 🍺 @@ -29,14 +29,13 @@ - 😢 :cry: :'( :,( + 😢 - 😈 :devil: :666: }:-) @@ -44,6 +43,7 @@ ]:-) ]:-> >:-> + 😈 @@ -75,15 +75,15 @@ - <3 :heart: :love: + - 🙋 :hi: + 🙋 @@ -99,31 +99,31 @@ - 😛 :impertinent: :-P :-p :P :p + 😛 - 😍 :inlove: + 😍 - 😙 :kiss: :* :-* + 😙 - 😄 :lol: :D :-D + 😄 @@ -151,12 +151,12 @@ - 🙊 :silence: :-x :-X :x :X + 🙊 @@ -180,8 +180,8 @@ - 🌧 :rain: + 🌧 @@ -192,10 +192,10 @@ - 😞 :sad: :( :-( + 😞 @@ -205,17 +205,17 @@ - 😴 :sleeping: |-) #) + 😴 - :smile: :-) :) + @@ -240,10 +240,10 @@ - 😉 :wink: ;-) ;) + 😉 @@ -256,16 +256,16 @@ - 😆 XD xD + 😆 - 😝 :emoticonmashup: XP xP + 😝 @@ -274,23 +274,23 @@ - 💣 :bomb: + 💣 - 🍪 :cookie: + 🍪 - 🔷 :diamond: + 🔷 - 👁 :eye: + 👁 @@ -299,9 +299,9 @@ - 💉 :syringe: :injection: + 💉 @@ -328,17 +328,17 @@ - 😎 :cool: 8) 8-) + 😎 - 😠 :angry: >:-( >:( + 😠 diff --git a/smileys/Classic/emoticons.xml b/smileys/Classic/emoticons.xml index c6f816f7b..50815abed 100644 --- a/smileys/Classic/emoticons.xml +++ b/smileys/Classic/emoticons.xml @@ -1,85 +1,85 @@ - 😊 :) :-) + 😊 - 😎 8-) 8) + 😎 - 😲 :O :-O + 😲 - 😋 :p :P + 😋 - 😕 :/ :-/ + 😕 - 😉 ;) ;-) + 😉 - 😖 :( :-( + 😖 - 😢 ;( ;-( + 😢 - 😃 :D :-D + 😃 - 😐 :| :-| + 😐 - 😄 ;D ;-D + 😄 - 😠 :@ + 😠 - 😨 D: + 😨 - 😆 xD XD + 😆 From 015a3be2c0b9206142e85722bcab5db937453730 Mon Sep 17 00:00:00 2001 From: ovalseven8 Date: Sun, 20 Dec 2015 15:46:13 +0100 Subject: [PATCH 041/210] Smiley changes: - Removed 'Kappa'-smiley from 'Classic'-pack because it doesn't fit in this pack - Removed 'raw.svg' from 'Classic'-pack because it actually wasn't used - Fixed broken path in Basic/emoticons.xml --- smileys/Basic/emoticons.xml | 5 +- smileys/Classic/Kappa.png | Bin 1242 -> 0 bytes smileys/Classic/emoticons.xml | 4 - smileys/Classic/raw.svg | 889 ---------------------------------- smileys/smileys.qrc | 2 - 5 files changed, 1 insertion(+), 899 deletions(-) delete mode 100644 smileys/Classic/Kappa.png delete mode 100644 smileys/Classic/raw.svg diff --git a/smileys/Basic/emoticons.xml b/smileys/Basic/emoticons.xml index 33b2c0682..6eadedb62 100644 --- a/smileys/Basic/emoticons.xml +++ b/smileys/Basic/emoticons.xml @@ -46,15 +46,13 @@ 😈 - + X. Xo >:. >:° >:o - :dho: - :d'ho: @@ -262,7 +260,6 @@ - :emoticonmashup: XP xP 😝 diff --git a/smileys/Classic/Kappa.png b/smileys/Classic/Kappa.png deleted file mode 100644 index a7ebbec4d90af0efba51de1a263d08793ce3a67a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1242 zcmeAS@N?(olHy`uVBq!ia0vp^l0YoO!2%@hbniq1DW)WEcNYeRRlUkaKptm-M`SUO z_5fqIli7Aa6^A`t978NlmtOJCo|7uk@bLBQmn!jUlYP?E)K+$?nO&e-OZw?oizWA8?#p0*xnjemD)|Aek7ijS0@{5&Eu5VbPmhBpTYemmI z)75Y@A8(s2wX8>D=OcC9%JWv{ z3gL%cHLuS-Hcxl^lu}XMij$g)laiB+<0K|*Uu1un)v>AR`<$)M_N^24)7qKgace{7 z(PsYBGfPiSv5ibVHYZ^EMPbj`+m~uw3$pf5^VMFl`t@mvNt41a1|C_mrzg?cjBiq> zhU~9jm#n0AHFd4pGp&$6WJ~XjYc?JkS;~v^<6T3~f1b52<94X|+RXPC_x@8a4B@MM z+@vV{YtyG7G2NR2U#7Y&I@}VzID4V0_9WxH!={e+_eBKX+R^5}=r~8Ibx~5N^Ng^~ zYm^MvX1u*vZ!5U;y_3>n?TVvwLQ_{)b(Q7(QmXPg{=;a(c8%q$(xQV??ml;S%`}K_ zU$cjkwKlpeq^3rp&Rs~ay|&iU@$9_wd{;lk>zWCB&W*|x0H$lz64!{5l*E!$tK_0o zAjM#0U}&UkV61Ck7Gh{>WngS&Y^rNuVP#;zu(-L1;F+74p6Z*Jo|&AjV5SFzx<(2>D-CqPwkiY~nki(IloVL$>z9|8>t%ve z12IswUVc%!gP83hpotP76GJjebCayBT=J7kb5rw5tgHfnN{bl`m;c|b4^$(Lqy}uK zl~qP+W_m^mgONq>=|vnsC1RLL!ZTA!G8l|Z!&TXD 😆 - - - :Kappa: - diff --git a/smileys/Classic/raw.svg b/smileys/Classic/raw.svg deleted file mode 100644 index 8ca952f95..000000000 --- a/smileys/Classic/raw.svg +++ /dev/null @@ -1,889 +0,0 @@ - - - - - qTox - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - qTox - - Created for the qTox project. Inspired by the "Never mind!" smiley pack. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/smileys/smileys.qrc b/smileys/smileys.qrc index 37389d377..6c6551ac2 100644 --- a/smileys/smileys.qrc +++ b/smileys/smileys.qrc @@ -60,11 +60,9 @@ Classic/crying.png Classic/emoticons.xml Classic/happy.png - Classic/Kappa.png Classic/laugh_closed_eyes.png Classic/laugh.png Classic/plain.png - Classic/raw.svg Classic/sad.png Classic/scared.png Classic/smile.png From 00fa6abc2f051407d2d3de6e1fc7f59a338d7ac8 Mon Sep 17 00:00:00 2001 From: ovalseven8 Date: Sun, 20 Dec 2015 15:51:39 +0100 Subject: [PATCH 042/210] The color of the eight smileys is black now. All smileys are visible, now. --- smileys/Universe/2714.svg | 2 +- smileys/Universe/2716.svg | 2 +- smileys/Universe/2734.svg | 2 +- smileys/Universe/2795.svg | 2 +- smileys/Universe/2796.svg | 2 +- smileys/Universe/2797.svg | 2 +- smileys/Universe/27b0.svg | 2 +- smileys/Universe/3030.svg | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/smileys/Universe/2714.svg b/smileys/Universe/2714.svg index 3f9830983..83292c0a2 100644 --- a/smileys/Universe/2714.svg +++ b/smileys/Universe/2714.svg @@ -1 +1 @@ - + diff --git a/smileys/Universe/2716.svg b/smileys/Universe/2716.svg index f071a1ec0..ef06926d5 100644 --- a/smileys/Universe/2716.svg +++ b/smileys/Universe/2716.svg @@ -1 +1 @@ - + diff --git a/smileys/Universe/2734.svg b/smileys/Universe/2734.svg index c68890aa9..4e9a9c369 100644 --- a/smileys/Universe/2734.svg +++ b/smileys/Universe/2734.svg @@ -1 +1 @@ - + diff --git a/smileys/Universe/2795.svg b/smileys/Universe/2795.svg index ac849de68..32718f465 100644 --- a/smileys/Universe/2795.svg +++ b/smileys/Universe/2795.svg @@ -1 +1 @@ - + diff --git a/smileys/Universe/2796.svg b/smileys/Universe/2796.svg index 6183aba1d..8865ee2e9 100644 --- a/smileys/Universe/2796.svg +++ b/smileys/Universe/2796.svg @@ -1 +1 @@ - + diff --git a/smileys/Universe/2797.svg b/smileys/Universe/2797.svg index 810aba7ff..acfb43d7a 100644 --- a/smileys/Universe/2797.svg +++ b/smileys/Universe/2797.svg @@ -1 +1 @@ - + diff --git a/smileys/Universe/27b0.svg b/smileys/Universe/27b0.svg index 81823c7c5..1fd2f3448 100644 --- a/smileys/Universe/27b0.svg +++ b/smileys/Universe/27b0.svg @@ -1 +1 @@ - + diff --git a/smileys/Universe/3030.svg b/smileys/Universe/3030.svg index ae9131376..4934ae305 100644 --- a/smileys/Universe/3030.svg +++ b/smileys/Universe/3030.svg @@ -1 +1 @@ - + From 19201dda8a0333c19fed52bdb1da9f5db15a3146 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sun, 20 Dec 2015 23:10:03 +0100 Subject: [PATCH 043/210] Merge pull request #2713 from antis81:newav_audio_cleanup --- src/audio/audio.cpp | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index d444b5654..5d67c6917 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -181,8 +181,8 @@ public: cleanupOutput(); } - bool initInput(const QString& inDevDescr); - bool initOutput(const QString& outDevDescr); + bool initInput(QString inDevDescr); + bool initOutput(QString outDevDescr); void cleanupInput(); void cleanupOutput(); @@ -406,7 +406,7 @@ void Audio::unsubscribeInput() d->cleanupInput(); } -bool AudioPrivate::initInput(const QString& inDevDescr) +bool AudioPrivate::initInput(QString inDevDescr) { qDebug() << "Opening audio input" << inDevDescr; @@ -430,11 +430,11 @@ bool AudioPrivate::initInput(const QString& inDevDescr) alInDev = alcCaptureOpenDevice(pDeviceList, sampleRate, stereoFlag, bufSize); int len = strlen(pDeviceList); #ifdef Q_OS_WIN - QString inDev = QString::fromUtf8(pDeviceList, len); + inDevDescr = QString::fromUtf8(pDeviceList, len); #else - QString inDev = QString::fromLocal8Bit(pDeviceList, len); + inDevDescr = QString::fromLocal8Bit(pDeviceList, len); #endif - Settings::getInstance().setInDev(inDev); + Settings::getInstance().setInDev(inDevDescr); } else { @@ -445,13 +445,9 @@ bool AudioPrivate::initInput(const QString& inDevDescr) alInDev = alcCaptureOpenDevice(inDevDescr.toStdString().c_str(), sampleRate, stereoFlag, bufSize); - if (alInDev) - qDebug() << "Opened audio input" << inDevDescr; - else - qWarning() << "Cannot open input audio device" << inDevDescr; - // Restart the capture if necessary if (alInDev) { + qDebug() << "Opened audio input" << inDevDescr; alcCaptureStart(alInDev); } else { qCritical() << "Failed to initialize audio input device:" << inDevDescr; @@ -467,7 +463,7 @@ bool AudioPrivate::initInput(const QString& inDevDescr) Open an audio output device */ -bool AudioPrivate::initOutput(const QString& outDevDescr) +bool AudioPrivate::initOutput(QString outDevDescr) { qDebug() << "Opening audio output" << outDevDescr; outSources.clear(); @@ -491,11 +487,11 @@ bool AudioPrivate::initOutput(const QString& outDevDescr) alOutDev = alcOpenDevice(pDeviceList); int len = strlen(pDeviceList); #ifdef Q_OS_WIN - QString outDev = QString::fromUtf8(pDeviceList, len); + outDevDescr = QString::fromUtf8(pDeviceList, len); #else - QString outDev = QString::fromLocal8Bit(pDeviceList, len); + outDevDescr = QString::fromLocal8Bit(pDeviceList, len); #endif - Settings::getInstance().setOutDev(outDev); + Settings::getInstance().setOutDev(outDevDescr); } else { @@ -747,7 +743,7 @@ void Audio::subscribeOutput(SID& sid) if (!d->alOutDev) { if (!d->initOutput(Settings::getInstance().getOutDev())) { - qWarning("Failed to subscribe to audio input device."); + qWarning("Failed to subscribe to audio output device."); return; } } From b01f47b1aa5c82b7172bcee05e72a855c37d89dd Mon Sep 17 00:00:00 2001 From: tux3 Date: Mon, 21 Dec 2015 01:14:09 +0100 Subject: [PATCH 044/210] Use pre Qt5.4 QTimer::singleShot For compatibility with Debian Jessie --- src/widget/tool/screenshotgrabber.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widget/tool/screenshotgrabber.cpp b/src/widget/tool/screenshotgrabber.cpp index a9bd01304..83120be82 100644 --- a/src/widget/tool/screenshotgrabber.cpp +++ b/src/widget/tool/screenshotgrabber.cpp @@ -110,7 +110,7 @@ bool ScreenshotGrabber::handleKeyPress(QKeyEvent* event) restoreHiddenWindows(); window->hide(); - QTimer::singleShot(350, this, &ScreenshotGrabber::reInit); + QTimer::singleShot(350, this, SLOT(reInit())); } else return false; From cf6623cfc8a50a9d1fdd3e7293ccd13abc23c198 Mon Sep 17 00:00:00 2001 From: Andrew Novikov Date: Sun, 20 Dec 2015 22:17:14 +0300 Subject: [PATCH 045/210] Implemented enumeration of video devices. --- qtox.pro | 8 ++++-- src/platform/camera/avfoundation.h | 37 +++++++++++++++++++++++++ src/platform/camera/avfoundation.mm | 42 +++++++++++++++++++++++++++++ src/video/cameradevice.cpp | 7 +++++ 4 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 src/platform/camera/avfoundation.h create mode 100644 src/platform/camera/avfoundation.mm diff --git a/qtox.pro b/qtox.pro index 2cc0f86ec..cad757550 100644 --- a/qtox.pro +++ b/qtox.pro @@ -159,7 +159,7 @@ win32 { ICON = img/icons/qtox.icns QMAKE_INFO_PLIST = osx/info.plist QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.7 - LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lsodium -lvpx -lopus -framework OpenAL -lavformat -lavdevice -lavcodec -lavutil -lswscale -mmacosx-version-min=10.7 + LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lsodium -lvpx -lopus -framework OpenAL -lavformat -lavdevice -lavcodec -lavutil -lswscale -framework AVFoundation -framework Foundation -mmacosx-version-min=10.7 LIBS += -lqrencode -lsqlcipher contains(DEFINES, QTOX_PLATFORM_EXT) { LIBS += -framework IOKit -framework CoreFoundation } contains(DEFINES, QTOX_FILTER_AUDIO) { LIBS += -lfilteraudio } @@ -462,7 +462,11 @@ macx { src/platform/install_osx.cpp HEADERS += \ - src/platform/install_osx.h + src/platform/install_osx.h \ + src/platform/camera/avfoundation.h + + OBJECTIVE_SOURCES += \ + src/platform/camera/avfoundation.mm } SOURCES += \ diff --git a/src/platform/camera/avfoundation.h b/src/platform/camera/avfoundation.h new file mode 100644 index 000000000..942074eca --- /dev/null +++ b/src/platform/camera/avfoundation.h @@ -0,0 +1,37 @@ +/* + Copyright © 2015 by The qTox Project + + This file is part of qTox, a Qt-based graphical interface for Tox. + + qTox is libre software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + qTox is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with qTox. If not, see . +*/ +#ifndef AVFOUNDATION_H +#define AVFOUNDATION_H + +#include +#include +#include +#include "src/video/videomode.h" + +#ifndef Q_OS_MACX +#error "This file is only meant to be compiled for Mac OS X targets" +#endif + +namespace avfoundation +{ + QVector getDeviceModes(QString devName); + QVector> getDeviceList(); +} + +#endif // AVFOUNDATION_H diff --git a/src/platform/camera/avfoundation.mm b/src/platform/camera/avfoundation.mm new file mode 100644 index 000000000..ce008b9e7 --- /dev/null +++ b/src/platform/camera/avfoundation.mm @@ -0,0 +1,42 @@ +/* + Copyright (c) 2014 Thilo Borgmann + Copyright © 2015 by The qTox Project + + This file is part of qTox, a Qt-based graphical interface for Tox. + + qTox is libre software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + qTox is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with qTox. If not, see . + */ + +#include "avfoundation.h" + +#import + +QVector > avfoundation::getDeviceList() +{ + QVector > result; + + NSArray* devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; + for (AVCaptureDevice* device in devices) { + result.append({ QString::number([devices indexOfObject:device]), [[device localizedName] UTF8String] }); + } + + return result; +} + +QVector avfoundation::getDeviceModes(QString devName) +{ + QVector result; + + return result; +} diff --git a/src/video/cameradevice.cpp b/src/video/cameradevice.cpp index 96c1ec3fa..23869f2c9 100644 --- a/src/video/cameradevice.cpp +++ b/src/video/cameradevice.cpp @@ -34,6 +34,9 @@ extern "C" { #ifdef Q_OS_LINUX #include "src/platform/camera/v4l2.h" #endif +#ifdef Q_OS_OSX +#include "src/platform/camera/avfoundation.h" +#endif QHash CameraDevice::openDevices; QMutex CameraDevice::openDeviceLock, CameraDevice::iformatLock; @@ -281,6 +284,10 @@ QVector> CameraDevice::getDeviceList() #ifdef Q_OS_LINUX else if (iformat->name == QString("video4linux2,v4l2")) devices += v4l2::getDeviceList(); +#endif +#ifdef Q_OS_OSX + else if (iformat->name == QString("avfoundation")) + devices += avfoundation::getDeviceList(); #endif else devices += getRawDeviceListGeneric(); From 1dac0d09c8fe172e73325d52f79bd5d1fa32ee76 Mon Sep 17 00:00:00 2001 From: Andrew Novikov Date: Sun, 20 Dec 2015 22:22:56 +0300 Subject: [PATCH 046/210] Rearranged link dependencies. --- qtox.pro | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qtox.pro b/qtox.pro index cad757550..19b2817eb 100644 --- a/qtox.pro +++ b/qtox.pro @@ -159,7 +159,8 @@ win32 { ICON = img/icons/qtox.icns QMAKE_INFO_PLIST = osx/info.plist QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.7 - LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lsodium -lvpx -lopus -framework OpenAL -lavformat -lavdevice -lavcodec -lavutil -lswscale -framework AVFoundation -framework Foundation -mmacosx-version-min=10.7 + LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lsodium -lvpx -lopus -framework OpenAL -lavformat -lavdevice -lavcodec -lavutil -lswscale -mmacosx-version-min=10.7 + LIBS += -framework AVFoundation -framework Foundation LIBS += -lqrencode -lsqlcipher contains(DEFINES, QTOX_PLATFORM_EXT) { LIBS += -framework IOKit -framework CoreFoundation } contains(DEFINES, QTOX_FILTER_AUDIO) { LIBS += -lfilteraudio } From 9d430626397bb66021949985d9ebbd099870cdea Mon Sep 17 00:00:00 2001 From: Andrew Novikov Date: Mon, 21 Dec 2015 00:44:53 +0300 Subject: [PATCH 047/210] Changed the type of VideoMode::FPS to float: this is necessary for Mac OS X which uses frame rates like 29.97 --- src/video/videomode.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/videomode.h b/src/video/videomode.h index ff76c063b..d3e17f98b 100644 --- a/src/video/videomode.h +++ b/src/video/videomode.h @@ -25,7 +25,7 @@ struct VideoMode { unsigned short width, height; ///< Displayed video resolution (NOT frame resolution) - unsigned short FPS; ///< Max frames per second supported by the device at this resolution + float FPS; ///< Max frames per second supported by the device at this resolution /// All zeros means a default/unspecified mode operator bool() const From cc64db3f275563dd83225cf61bcc7eac6cf85cba Mon Sep 17 00:00:00 2001 From: Andrew Novikov Date: Mon, 21 Dec 2015 00:50:51 +0300 Subject: [PATCH 048/210] Implemented listing and setting video modes on Mac OS X --- qtox.pro | 2 +- src/platform/camera/avfoundation.mm | 30 ++++++++++++++++++++++++++++- src/video/cameradevice.cpp | 11 +++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/qtox.pro b/qtox.pro index 19b2817eb..960a78412 100644 --- a/qtox.pro +++ b/qtox.pro @@ -160,7 +160,7 @@ win32 { QMAKE_INFO_PLIST = osx/info.plist QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.7 LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lsodium -lvpx -lopus -framework OpenAL -lavformat -lavdevice -lavcodec -lavutil -lswscale -mmacosx-version-min=10.7 - LIBS += -framework AVFoundation -framework Foundation + LIBS += -framework AVFoundation -framework Foundation -framework CoreMedia LIBS += -lqrencode -lsqlcipher contains(DEFINES, QTOX_PLATFORM_EXT) { LIBS += -framework IOKit -framework CoreFoundation } contains(DEFINES, QTOX_FILTER_AUDIO) { LIBS += -lfilteraudio } diff --git a/src/platform/camera/avfoundation.mm b/src/platform/camera/avfoundation.mm index ce008b9e7..5f625e17e 100644 --- a/src/platform/camera/avfoundation.mm +++ b/src/platform/camera/avfoundation.mm @@ -28,7 +28,7 @@ QVector > avfoundation::getDeviceList() NSArray* devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; for (AVCaptureDevice* device in devices) { - result.append({ QString::number([devices indexOfObject:device]), [[device localizedName] UTF8String] }); + result.append({ QString::fromUtf8([[device uniqueID] UTF8String]), QString::fromUtf8([[device localizedName] UTF8String]) }); } return result; @@ -38,5 +38,33 @@ QVector avfoundation::getDeviceModes(QString devName) { QVector result; + NSArray* devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; + AVCaptureDevice* device = nil; + + for (AVCaptureDevice* dev in devices) { + if (devName == QString::fromUtf8([[dev uniqueID] UTF8String])) { + device = dev; + break; + } + } + if (device == nil) { + return result; + } + + for (AVCaptureDeviceFormat* format in [device formats]) { + CMFormatDescriptionRef formatDescription; + CMVideoDimensions dimensions; + formatDescription = (CMFormatDescriptionRef)[format performSelector:@selector(formatDescription)]; + dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription); + + for (AVFrameRateRange* range in format.videoSupportedFrameRateRanges) { + VideoMode mode; + mode.width = dimensions.width; + mode.height = dimensions.height; + mode.FPS = range.maxFrameRate; + result.append(mode); + } + } + return result; } diff --git a/src/video/cameradevice.cpp b/src/video/cameradevice.cpp index 23869f2c9..d9cab566a 100644 --- a/src/video/cameradevice.cpp +++ b/src/video/cameradevice.cpp @@ -165,6 +165,13 @@ CameraDevice* CameraDevice::open(QString devName, VideoMode mode) av_dict_set(&options, "video_size", QString("%1x%2").arg(mode.width).arg(mode.height).toStdString().c_str(), 0); av_dict_set(&options, "framerate", QString().setNum(mode.FPS).toStdString().c_str(), 0); } +#endif +#ifdef Q_OS_OSX + else if (iformat->name == QString("avfoundation") && mode) + { + av_dict_set(&options, "video_size", QString("%1x%2").arg(mode.width).arg(mode.height).toStdString().c_str(), 0); + av_dict_set(&options, "framerate", QString().setNum(mode.FPS).toStdString().c_str(), 0); + } #endif else if (mode) { @@ -331,6 +338,10 @@ QVector CameraDevice::getVideoModes(QString devName) #ifdef Q_OS_LINUX else if (iformat->name == QString("video4linux2,v4l2")) return v4l2::getDeviceModes(devName); +#endif +#ifdef Q_OS_OSX + else if (iformat->name == QString("avfoundation")) + return avfoundation::getDeviceModes(devName); #endif else qWarning() << "Video mode listing not implemented for input "<name; From e5baa403e08bea1d2686dc66154625bc2b2c0bde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20L=C3=B6thberg?= Date: Mon, 21 Dec 2015 06:02:32 +0100 Subject: [PATCH 049/210] Add SVG support to filetransfer preview MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only requires Qt SVG which is already a dependency of qTox. Signed-off-by: Johannes Löthberg --- src/chatlog/content/filetransferwidget.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/chatlog/content/filetransferwidget.cpp b/src/chatlog/content/filetransferwidget.cpp index 0ced90852..8021ce0e6 100644 --- a/src/chatlog/content/filetransferwidget.cpp +++ b/src/chatlog/content/filetransferwidget.cpp @@ -496,7 +496,8 @@ void FileTransferWidget::handleButton(QPushButton *btn) void FileTransferWidget::showPreview(const QString &filename) { - static const QStringList previewExtensions = { "png", "jpeg", "jpg", "gif", "PNG", "JPEG", "JPG", "GIF" }; + static const QStringList previewExtensions = { "png", "jpeg", "jpg", "gif", "svg", + "PNG", "JPEG", "JPG", "GIF", "SVG" }; if (previewExtensions.contains(QFileInfo(filename).suffix())) { From 3f4c21216a6aa04f52c39c53086ec3648f41dea4 Mon Sep 17 00:00:00 2001 From: Jacob Henner Date: Mon, 14 Dec 2015 22:35:12 -0500 Subject: [PATCH 050/210] Fixes #2629: avatars will be re-encrypted when the profile password changes --- src/persistence/profile.cpp | 15 ++++++++++++++- src/persistence/profile.h | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/persistence/profile.cpp b/src/persistence/profile.cpp index 8849bad3f..39af9dec5 100644 --- a/src/persistence/profile.cpp +++ b/src/persistence/profile.cpp @@ -363,6 +363,11 @@ QPixmap Profile::loadAvatar(const QString &ownerId) } QByteArray Profile::loadAvatarData(const QString &ownerId) +{ + return loadAvatarData(ownerId, password); +} + +QByteArray Profile::loadAvatarData(const QString &ownerId, const QString &password) { QString path = avatarPath(ownerId); bool encrypted = !password.isEmpty(); @@ -554,7 +559,7 @@ void Profile::restartCore() void Profile::setPassword(QString newPassword) { QByteArray avatar = loadAvatarData(core->getSelfId().publicKey); - + QString oldPassword = password; password = newPassword; passkey = *core->createPasskey(password); saveToxSave(); @@ -565,4 +570,12 @@ void Profile::setPassword(QString newPassword) Nexus::getDesktopGUI()->reloadHistory(); } saveAvatar(avatar, core->getSelfId().publicKey); + + QVector friendList = core->getFriendList(); + QVectorIterator i(friendList); + while (i.hasNext()) + { + QString friendPublicKey = core->getFriendPublicKey(i.next()); + saveAvatar(loadAvatarData(friendPublicKey,oldPassword),friendPublicKey); + } } diff --git a/src/persistence/profile.h b/src/persistence/profile.h index 4f4e454d4..0fa295d1a 100644 --- a/src/persistence/profile.h +++ b/src/persistence/profile.h @@ -64,6 +64,7 @@ public: QPixmap loadAvatar(); ///< Get our avatar from cache QPixmap loadAvatar(const QString& ownerId); ///< Get a contact's avatar from cache QByteArray loadAvatarData(const QString& ownerId); ///< Get a contact's avatar from cache + QByteArray loadAvatarData(const QString& ownerId, const QString& password); ///< Get a contact's avatar from cache, with a specified profile password. void saveAvatar(QByteArray pic, const QString& ownerId); ///< Save an avatar to cache QByteArray getAvatarHash(const QString& ownerId); ///< Get the tox hash of a cached avatar void removeAvatar(const QString& ownerId); ///< Removes a cached avatar From e9b34f5154cdccf9709c55c7a30d53fc70e83e0a Mon Sep 17 00:00:00 2001 From: Jacob Henner Date: Mon, 21 Dec 2015 04:14:23 -0500 Subject: [PATCH 051/210] Fixes #2686 - Profiles will store avatars in distinct files --- src/persistence/profile.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/persistence/profile.cpp b/src/persistence/profile.cpp index 39af9dec5..a69757a19 100644 --- a/src/persistence/profile.cpp +++ b/src/persistence/profile.cpp @@ -342,11 +342,14 @@ QString Profile::avatarPath(const QString &ownerId, bool forceUnencrypted) return Settings::getInstance().getSettingsDirPath() + "avatars/" + ownerId + ".png"; QByteArray idData = ownerId.toUtf8(); - constexpr int hashSize = TOX_PUBLIC_KEY_SIZE; // As long as an unencrypted hash + QByteArray pubkeyData = core->getSelfId().publicKey.toUtf8(); + constexpr int hashSize = TOX_PUBLIC_KEY_SIZE; static_assert(hashSize >= crypto_generichash_BYTES_MIN && hashSize <= crypto_generichash_BYTES_MAX, "Hash size not supported by libsodium"); + static_assert(hashSize >= crypto_generichash_KEYBYTES_MIN + && hashSize <= crypto_generichash_KEYBYTES_MAX, "Key size not supported by libsodium"); QByteArray hash(hashSize, 0); - crypto_generichash((uint8_t*)hash.data(), hashSize, (uint8_t*)idData.data(), idData.size(), nullptr, 0); + crypto_generichash((uint8_t*)hash.data(), hashSize, (uint8_t*)idData.data(), idData.size(), (uint8_t*)pubkeyData.data(), pubkeyData.size()); return Settings::getInstance().getSettingsDirPath() + "avatars/" + hash.toHex().toUpper() + ".png"; } From d3e266b71b064f9b5be0c34976284325ee04dd2e Mon Sep 17 00:00:00 2001 From: Rowen Stipe Date: Mon, 21 Dec 2015 12:11:20 -0500 Subject: [PATCH 052/210] Updated bootstrap-sox for sqlcipher Updated the bootstrap file for use with sqlcipher. --- bootstrap-osx.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) mode change 100644 => 100755 bootstrap-osx.sh diff --git a/bootstrap-osx.sh b/bootstrap-osx.sh old mode 100644 new mode 100755 index a962e1044..3b6eba2eb --- a/bootstrap-osx.sh +++ b/bootstrap-osx.sh @@ -29,13 +29,15 @@ cp /usr/local/lib/libav* libs/lib cp /usr/local/lib/libswscale* libs/lib cp /usr/local/lib/libqrencode* libs/lib cp /usr/local/lib/libfilteraudio* libs/lib -cp /usr/local/include/filter_audio* libs/include +cp /usr/local/lib/libsqlcipher* libs/lib echo Copying include files... +cp /usr/local/include/filter_audio* libs/include cp -r /usr/local/include/tox* libs/include cp -r /usr/local/include/vpx* libs/include cp -r /usr/local/include/sodium* libs/include cp -r /usr/local/include/qrencode* libs/include cp -r /usr/local/include/libav* libs/include cp -r /usr/local/include/libswscale* libs/include +cp -r /usr/local/include/sqlcipher* libs/include echo Done. From f61332bc565730e82ea6af11d18163056c135519 Mon Sep 17 00:00:00 2001 From: tux3 Date: Mon, 21 Dec 2015 20:16:48 +0100 Subject: [PATCH 053/210] Fix bad casts in updater code --- updater/serialize.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/updater/serialize.cpp b/updater/serialize.cpp index e3511cafa..a00e3dcac 100644 --- a/updater/serialize.cpp +++ b/updater/serialize.cpp @@ -157,18 +157,18 @@ QByteArray rangedSingleToData(float value, float min, float max, int numberOfBit numberOfBits -= 8; if (numberOfBits <= 8) { - data += (unsigned char)source>>8; + data += (unsigned char)(source>>8); return data; } - data += (unsigned char)source>>8; + data += (unsigned char)(source>>8); numberOfBits -= 8; if (numberOfBits <= 8) { - data += (unsigned char)source>>16; + data += (unsigned char)(source>>16); return data; } - data += (unsigned char)source>>16; - data += (unsigned char)source>>24; + data += (unsigned char)(source>>16); + data += (unsigned char)(source>>24); return data; } From 056a77d4dd0eaeea7273b87be82218a5d1d7bca4 Mon Sep 17 00:00:00 2001 From: rku Date: Tue, 22 Dec 2015 14:48:52 +0200 Subject: [PATCH 054/210] Cleaned up all the ipc/startup code: * Removed duplicate code of ipc event sending * Removed duplicate code of profile loading * Fixed bug where activating existing instance still started new instance of qtox asking to select a profile * IPC messages are now profile-aware and are sent to instance that runs specified profile in -p flag or to ipc owner if -p is not specified. If -p flag is specified ipc events will be send to instance which runs specified profile. If instance using that profile does not run - new qTox instance will be started. This works with password-protected profiles too - new instance will handle "uri" or "save" events after accepting user password. --- src/ipc.cpp | 3 +- src/main.cpp | 100 +++++++++++++++---------------------- src/persistence/settings.h | 3 +- 3 files changed, 44 insertions(+), 62 deletions(-) diff --git a/src/ipc.cpp b/src/ipc.cpp index a959d6596..f2d6314b8 100644 --- a/src/ipc.cpp +++ b/src/ipc.cpp @@ -186,7 +186,8 @@ bool IPC::waitUntilAccepted(time_t postTime, int32_t timeout/*=-1*/) { bool result = false; time_t start = time(0); - forever { + forever + { result = isEventAccepted(postTime); if (result || (timeout > 0 && difftime(time(0), start) >= timeout)) break; diff --git a/src/main.cpp b/src/main.cpp index 57ddadc14..324dc418c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -157,105 +157,85 @@ int main(int argc, char *argv[]) #endif + QString profileName; + bool autoLogin = Settings::getInstance().getAutoLogin(); #ifndef Q_OS_ANDROID // Inter-process communication ipc.registerEventHandler("uri", &toxURIEventHandler); ipc.registerEventHandler("save", &toxSaveEventHandler); ipc.registerEventHandler("activate", &toxActivateEventHandler); + uint32_t ipcDest = 0; + QString eventType, firstParam; if (parser.isSet("p")) { - QString profileName = parser.value("p"); - if (Profile::exists(profileName)) - { - qDebug() << "Setting profile to" << profileName; - if (Profile::isEncrypted(profileName)) - { - Settings::getInstance().setCurrentProfile(profileName); - } - else - { - Profile* profile = Profile::loadProfile(profileName); - if (!profile) - { - qCritical() << "-p profile" << profileName + ".tox" << " couldn't be loaded"; - return EXIT_FAILURE; - } - Nexus::getInstance().setProfile(profile); - } - } - else + profileName = parser.value("p"); + if (!Profile::exists(profileName)) { qCritical() << "-p profile" << profileName + ".tox" << "doesn't exist"; return EXIT_FAILURE; } + ipcDest = Settings::makeProfileId(profileName); + autoLogin = true; } + else + profileName = Settings::getInstance().getCurrentProfile(); - if (parser.positionalArguments().size() > 0) + if (parser.positionalArguments().size() == 0) + eventType = "activate"; + else { - QString firstParam(parser.positionalArguments()[0]); + firstParam = parser.positionalArguments()[0]; // Tox URIs. If there's already another qTox instance running, we ask it to handle the URI and we exit // Otherwise we start a new qTox instance and process it ourselves if (firstParam.startsWith("tox:")) - { - if (ipc.isCurrentOwner()) // Don't bother sending an event if we're going to process it ourselves - { - handleToxURI(firstParam.toUtf8()); - } - else - { - time_t event = ipc.postEvent("uri", firstParam.toUtf8()); - ipc.waitUntilAccepted(event); - // If someone else processed it, we're done here, no need to actually start qTox - if (!ipc.isCurrentOwner()) - return EXIT_SUCCESS; - } - } + eventType = "uri"; else if (firstParam.endsWith(".tox")) - { - if (ipc.isCurrentOwner()) // Don't bother sending an event if we're going to process it ourselves - { - handleToxSave(firstParam.toUtf8()); - } - else - { - time_t event = ipc.postEvent("save", firstParam.toUtf8()); - ipc.waitUntilAccepted(event); - // If someone else processed it, we're done here, no need to actually start qTox - if (!ipc.isCurrentOwner()) - return EXIT_SUCCESS; - } - } + eventType = "save"; else { - fprintf(stderr, "Invalid argument\n"); + qCritical() << "Invalid argument"; return EXIT_FAILURE; } } - else if (!ipc.isCurrentOwner() && !parser.isSet("p")) + + if (!ipc.isCurrentOwner()) { - time_t event = ipc.postEvent("activate"); - if (!ipc.waitUntilAccepted(event, 2)) + time_t event = ipc.postEvent(eventType, firstParam.toUtf8(), ipcDest); + // If someone else processed it, we're done here, no need to actually start qTox + if (ipc.waitUntilAccepted(event, 2)) { + qDebug() << "Event" << eventType << "was handled by other client."; return EXIT_SUCCESS; } } #endif // Autologin - if (Settings::getInstance().getAutoLogin()) + if (autoLogin) { - QString profileName = Settings::getInstance().getCurrentProfile(); - if (Profile::exists(profileName) && !Profile::isEncrypted(profileName)) + if (Profile::exists(profileName)) { - Profile* profile = Profile::loadProfile(profileName); - if (profile) - Nexus::getInstance().setProfile(profile); + if (!Profile::isEncrypted(profileName)) + { + Profile* profile = Profile::loadProfile(profileName); + if (profile) + Nexus::getInstance().setProfile(profile); + } + Settings::getInstance().setCurrentProfile(profileName); } } Nexus::getInstance().start(); +#ifndef Q_OS_ANDROID + // Event was not handled by already running instance therefore we handle it ourselves + if (eventType == "uri") + handleToxURI(firstParam.toUtf8()); + else if (eventType == "save") + handleToxSave(firstParam.toUtf8()); +#endif + // Run int errorcode = a.exec(); diff --git a/src/persistence/settings.h b/src/persistence/settings.h index c86b7bab5..23c466370 100644 --- a/src/persistence/settings.h +++ b/src/persistence/settings.h @@ -294,12 +294,13 @@ public: setWidgetData(widget->objectName() + "State", widget->saveState()); } + static uint32_t makeProfileId(const QString& profile); + private: Settings(); ~Settings(); Settings(Settings &settings) = delete; Settings& operator=(const Settings&) = delete; - static uint32_t makeProfileId(const QString& profile); private slots: void savePersonal(QString profileName, QString password); From bd8a2c84efd1c55804357be2897d3a2766e502b1 Mon Sep 17 00:00:00 2001 From: Andrew Novikov Date: Wed, 23 Dec 2015 11:03:56 +0300 Subject: [PATCH 055/210] Optimized working with strings --- src/platform/camera/avfoundation.mm | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/platform/camera/avfoundation.mm b/src/platform/camera/avfoundation.mm index 5f625e17e..76f6fd62b 100644 --- a/src/platform/camera/avfoundation.mm +++ b/src/platform/camera/avfoundation.mm @@ -28,7 +28,7 @@ QVector > avfoundation::getDeviceList() NSArray* devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; for (AVCaptureDevice* device in devices) { - result.append({ QString::fromUtf8([[device uniqueID] UTF8String]), QString::fromUtf8([[device localizedName] UTF8String]) }); + result.append({ QString::fromNSString([device uniqueID]), QString::fromNSString([device localizedName]) }); } return result; @@ -38,15 +38,9 @@ QVector avfoundation::getDeviceModes(QString devName) { QVector result; - NSArray* devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; - AVCaptureDevice* device = nil; + NSString* deviceName = [NSString stringWithCString:devName.toUtf8() encoding:NSUTF8StringEncoding]; + AVCaptureDevice* device = [AVCaptureDevice deviceWithUniqueID:deviceName]; - for (AVCaptureDevice* dev in devices) { - if (devName == QString::fromUtf8([[dev uniqueID] UTF8String])) { - device = dev; - break; - } - } if (device == nil) { return result; } From 985def25ff59c7060e0c7c8e655cb88a41ededa7 Mon Sep 17 00:00:00 2001 From: Andrew Novikov Date: Wed, 23 Dec 2015 15:31:28 +0300 Subject: [PATCH 056/210] Implemented screen capturing support for Mac OS X --- qtox.pro | 2 +- src/platform/camera/avfoundation.h | 2 ++ src/platform/camera/avfoundation.mm | 46 +++++++++++++++++++---------- src/video/cameradevice.cpp | 15 ++++++++-- 4 files changed, 46 insertions(+), 19 deletions(-) diff --git a/qtox.pro b/qtox.pro index 960a78412..84ffa9dc8 100644 --- a/qtox.pro +++ b/qtox.pro @@ -160,7 +160,7 @@ win32 { QMAKE_INFO_PLIST = osx/info.plist QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.7 LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lsodium -lvpx -lopus -framework OpenAL -lavformat -lavdevice -lavcodec -lavutil -lswscale -mmacosx-version-min=10.7 - LIBS += -framework AVFoundation -framework Foundation -framework CoreMedia + LIBS += -framework AVFoundation -framework Foundation -framework CoreMedia -framework ApplicationServices LIBS += -lqrencode -lsqlcipher contains(DEFINES, QTOX_PLATFORM_EXT) { LIBS += -framework IOKit -framework CoreFoundation } contains(DEFINES, QTOX_FILTER_AUDIO) { LIBS += -lfilteraudio } diff --git a/src/platform/camera/avfoundation.h b/src/platform/camera/avfoundation.h index 942074eca..1ee519392 100644 --- a/src/platform/camera/avfoundation.h +++ b/src/platform/camera/avfoundation.h @@ -30,6 +30,8 @@ namespace avfoundation { + const QString CAPTURE_SCREEN{"Capture screen"}; + QVector getDeviceModes(QString devName); QVector> getDeviceList(); } diff --git a/src/platform/camera/avfoundation.mm b/src/platform/camera/avfoundation.mm index 76f6fd62b..72c79a9f6 100644 --- a/src/platform/camera/avfoundation.mm +++ b/src/platform/camera/avfoundation.mm @@ -19,6 +19,7 @@ */ #include "avfoundation.h" +#include #import @@ -31,6 +32,16 @@ QVector > avfoundation::getDeviceList() result.append({ QString::fromNSString([device uniqueID]), QString::fromNSString([device localizedName]) }); } + uint32_t numScreens = 0; + CGGetActiveDisplayList(0, NULL, &numScreens); + if (numScreens > 0) { + CGDirectDisplayID screens[numScreens]; + CGGetActiveDisplayList(numScreens, screens, &numScreens); + for (uint32_t i = 0; i < numScreens; i++) { + result.append({ QString("%1 %2").arg(CAPTURE_SCREEN).arg(i), QObject::tr("Capture screen %1").arg(i) }); + } + } + return result; } @@ -38,25 +49,30 @@ QVector avfoundation::getDeviceModes(QString devName) { QVector result; - NSString* deviceName = [NSString stringWithCString:devName.toUtf8() encoding:NSUTF8StringEncoding]; - AVCaptureDevice* device = [AVCaptureDevice deviceWithUniqueID:deviceName]; - - if (device == nil) { + if (devName.startsWith(CAPTURE_SCREEN)) { return result; } + else { + NSString* deviceName = [NSString stringWithCString:devName.toUtf8() encoding:NSUTF8StringEncoding]; + AVCaptureDevice* device = [AVCaptureDevice deviceWithUniqueID:deviceName]; - for (AVCaptureDeviceFormat* format in [device formats]) { - CMFormatDescriptionRef formatDescription; - CMVideoDimensions dimensions; - formatDescription = (CMFormatDescriptionRef)[format performSelector:@selector(formatDescription)]; - dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription); + if (device == nil) { + return result; + } - for (AVFrameRateRange* range in format.videoSupportedFrameRateRanges) { - VideoMode mode; - mode.width = dimensions.width; - mode.height = dimensions.height; - mode.FPS = range.maxFrameRate; - result.append(mode); + for (AVCaptureDeviceFormat* format in [device formats]) { + CMFormatDescriptionRef formatDescription; + CMVideoDimensions dimensions; + formatDescription = (CMFormatDescriptionRef)[format performSelector:@selector(formatDescription)]; + dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription); + + for (AVFrameRateRange* range in format.videoSupportedFrameRateRanges) { + VideoMode mode; + mode.width = dimensions.width; + mode.height = dimensions.height; + mode.FPS = range.maxFrameRate; + result.append(mode); + } } } diff --git a/src/video/cameradevice.cpp b/src/video/cameradevice.cpp index d9cab566a..77a685b6e 100644 --- a/src/video/cameradevice.cpp +++ b/src/video/cameradevice.cpp @@ -167,10 +167,19 @@ CameraDevice* CameraDevice::open(QString devName, VideoMode mode) } #endif #ifdef Q_OS_OSX - else if (iformat->name == QString("avfoundation") && mode) + else if (iformat->name == QString("avfoundation")) { - av_dict_set(&options, "video_size", QString("%1x%2").arg(mode.width).arg(mode.height).toStdString().c_str(), 0); - av_dict_set(&options, "framerate", QString().setNum(mode.FPS).toStdString().c_str(), 0); + if (mode) + { + av_dict_set(&options, "video_size", QString("%1x%2").arg(mode.width).arg(mode.height).toStdString().c_str(), 0); + av_dict_set(&options, "framerate", QString().setNum(mode.FPS).toStdString().c_str(), 0); + } + else if (devName.startsWith(avfoundation::CAPTURE_SCREEN)) + { + av_dict_set(&options, "framerate", QString().setNum(5).toStdString().c_str(), 0); + av_dict_set_int(&options, "capture_cursor", 1, 0); + av_dict_set_int(&options, "capture_mouse_clicks", 1, 0); + } } #endif else if (mode) From 9a3df5094c62b7e587076315eb712c1191314022 Mon Sep 17 00:00:00 2001 From: sudden6 Date: Wed, 23 Dec 2015 18:17:27 +0100 Subject: [PATCH 057/210] add sqlcipher as dependency for opensuse --- INSTALL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/INSTALL.md b/INSTALL.md index 07e3dd503..51f78d969 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -200,7 +200,7 @@ sudo dnf install qt-devel qt-doc qt-creator qt5-qtsvg qt5-qtsvg-devel openal-sof #### openSUSE: ```bash -sudo zypper install patterns-openSUSE-devel_basis libqt5-qtbase-common-devel libqt5-qtsvg-devel libqt5-linguist libQt5Network-devel libQt5OpenGL-devel libQt5Concurrent-devel libQt5Xml-devel libQt5Sql-devel openal-soft-devel qrencode-devel libXScrnSaver-devel libQt5Sql5-sqlite libffmpeg-devel +sudo zypper install patterns-openSUSE-devel_basis libqt5-qtbase-common-devel libqt5-qtsvg-devel libqt5-linguist libQt5Network-devel libQt5OpenGL-devel libQt5Concurrent-devel libQt5Xml-devel libQt5Sql-devel openal-soft-devel qrencode-devel libXScrnSaver-devel libQt5Sql5-sqlite libffmpeg-devel sqlcipher-devel ``` From 081154e78a4c907180eb7fb79df25853e3dda616 Mon Sep 17 00:00:00 2001 From: sudden6 Date: Wed, 23 Dec 2015 18:54:34 +0100 Subject: [PATCH 058/210] initial usermanual --- doc/user_manual_en.html | 43 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 doc/user_manual_en.html diff --git a/doc/user_manual_en.html b/doc/user_manual_en.html new file mode 100644 index 000000000..eb92d6345 --- /dev/null +++ b/doc/user_manual_en.html @@ -0,0 +1,43 @@ + + + + + + +qTox User Manual + + + +

qTox User Manual

+

Index

+
    +
  1. Settings
  2. +
  3. Groupchats
  4. +
  5. Multi Window Mode
  6. +
  7. Keyboard Shortcuts
  8. +
+ +
    +

  1. Settings
  2. +
      +

    • General
    • +
        +

        General Settings

        +
      • Language: Changes which language the qTox interface uses.

      • +
      • Autostart: If set, qTox will start when you login on your computer.

      • +
      • Light icon: If set, qTox will use a different icon, which is easier to read on black backgrounds.

      • +
      • Show system tray icon: If set, qTox will show its icon in your system tray.

      • +
          +
        • Start in tray: On start, qTox will only show its tray icon and no window.

        • +
        • Minimize to tray: The minimize button on the top right, will minimize qTox to its tray icon. There won't be a taskbar item.

        • +
        • Close to tray The close button on the top right, will minimize qTox to its tray icon.

        • +
        +
      • Auto away after (0 to disable): After the specified amount of time, qTox will set your Status to away. A setting of 0 will never set your status.

      • +
      • Default directory to save files: You can set the directory where qTox puts files you recieved here.

      • +
      • Autoaccept files: If set, qTox will automatically accept filetransfers and put them in the directory specified above.

      • +

        General Settings

        +
      +
    +
+ + \ No newline at end of file From 552155bd1f5824c536dd6d1bbc8d293f3f1d8499 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Wed, 23 Dec 2015 23:29:20 +0100 Subject: [PATCH 059/210] Merge PR #2719 from antis81:fix_audio_subscriptions * fix dangling audio output device * do not resubscribe sid in copy constructor --- src/audio/audio.cpp | 4 ++-- src/core/toxcall.cpp | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 5d67c6917..704c4c17c 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -760,6 +760,8 @@ void Audio::unsubscribeOutput(SID& sid) { QMutexLocker locker(&d->audioLock); + d->outSources.removeAll(sid); + if (sid) { if (alIsSource(sid)) { alDeleteSources(1, &sid); @@ -772,8 +774,6 @@ void Audio::unsubscribeOutput(SID& sid) sid = 0; } - d->outSources.removeAll(sid); - if (d->outSources.isEmpty()) d->cleanupOutput(); } diff --git a/src/core/toxcall.cpp b/src/core/toxcall.cpp index 7a878edc6..191034f1e 100644 --- a/src/core/toxcall.cpp +++ b/src/core/toxcall.cpp @@ -49,7 +49,6 @@ ToxCall::ToxCall(ToxCall&& other) noexcept // required -> ownership of audio input is moved to new instance Audio& audio = Audio::getInstance(); audio.subscribeInput(); - audio.subscribeOutput(alSource); #ifdef QTOX_FILTER_AUDIO filterer = other.filterer; From f70b249ed8c101fbaf056336153bdf94bfcd2d29 Mon Sep 17 00:00:00 2001 From: ovalseven8 Date: Thu, 24 Dec 2015 16:00:05 +0100 Subject: [PATCH 060/210] Fix default smiley pack. Necessary because of the name changes. --- src/persistence/settings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/persistence/settings.cpp b/src/persistence/settings.cpp index da06b74ff..88c390d79 100644 --- a/src/persistence/settings.cpp +++ b/src/persistence/settings.cpp @@ -192,7 +192,7 @@ void Settings::loadGlobal() s.endGroup(); s.beginGroup("GUI"); - smileyPack = s.value("smileyPack", ":/smileys/TwitterEmojiSVG/emoticons.xml").toString(); + smileyPack = s.value("smileyPack", ":/smileys/Universe/emoticons.xml").toString(); emojiFontPointSize = s.value("emojiFontPointSize", 16).toInt(); firstColumnHandlePos = s.value("firstColumnHandlePos", 50).toInt(); secondColumnHandlePosFromRight = s.value("secondColumnHandlePosFromRight", 50).toInt(); From 79ddbf7d029f0b6f7caf38bd338939418caa2053 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Mon, 28 Dec 2015 12:06:22 +0100 Subject: [PATCH 061/210] open the first available audio in/out device as default, if specifier is empty --- src/audio/audio.cpp | 56 +++++++++++---------------------------------- 1 file changed, 13 insertions(+), 43 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 704c4c17c..639fac1ef 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -422,27 +422,14 @@ bool AudioPrivate::initInput(QString inDevDescr) const uint16_t frameDuration = AUDIO_FRAME_DURATION; const uint32_t chnls = AUDIO_CHANNELS; const ALCsizei bufSize = (frameDuration * sampleRate * 4) / 1000 * chnls; - if (inDevDescr.isEmpty()) - { - const ALchar *pDeviceList = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); + if (inDevDescr.isEmpty()) { + const ALchar *pDeviceList = Audio::inDeviceNames(); if (pDeviceList) - { - alInDev = alcCaptureOpenDevice(pDeviceList, sampleRate, stereoFlag, bufSize); - int len = strlen(pDeviceList); -#ifdef Q_OS_WIN - inDevDescr = QString::fromUtf8(pDeviceList, len); -#else - inDevDescr = QString::fromLocal8Bit(pDeviceList, len); -#endif - Settings::getInstance().setInDev(inDevDescr); - } - else - { - alInDev = alcCaptureOpenDevice(nullptr, sampleRate, stereoFlag, bufSize); - } + inDevDescr = QString::fromUtf8(pDeviceList, strlen(pDeviceList)); } - else - alInDev = alcCaptureOpenDevice(inDevDescr.toStdString().c_str(), + + if (!inDevDescr.isEmpty()) + alInDev = alcCaptureOpenDevice(inDevDescr.toUtf8().constData(), sampleRate, stereoFlag, bufSize); // Restart the capture if necessary @@ -474,32 +461,15 @@ bool AudioPrivate::initOutput(QString outDevDescr) assert(!alOutDev); - if (outDevDescr.isEmpty()) - { - // Attempt to default to the first available audio device. - const ALchar *pDeviceList; - if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE) - pDeviceList = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); - else - pDeviceList = alcGetString(NULL, ALC_DEVICE_SPECIFIER); + if (outDevDescr.isEmpty()) { + // default to the first available audio device. + const ALchar *pDeviceList = Audio::outDeviceNames(); if (pDeviceList) - { - alOutDev = alcOpenDevice(pDeviceList); - int len = strlen(pDeviceList); -#ifdef Q_OS_WIN - outDevDescr = QString::fromUtf8(pDeviceList, len); -#else - outDevDescr = QString::fromLocal8Bit(pDeviceList, len); -#endif - Settings::getInstance().setOutDev(outDevDescr); - } - else - { - alOutDev = alcOpenDevice(nullptr); - } + outDevDescr = QString::fromUtf8(pDeviceList, strlen(pDeviceList)); } - else - alOutDev = alcOpenDevice(outDevDescr.toStdString().c_str()); + + if (!outDevDescr.isEmpty()) + alOutDev = alcOpenDevice(outDevDescr.toUtf8().constData()); if (alOutDev) { From 5ecc2d99a0bd9e41e05311387295544354924039 Mon Sep 17 00:00:00 2001 From: minj <4mr.minj@gmail.com> Date: Tue, 29 Dec 2015 20:44:51 +0200 Subject: [PATCH 062/210] update Lithuanian translation --- translations/lt.ts | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/translations/lt.ts b/translations/lt.ts index ba7db597f..3886cb8b0 100644 --- a/translations/lt.ts +++ b/translations/lt.ts @@ -311,18 +311,6 @@ Ignoruoti įgaliotąjį serverį ir jungtis prie interneto tiesiogiai?Advanced Kita - - Synchronized - safe (recommended) - Sinchronizuotas – saugu (rekomenduojama) - - - Partially async - risky (20% faster) - Iš dalies sinchronizuotas – rizikinga (20 % greičiau) - - - Asynchronous - dangerous (fastest) - Nesinchronizuotas – pavojinga (greičiausia) - AdvancedSettings @@ -343,14 +331,6 @@ Ignoruoti įgaliotąjį serverį ir jungtis prie interneto tiesiogiai?Reset to default settings Atstatyti pradinius nustatymus - - Chat history - Pokalbių žurnalas - - - <html><head/><body><p><a href="http://www.sqlite.org/pragma.html#pragma_synchronous"><span style=" text-decoration: underline; color:#0000ff;">Writing to DB</span></a></p></body></html> - <html><head/><body><p><a href="http://www.sqlite.org/pragma.html#pragma_synchronous"><span style=" text-decoration: underline; color:#0000ff;">Duomenų bazės pildymas</span></a></p></body></html> - Android @@ -1886,6 +1866,14 @@ Ji bus įdiegta paleidus qTox iš naujo. Desktop as a camera input for screen sharing Darbalaukio transliacija + + Error + Klaida + + + qTox couldn't open your chat logs, they will be disabled. + qTox nepavyko atidaryti pokalbių žurnalo, todėl jis buvo išjungtas. + RemoveFriendDialog From b998dba3738b8994bb43c8fa43eee0165b91efaa Mon Sep 17 00:00:00 2001 From: Corey Sheldon Date: Wed, 30 Dec 2015 07:28:57 -0500 Subject: [PATCH 063/210] Some small updates. + updated libsodium tag to current tag of 1.0.7 + added sqlcipher compile for Fedora users and any others where sqlcipher is not a distro available package ( linux distros) --- INSTALL.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index 51f78d969..eb246b03c 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -332,7 +332,7 @@ You will need to install manually `libsodium`: ``` git clone git://github.com/jedisct1/libsodium.git cd libsodium -git checkout tags/1.0.3 +git checkout tags/1.0.7 ./autogen.sh ./configure && make check sudo checkinstall --install --pkgname libsodium --pkgversion 1.0.0 --nodoc @@ -368,7 +368,16 @@ cd filter_audio make -j$(nproc) sudo make install ``` - +### Sqlcipher compiling, For Fedora users and possibly others. +```bash +git clone https://github.com/sqlcipher/sqlcipher +cd sqlcipher +autoreconf -if +./configure +make -j$(nproc) +sudo make install +cd .. +```` ### toxcore compiling From 26768de94abfe8ff8d2b980e03f7751994d93ecf Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Wed, 30 Dec 2015 14:45:55 +0100 Subject: [PATCH 064/210] set mouse cursor to I-Beam shape, when hovering over text within chat --- src/chatlog/content/text.cpp | 6 +++--- src/chatlog/content/text.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/chatlog/content/text.cpp b/src/chatlog/content/text.cpp index bd2bec7ee..4e4adfc8c 100644 --- a/src/chatlog/content/text.cpp +++ b/src/chatlog/content/text.cpp @@ -220,10 +220,10 @@ void Text::hoverMoveEvent(QGraphicsSceneHoverEvent *event) QString anchor = doc->documentLayout()->anchorAt(event->pos()); - if (!anchor.isEmpty()) - setCursor(QCursor(Qt::PointingHandCursor)); + if (anchor.isEmpty()) + setCursor(Qt::IBeamCursor); else - setCursor(QCursor()); + setCursor(Qt::PointingHandCursor); // tooltip setToolTip(extractImgTooltip(cursorFromPos(event->scenePos(), false))); diff --git a/src/chatlog/content/text.h b/src/chatlog/content/text.h index f994c21e0..3bdc59d3c 100644 --- a/src/chatlog/content/text.h +++ b/src/chatlog/content/text.h @@ -54,7 +54,7 @@ public: virtual qreal getAscent() const final; virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) final override; virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) final override; - virtual void hoverMoveEvent(QGraphicsSceneHoverEvent* event) final override; + void hoverMoveEvent(QGraphicsSceneHoverEvent* event) final override; virtual QString getText() const final; From 910264a7d658d6d7f5d9488fc12a3b168e164e0f Mon Sep 17 00:00:00 2001 From: Zetok Zalbavar Date: Thu, 31 Dec 2015 13:18:57 +0000 Subject: [PATCH 065/210] Add CONTRIBUTING.md It was taken from https://github.com/qbittorrent/qBittorrent/blob/76c16e0994570205efb4a5596da8140eebfdcb51/CONTRIBUTING.md and adjusted for qTox needs. Since qBittorrent is licensed under GPLv2+, file in qTox source is covered by GPLv3+. --- CONTRIBUTING.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..e74104c4b --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,37 @@ +# Filing an issue + +### Must read +* If you aren't sure, you can ask on the [**IRC channel**](https://webchat.freenode.net/?channels=qtox) or read our [**wiki**](https://github.com/tux3/qTox/wiki) first. +* Do a quick **search**. Others might already reported the issue. +* Write in **English**! +* Provide **version** information: (You can find version numbers at menu `Settings → About`) + ``` +qTox: +Commit hash: +toxcore: +Qt: +OS version: + + ``` +* Provide **steps** to reproduce the problem, it will be easier to pinpoint the fault. +* **Screenshots**! A screenshot is worth a thousand words. just upload it. [(How?)](https://help.github.com/articles/file-attachments-on-issues-and-pull-requests) + +### Good to know +* **Patience**. The dev team is small and resource limited. Devs finding their free time, analyzing the problem and fixing the issue, it all takes time. :clock3: +* If you can code, why not become a **contributor** by fixing the issue and open a pull request? :wink: +* Harsh words or threats won't help your situation. What's worse, your complain will (very likely) to be **ignored**. :fearful: + + +# Opening a pull request + +### Must read +* Read our [**coding guidelines**](https://github.com/tux3/qTox/wiki/Coding). +* Keep the title **short** and provide a **clear** description about what your pull request does. +* Provide **screenshots** for UI related changes. +* Keep your git commit history **clean** and **precise**. Commits like `xxx fixup` should not appear. +* If your commit fix a reported issue (for example #4134), add the following message to the commit `Fixes #4134.`. Example [here](https://github.com/tux3/qTox/commit/87160526d5bafcee7869d6741a06045e13d731d5). + +### Good to know +* **Search** pull request history! Others might already implemented your idea and is waiting to be merged (or got rejected already). Save your precious time by doing a search first. +* When resolving merge conflicts, do `git rebase `, don't do `git pull`. Then you can start fixing the conflicts. Here is a good explanation: [link](https://www.atlassian.com/git/tutorials/merging-vs-rebasing). + From f2ba03b45f7441a763bad0290b24fa6e41b95594 Mon Sep 17 00:00:00 2001 From: tux3 Date: Thu, 31 Dec 2015 14:36:12 +0100 Subject: [PATCH 066/210] Fix some messages being saved with history disabled --- src/widget/form/chatform.cpp | 22 ++++++++++++++++------ src/widget/widget.cpp | 4 +++- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/widget/form/chatform.cpp b/src/widget/form/chatform.cpp index d90507e26..ac970f844 100644 --- a/src/widget/form/chatform.cpp +++ b/src/widget/form/chatform.cpp @@ -949,13 +949,23 @@ void ChatForm::SendMessageStr(QString msg) else rec = Core::getInstance()->sendMessage(f->getFriendID(), qt_msg); - auto* offMsgEngine = getOfflineMsgEngine(); - Nexus::getProfile()->getHistory()->addNewMessage(f->getToxId().publicKey, qt_msg_hist, - Core::getInstance()->getSelfId().publicKey, timestamp, status, Core::getInstance()->getUsername(), - [offMsgEngine,rec,ma](int64_t id) + + Profile* profile = Nexus::getProfile(); + if (profile->isHistoryEnabled()) { - offMsgEngine->registerReceipt(rec, id, ma); - }); + auto* offMsgEngine = getOfflineMsgEngine(); + profile->getHistory()->addNewMessage(f->getToxId().publicKey, qt_msg_hist, + Core::getInstance()->getSelfId().publicKey, timestamp, status, Core::getInstance()->getUsername(), + [offMsgEngine,rec,ma](int64_t id) + { + offMsgEngine->registerReceipt(rec, id, ma); + }); + } + else + { + /// TODO: Make faux-offline messaging work partially with the history disabled + ma->markAsSent(QDateTime::currentDateTime()); + } msgEdit->setLastMessage(msg); //set last message only when sending it diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index 6aaff7966..b7fffb3ee 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -1080,7 +1080,9 @@ void Widget::onFriendMessageReceived(int friendId, const QString& message, bool QDateTime timestamp = QDateTime::currentDateTime(); f->getChatForm()->addMessage(f->getToxId(), message, isAction, timestamp, true); - Nexus::getProfile()->getHistory()->addNewMessage(f->getToxId().publicKey, isAction ? "/me " + f->getDisplayedName() + " " + message : message, + Profile* profile = Nexus::getProfile(); + if (profile->isHistoryEnabled()) + profile->getHistory()->addNewMessage(f->getToxId().publicKey, isAction ? "/me " + f->getDisplayedName() + " " + message : message, f->getToxId().publicKey, timestamp, true, f->getDisplayedName()); newFriendMessageAlert(friendId); From bfe013c58b22edad8ad257c4d5a386b73e25b2c6 Mon Sep 17 00:00:00 2001 From: sudden6 Date: Fri, 1 Jan 2016 17:26:58 +0100 Subject: [PATCH 067/210] most settings documented --- doc/user_manual_en.html | 75 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/doc/user_manual_en.html b/doc/user_manual_en.html index eb92d6345..16f0d5212 100644 --- a/doc/user_manual_en.html +++ b/doc/user_manual_en.html @@ -22,7 +22,7 @@

  • General
    • -

      General Settings

      +

      General Settings

    • Language: Changes which language the qTox interface uses.

    • Autostart: If set, qTox will start when you login on your computer.

    • Light icon: If set, qTox will use a different icon, which is easier to read on black backgrounds.

    • @@ -35,7 +35,78 @@
    • Auto away after (0 to disable): After the specified amount of time, qTox will set your Status to away. A setting of 0 will never set your status.

    • Default directory to save files: You can set the directory where qTox puts files you recieved here.

    • Autoaccept files: If set, qTox will automatically accept filetransfers and put them in the directory specified above.

    • -

      General Settings

      + +

      Chat

      +
    • Play sound: If checked, qTox will play a sound when you get a new message.

    • +
    • Open window: If checked, the qTox window will be opened.

    • +
        +
      • Focus window: If checked, the qTox window will additionally be focused.

      • +
      +
    • Show contacts' status changes: ???

    • +
    • Group chats always notify: ???

    • +
    • Place groupchats at top of friend list: If checked, your groupchats will be at the top of the contacts list.

    • +
    • Faux offline messaging: If enabled, qTox will attempt to send messages when a currently offline contact comes online again.

    • +
    • Compact contact list: If set, qTox will use a contact list layout which takes up less screen space.

    • +
    • Multiple windows mode: If enabled, the qTox user interface will be split into multiple independent windows. For details see TODO.

    • +
        +
      • Open each chat in an individual window: If checked, a new window will be opened for every chat you open.

      • +
      + +

      Theme

      +
    • Use emoticons: If enabled, qTox will replace simleys ( e.g. :-) ) with Unicode emoticons.

    • +
    • Smiley Pack: You can choose from different sets of shiped emoticon styles. You can also install your own, see ??? for details

    • +
    • Emoticon size: You can change the size of the emoticons here.

    • +
    • Style: Changes the appearance of qTox.

    • +
    • Theme color: Changes the colors qTox uses.

    • +
    • Timestamp format: Change the format in which qTox displays message timestamps.

    • +
    • Date format: Same as above for the date.

    • + +

      Connection Settings

      +
    • Enable IPv6 (recommended): If enabled, qTox will use IPv4 and IPv6 protocols, whichever is available. If disabled, qTox will only use IPv4.

    • +
    • Enable UDP (recommended): If enabled, qTox will use TCP and UDP protocols. If disabled, qTox will only use TCP.

    • +
    • Proxy type: If you want to use a proxy, set the type here. "None" disables the proxy.

    • +
    • Address: If you use a proxy, enter the address here.

    • +
    • Port: If you use a proxy, enter the port here.

    • +
    • Reconnect: Reconnect to the tox network, e.g. if you changed the proxy settings.

    • +
    +

  • Privacy
  • +
      +
    • Send typing notifications: If enabled, notify your chat partner when you are currently typing.

    • +
    • Keep chat history: If enabled, qTox will save your sent and recieved messages. Encrypt your profile, if you want to encrypt the chat history.

    • + +
    • NoSpam

    • + + NoSpam is a feature of Tox to prevent someone spamming you with friend requests. If you get spammed, enter or generate a new NoSpam value, this will alter your Tox ID. You don't need to tell your existing contacts your new Tox ID, but you have to tell new contacts your new Tox ID. Your Tox ID can be found ??? + +
    +

  • Audio/Video
  • +
      +

      Audio Settings

      +
    • Playback device: Select the device qTox should use for all audio output (notifications, calls,..).

    • +
    • Playback: Here you can adjust the playback volume to your needs.

    • +
    • Capture device: Select the device qTox should use for audio input in calls.

    • +
    • Microphone: Set the input volume of your microphone with this slider. When you are talking normaly, the the display should be in the green range.

    • +
    • Filter audio If enabled, qTox will try to remove noise and echo from your audio input.

    • + +

      Video Settings

      +
    • Video device: Select the video device qTox should use for video calls. "None" will show a dummy picture to your chat partner. "Desktop" will stream the content of your screen.

    • +
    • Resolution: You can select from the available resolutions and framerates here. Higher resolutions provide more quality, but if the bandwidth of your connection is low, the video may get choppy.

    • + + If you set up everything correctly, you should see the preview of your video device in the box. + +
    • Rescan devices Use this button to search for newly attached devices, e.g. you plugged in a webcam.

    • +
    +

  • Advanced
  • +
      +
    • Make Tox portable: ???

    • +
    • Reset to default settings Use this button to delete any changes you made to the qTox settings.

    • +
    +

  • About
  • +
      +
    • Version The version of qTox and the libraries it depends on. Please append this information to every bugreport.

    • +
    • License The license under which the code of qTox is available.

    • +
    • Authors The people who developed this shiny piece of software.

    • +
    • Known Issues Links to our list of known issues and improvements.

From ca229baea12ff2d78eff77fe249e87219bf9132a Mon Sep 17 00:00:00 2001 From: Corey Sheldon Date: Fri, 1 Jan 2016 15:16:55 -0500 Subject: [PATCH 068/210] Cleaned up sqlcipher instructions, added interlink --- INSTALL.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/INSTALL.md b/INSTALL.md index eb246b03c..31bc4d7ea 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -32,6 +32,7 @@ - [Ubuntu <15.04](#ubuntu14-toxcore) - [Ubuntu >=15.04](#ubuntu-toxcore) - [filter_audio](#filter_audio) + - [sqlcipher (Fedora)](#sqlcipher) - [toxcore compiling](#toxcore-compiling) - [Compile qTox](#compile-qtox) - [OS X](#osx) @@ -368,7 +369,8 @@ cd filter_audio make -j$(nproc) sudo make install ``` -### Sqlcipher compiling, For Fedora users and possibly others. + +### Sqlcipher compiling (Fedora) ```bash git clone https://github.com/sqlcipher/sqlcipher cd sqlcipher From f70e720d3f31bd45133a7e0308a492c0410187b4 Mon Sep 17 00:00:00 2001 From: Corey Sheldon Date: Fri, 1 Jan 2016 15:40:45 -0500 Subject: [PATCH 069/210] Cleaning up some more.... --- INSTALL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/INSTALL.md b/INSTALL.md index 31bc4d7ea..8f9176373 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -32,7 +32,7 @@ - [Ubuntu <15.04](#ubuntu14-toxcore) - [Ubuntu >=15.04](#ubuntu-toxcore) - [filter_audio](#filter_audio) - - [sqlcipher (Fedora)](#sqlcipher) + - [sqlcipher](#sqlcipher) - [toxcore compiling](#toxcore-compiling) - [Compile qTox](#compile-qtox) - [OS X](#osx) From 18b966e6857ccb16a5105422d300e8d19411115e Mon Sep 17 00:00:00 2001 From: Corey Sheldon Date: Fri, 1 Jan 2016 15:49:12 -0500 Subject: [PATCH 070/210] Cleaning up linkage again. --- INSTALL.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/INSTALL.md b/INSTALL.md index 8f9176373..1ad602402 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -370,7 +370,10 @@ make -j$(nproc) sudo make install ``` -### Sqlcipher compiling (Fedora) +### sqlcipher + +If you are not using Fedora, skip this section, and go directly to installing [**toxcore**](#toxcore-dependencies). + ```bash git clone https://github.com/sqlcipher/sqlcipher cd sqlcipher From 8ce16ad399dd36f280be820a63d20282a55fcaed Mon Sep 17 00:00:00 2001 From: Andrey S Date: Sat, 2 Jan 2016 00:00:05 +0300 Subject: [PATCH 071/210] Fixes #2484 - Error message inside the chat --- src/chatlog/content/filetransferwidget.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chatlog/content/filetransferwidget.cpp b/src/chatlog/content/filetransferwidget.cpp index 8021ce0e6..b19e39ca7 100644 --- a/src/chatlog/content/filetransferwidget.cpp +++ b/src/chatlog/content/filetransferwidget.cpp @@ -22,6 +22,7 @@ #include "src/nexus.h" #include "src/core/core.h" +#include "src/widget/gui.h" #include "src/widget/style.h" #include "src/widget/widget.h" #include "src/persistence/settings.h" @@ -138,8 +139,7 @@ void FileTransferWidget::acceptTransfer(const QString &filepath) //test if writable if (!Nexus::tryRemoveFile(filepath)) { - QMessageBox::warning(this, - tr("Location not writable", "Title of permissions popup"), + GUI::showWarning( tr("Location not writable", "Title of permissions popup"), tr("You do not have permission to write that location. Choose another, or cancel the save dialog.", "text of permissions popup")); return; } From 371900b56ff9389cff0cfabf909740bd2addfe0e Mon Sep 17 00:00:00 2001 From: Andrew Novikov Date: Wed, 23 Dec 2015 19:43:06 +0300 Subject: [PATCH 072/210] Fix for the issue #2458 --- src/widget/widget.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index b7fffb3ee..dae2b1e46 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -144,7 +144,10 @@ void Widget::init() actionLogout->setIcon(prepareIcon(":/img/others/logout-icon.svg", icon_size, icon_size)); actionQuit = new QAction(this); +#ifndef Q_OS_OSX actionQuit->setMenuRole(QAction::QuitRole); +#endif + actionQuit->setShortcut(QKeySequence::Quit); actionQuit->setIcon(prepareIcon(":/ui/rejectCall/rejectCall.svg", icon_size, icon_size)); connect(actionQuit, &QAction::triggered, qApp, &QApplication::quit); From cb43a9b70ec8cad0dc8c1f1e1fa8564d651bd067 Mon Sep 17 00:00:00 2001 From: agilob Date: Sat, 2 Jan 2016 22:01:41 +0000 Subject: [PATCH 073/210] Remove ctrl+q from tray menu --- src/widget/widget.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index dae2b1e46..97ca9a497 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -147,7 +147,6 @@ void Widget::init() #ifndef Q_OS_OSX actionQuit->setMenuRole(QAction::QuitRole); #endif - actionQuit->setShortcut(QKeySequence::Quit); actionQuit->setIcon(prepareIcon(":/ui/rejectCall/rejectCall.svg", icon_size, icon_size)); connect(actionQuit, &QAction::triggered, qApp, &QApplication::quit); @@ -773,7 +772,7 @@ void Widget::onIconClick(QSystemTrayIcon::ActivationReason reason) } else if (reason == QSystemTrayIcon::Unknown) { - if (isHidden()) + if (isHidden()) forceShow(); } } From f7118071b784d5ec367636c2a673fd5ca258c24d Mon Sep 17 00:00:00 2001 From: agilob Date: Sun, 3 Jan 2016 13:06:24 +0000 Subject: [PATCH 074/210] Set window icons on settings window --- src/mainwindow.ui | 2 +- src/widget/widget.cpp | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 2b07aaa98..a6d3ebee1 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -1094,7 +1094,7 @@ QSplitter:handle{ 0 0 775 - 284 + 279 diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index 97ca9a497..9c7f4a50d 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -682,7 +682,7 @@ void Widget::setWindowTitle(const QString& title) void Widget::forceShow() { - hide(); // Workaround to force minimized window to be restored + hide(); // Workaround to force minimized window to be restored show(); activateWindow(); } @@ -785,6 +785,7 @@ void Widget::onSettingsClicked() settingsWidget->show(createContentDialog(SettingDialog)); setActiveToolMenuButton(Widget::None); + settingsWidget->setWindowIcon(QIcon(":/img/settings.svg")); } else { @@ -803,6 +804,7 @@ void Widget::showProfile() // onAvatarClicked, onUsernameClicked profileForm->show(createContentDialog(ProfileDialog)); setActiveToolMenuButton(Widget::None); + settingsWidget->setWindowIcon(QIcon(":/img/icons/qtox.svg")); } else { @@ -1368,6 +1370,7 @@ ContentLayout* Widget::createContentDialog(DialogType type) void retranslateUi() { setWindowTitle(Core::getInstance()->getUsername() + QStringLiteral(" - ") + Widget::fromDialogType(type)); + setWindowIcon(QIcon(":/img/settings.svg")); } protected: From ee2d6d0db0e67a043d6d7e799053fc1aad415c0c Mon Sep 17 00:00:00 2001 From: Zetok Zalbavar Date: Sun, 3 Jan 2016 16:56:32 +0000 Subject: [PATCH 075/210] Remove useless travis --- .travis.yml | 85 ----------------------------------------------------- README.md | 2 +- 2 files changed, 1 insertion(+), 86 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 113605e39..000000000 --- a/.travis.yml +++ /dev/null @@ -1,85 +0,0 @@ -language: cpp - -compiler: - - gcc - -sudo: true - -before_install: -# Qt >= 5.2 - - sudo add-apt-repository -y ppa:beineri/opt-qt542 -# GCC >=4.8 - - if [ "$CXX" == "g++" ]; then sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test; fi - - if [ "$CXX" == "clang++" ]; then sudo add-apt-repository -y ppa:h-rayflood/llvm; fi - - sudo apt-get update -qq - -install: -# install needed Qt stuff - - sudo apt-get install -y build-essential qt54base qt54script qt54svg qt54tools qt54xmlpatterns libopenal-dev libxss-dev qrencode libqrencode-dev libglib2.0-dev libgdk-pixbuf2.0-dev libgtk2.0-dev libtool autotools-dev automake checkinstall check libvpx-dev -# install needed GCC version and set VM to use - - if [ "$CC" == "gcc" ]; then sudo apt-get install -qq gcc-4.9; fi - - if [ "$CC" == "gcc" ]; then export CC="gcc-4.9"; fi - - if [ "$CXX" == "g++" ]; then sudo apt-get install -qq g++-4.9; fi - - if [ "$CXX" == "g++" ]; then export CXX="g++-4.9"; fi -# clang - - if [ "$CXX" == "clang++" ]; then sudo apt-get install --allow-unauthenticated -qq clang-3.4; fi - - if [ "$CXX" == "clang++" ]; then export CXX="clang++-3.4"; fi - - -before_script: -# libopus - - wget http://downloads.xiph.org/releases/opus/opus-1.0.3.tar.gz > /dev/null - - tar xzf opus-1.0.3.tar.gz > /dev/null - - cd opus-1.0.3 - - ./configure > /dev/null - - make -j$(nproc) > /dev/null - - sudo make install > /dev/null - - cd .. -# ffmpeg - - if [ ! -e "libs" ]; then mkdir libs; fi - - if [ ! -e "ffmpeg" ]; then mkdir ffmpeg; fi -# - - cd libs/ - - export PREFIX_DIR="$PWD" -# - - cd ../ffmpeg - - wget http://ffmpeg.org/releases/ffmpeg-2.7.2.tar.bz2 - - tar xf ffmpeg* - - cd ffmpeg* - - ./configure --prefix="$PREFIX_DIR" --enable-shared --disable-static --disable-programs --disable-protocols --disable-doc --disable-sdl --disable-avfilter --disable-avresample --disable-filters --disable-iconv --disable-network --disable-muxers --disable-postproc --disable-swresample --disable-swscale-alpha --disable-dct --disable-dwt --disable-lsp --disable-lzo --disable-mdct --disable-rdft --disable-fft --disable-faan --disable-vaapi --disable-vdpau --disable-zlib --disable-xlib --disable-bzlib --disable-lzma --disable-encoders --disable-yasm --enable-memalign-hack - - make -j$(nproc) - - make install - - cd ../../ -# filter_audio - - git clone https://github.com/irungentoo/filter_audio - - cd filter_audio - - make -j$(nproc) - - sudo make install - - cd .. -# libsodium - - git clone git://github.com/jedisct1/libsodium.git - - cd libsodium - - git checkout tags/1.0.3 - - ./autogen.sh - - ./configure && make -j$(nproc) - - sudo checkinstall --install --pkgname libsodium --pkgversion 1.0.0 --nodoc -y - - sudo ldconfig - - cd .. -# toxcore - - git clone https://github.com/irungentoo/toxcore.git - - cd toxcore - - autoreconf -if - - ./configure - - make -j$(nproc) - - sudo make install - - echo '/usr/local/lib/' | sudo tee -a /etc/ld.so.conf.d/locallib.conf - - sudo ldconfig - - cd .. -# Qt - - source /opt/qt54/bin/qt54-env.sh - -script: - - qmake qtox.pro QMAKE_CC="$CC" QMAKE_CXX="$CXX" - - $CC --version - - $CXX --version - - make -j10 diff --git a/README.md b/README.md index b9c13a606..cc8d7fa7c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -qTox [![Build Status](https://travis-ci.org/tux3/qTox.svg)](https://travis-ci.org/tux3/qTox) +qTox ====== [**Compile**](/INSTALL.md) **⦁** [**Contribute**](https://github.com/tux3/qTox/wiki#contributing) **⦁** [**Report bugs**](https://github.com/tux3/qTox/wiki/Writing-Useful-Bug-Reports) **⦁** [**Translate**](https://github.com/tux3/qTox/wiki/Translating) **⦁** [**Jenkins builds**](https://build.tox.chat/) **⦁** [**Keyboard shortcuts**](https://github.com/tux3/qTox/wiki/Keyboard-shortcuts) **⦁** [**Mailing list**](https://lists.tox.chat) **⦁** **IRC Channel:** [#qtox@freenode](https://webchat.freenode.net/?channels=qtox) From d69139bf4a7c1b2d8440edec519b0eb3f59883c0 Mon Sep 17 00:00:00 2001 From: Andrey S Date: Mon, 4 Jan 2016 14:02:37 +0300 Subject: [PATCH 076/210] Remove extra spaces --- src/chatlog/content/filetransferwidget.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chatlog/content/filetransferwidget.cpp b/src/chatlog/content/filetransferwidget.cpp index b19e39ca7..d0b44c06c 100644 --- a/src/chatlog/content/filetransferwidget.cpp +++ b/src/chatlog/content/filetransferwidget.cpp @@ -139,8 +139,8 @@ void FileTransferWidget::acceptTransfer(const QString &filepath) //test if writable if (!Nexus::tryRemoveFile(filepath)) { - GUI::showWarning( tr("Location not writable", "Title of permissions popup"), - tr("You do not have permission to write that location. Choose another, or cancel the save dialog.", "text of permissions popup")); + GUI::showWarning(tr("Location not writable", "Title of permissions popup"), + tr("You do not have permission to write that location. Choose another, or cancel the save dialog.", "text of permissions popup")); return; } From e952d1a6547aa2083b6e730a1ae3b32d76fab570 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Mon, 4 Jan 2016 22:34:30 +0100 Subject: [PATCH 077/210] Merge pull request #2767 from branch agilob:chat_window_icon * Set status icon on separate chat window, closes #2210 --- src/widget/contentdialog.cpp | 43 +++++++++++++++++++++++++++--------- src/widget/contentdialog.h | 2 +- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/widget/contentdialog.cpp b/src/widget/contentdialog.cpp index 86e2e3cdc..4a3c31014 100644 --- a/src/widget/contentdialog.cpp +++ b/src/widget/contentdialog.cpp @@ -120,7 +120,7 @@ ContentDialog::ContentDialog(SettingsWidget* settingsWidget, QWidget* parent) new QShortcut(Qt::CTRL + Qt::Key_PageUp, this, SLOT(previousContact())); new QShortcut(Qt::CTRL + Qt::Key_PageDown, this, SLOT(nextContact())); - connect(Core::getInstance(), &Core::usernameSet, this, &ContentDialog::updateTitleUsername); + connect(Core::getInstance(), &Core::usernameSet, this, &ContentDialog::updateTitleAndStatusIcon); Translator::registerHandler(std::bind(&ContentDialog::retranslateUi, this), this); } @@ -214,11 +214,9 @@ void ContentDialog::removeFriend(int friendId) FriendWidget* chatroomWidget = static_cast(std::get<1>(iter.value())); disconnect(chatroomWidget->getFriend(), &Friend::displayedNameChanged, this, &ContentDialog::updateFriendWidget); + // Need to find replacement to show here instead. if (activeChatroomWidget == chatroomWidget) - { - // Need to find replacement to show here instead. cycleContacts(true, false); - } friendLayout->removeFriendWidget(chatroomWidget, Status::Offline); friendLayout->removeFriendWidget(chatroomWidget, Status::Online); @@ -255,11 +253,9 @@ void ContentDialog::removeGroup(int groupId) GenericChatroomWidget* chatroomWidget = std::get<1>(iter.value()); + // Need to find replacement to show here instead. if (activeChatroomWidget == chatroomWidget) - { - // Need to find replacement to show here instead. cycleContacts(true, false); - } groupLayout.removeSortedWidget(chatroomWidget); chatroomWidget->deleteLater(); @@ -425,10 +421,37 @@ ContentDialog* ContentDialog::getGroupDialog(int groupId) return getDialog(groupId, groupList); } -void ContentDialog::updateTitleUsername(const QString& username) +void ContentDialog::updateTitleAndStatusIcon(const QString& username) { if (displayWidget != nullptr) + { + setWindowTitle(displayWidget->getTitle() + QStringLiteral(" - ") + username); + + // it's null when it's a groupchat + if(displayWidget->getFriend() == nullptr) + { + setWindowIcon(QIcon(":/img/group.svg")); + return; + } + + Status currentStatus = displayWidget->getFriend()->getStatus(); + + switch(currentStatus) { + case Status::Online: + setWindowIcon(QIcon(":/img/status/dot_online.svg")); + break; + case Status::Away: + setWindowIcon(QIcon(":/img/status/dot_away.svg")); + break; + case Status::Busy: + setWindowIcon(QIcon(":/img/status/dot_busy.svg")); + break; + case Status::Offline: + setWindowIcon(QIcon(":/img/status/dot_offline.svg")); + break; + } + } else setWindowTitle(username); } @@ -436,7 +459,7 @@ void ContentDialog::updateTitleUsername(const QString& username) void ContentDialog::updateTitle(GenericChatroomWidget* chatroomWidget) { displayWidget = chatroomWidget; - updateTitleUsername(Core::getInstance()->getUsername()); + updateTitleAndStatusIcon(Core::getInstance()->getUsername()); } void ContentDialog::previousContact() @@ -636,7 +659,7 @@ void ContentDialog::onGroupchatPositionChanged(bool top) void ContentDialog::retranslateUi() { - updateTitleUsername(Core::getInstance()->getUsername()); + updateTitleAndStatusIcon(Core::getInstance()->getUsername()); } void ContentDialog::saveDialogGeometry() diff --git a/src/widget/contentdialog.h b/src/widget/contentdialog.h index 51904f087..29d67b4e7 100644 --- a/src/widget/contentdialog.h +++ b/src/widget/contentdialog.h @@ -72,7 +72,7 @@ signals: #endif public slots: - void updateTitleUsername(const QString& username); + void updateTitleAndStatusIcon(const QString& username); void updateTitle(GenericChatroomWidget* chatroomWidget); void previousContact(); void nextContact(); From a9795473dc31d78c90cffc0d8865ba882c857316 Mon Sep 17 00:00:00 2001 From: Zetok Zalbavar Date: Thu, 7 Jan 2016 13:36:29 +0000 Subject: [PATCH 078/210] README.md: expose portable builds for windows closes #2766 --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b9c13a606..1dcd78ed5 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,10 @@ qTox [![Build Status](https://travis-ci.org/tux3/qTox.svg)](https://travis-ci.or ---- * **Windows**: - - [**64 bit download**](https://build.tox.chat/view/qtox/job/qTox_pkg_windows_x86-64_stable_release/lastSuccessfulBuild/artifact/setup-qtox.exe) - - [**32 bit download**](https://build.tox.chat/view/qtox/job/qTox_pkg_windows_x86_stable_release/lastSuccessfulBuild/artifact/setup-qtox.exe) + - [**64 bit installer**](https://build.tox.chat/view/qtox/job/qTox_pkg_windows_x86-64_stable_release/lastSuccessfulBuild/artifact/setup-qtox.exe) + - [**32 bit installer**](https://build.tox.chat/view/qtox/job/qTox_pkg_windows_x86_stable_release/lastSuccessfulBuild/artifact/setup-qtox.exe) + - [**64 bit portable**](https://build.tox.chat/job/qTox_build_windows_x86-64_release/lastSuccessfulBuild/artifact/qTox_build_windows_x86-64_release.zip) + - [**32 bit portable**](https://build.tox.chat/job/qTox_build_windows_x86_release/lastSuccessfulBuild/artifact/qTox_build_windows_x86_release.zip) * **Linux**: - [**64 bit download**](https://build.tox.chat/view/Clients/job/qTox_build_linux_x86-64_release/lastSuccessfulBuild/artifact/qTox_build_linux_x86-64_release.tar.xz) - [**32 bit download**](https://build.tox.chat/view/Clients/job/qTox_build_linux_x86_release/lastSuccessfulBuild/artifact/qTox_build_linux_x86_release.tar.xz) @@ -22,7 +24,7 @@ qTox [![Build Status](https://travis-ci.org/tux3/qTox.svg)](https://travis-ci.or - [**Port**](/INSTALL.md#freebsd-easy)
-Nighly builds do not update automatically at this stage of development, so make sure you get back to this site and regularly download the latest version of qTox. +Builds other than installer/packages don't receive updates automatically, so make sure you get back to this site and regularly download the latest version of qTox. #### Screenshots From 03cb9d8a03f21600eb7b3f9313c51dbfd71320dd Mon Sep 17 00:00:00 2001 From: Taha Date: Fri, 8 Jan 2016 21:02:48 -0500 Subject: [PATCH 079/210] qTox uses default smiley pack if there's an invalid one in the qtox.ini file (fixes #2757) --- src/persistence/settings.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/persistence/settings.cpp b/src/persistence/settings.cpp index 88c390d79..95b2b0136 100644 --- a/src/persistence/settings.cpp +++ b/src/persistence/settings.cpp @@ -192,7 +192,12 @@ void Settings::loadGlobal() s.endGroup(); s.beginGroup("GUI"); - smileyPack = s.value("smileyPack", ":/smileys/Universe/emoticons.xml").toString(); + static const QString DEFAULT_SMILEYS = ":/smileys/Universe/emoticons.xml"; + smileyPack = s.value("smileyPack", DEFAULT_SMILEYS).toString(); + if (!SmileyPack::isValid(smileyPack)) + { + smileyPack = DEFAULT_SMILEYS; + } emojiFontPointSize = s.value("emojiFontPointSize", 16).toInt(); firstColumnHandlePos = s.value("firstColumnHandlePos", 50).toInt(); secondColumnHandlePosFromRight = s.value("secondColumnHandlePosFromRight", 50).toInt(); From 82dfe0f7045be37f0cd38676e9780196eee58c23 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sat, 9 Jan 2016 13:12:39 +0100 Subject: [PATCH 080/210] fix audio singleton implementation --- src/audio/audio.cpp | 30 ++++++++---------------------- src/audio/audio.h | 5 ----- 2 files changed, 8 insertions(+), 27 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 639fac1ef..8f1520f00 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -56,8 +56,6 @@ #include "audiofilterer.h" #endif -Audio* Audio::instance{nullptr}; - /** @class AudioPlayer @@ -267,16 +265,12 @@ void AudioMeterListener::doListen() } /** -Returns the singleton's instance. Will construct on first call. +Returns the singleton instance. */ Audio& Audio::getInstance() { - if (!instance) - { - instance = new Audio(); - instance->startAudioThread(); - } - return *instance; + static Audio instance; + return instance; } AudioMeterListener* Audio::createAudioMeterListener() const @@ -289,18 +283,6 @@ AudioMeterListener* Audio::createAudioMeterListener() const Audio::Audio() : d(new AudioPrivate) -{ -} - -Audio::~Audio() -{ - delete d; -} - -/** -Start the audio thread for capture and playback. -*/ -void Audio::startAudioThread() { moveToThread(d->audioThread); @@ -308,7 +290,11 @@ void Audio::startAudioThread() d->audioThread->start(); else qWarning("Audio thread already started -> ignored."); +} +Audio::~Audio() +{ + delete d; } /** @@ -541,7 +527,7 @@ The first and last argument are ignored, but allow direct compatibility with tox void Audio::playGroupAudioQueued(void*,int group, int peer, const int16_t* data, unsigned samples, uint8_t channels, unsigned sample_rate, void* core) { - QMetaObject::invokeMethod(instance, "playGroupAudio", Qt::BlockingQueuedConnection, + QMetaObject::invokeMethod(&Audio::getInstance(), "playGroupAudio", Qt::BlockingQueuedConnection, Q_ARG(int,group), Q_ARG(int,peer), Q_ARG(const int16_t*,data), Q_ARG(unsigned,samples), Q_ARG(uint8_t,channels), Q_ARG(unsigned,sample_rate)); emit static_cast(core)->groupPeerAudioPlaying(group, peer); diff --git a/src/audio/audio.h b/src/audio/audio.h index 777c30cb6..7436ff55e 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -50,8 +50,6 @@ public: static Audio& getInstance(); public: - void startAudioThread(); - AudioMeterListener* createAudioMeterListener() const; qreal outputVolume(); @@ -100,9 +98,6 @@ private: Audio(); ~Audio(); -private: - static Audio* instance; - private: AudioPrivate* d; }; From 87ee8e966c52ab6e28af868e384d1aa478dc9e07 Mon Sep 17 00:00:00 2001 From: sudden6 Date: Sat, 9 Jan 2016 19:21:05 +0100 Subject: [PATCH 081/210] write it in markdown --- doc/user_manual_en.md | 107 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 doc/user_manual_en.md diff --git a/doc/user_manual_en.md b/doc/user_manual_en.md new file mode 100644 index 000000000..10fbafd1c --- /dev/null +++ b/doc/user_manual_en.md @@ -0,0 +1,107 @@ +# qTox User Manual +## Index + +* [Settings](#Settings) +* [Groupchats](#Groupchats) +* Multi Window Mode +* Keyboard Shortcuts + +## Settings +### General + +#### General Settings +* _Language:_ Changes which language the qTox interface uses. +* _Autostart:_ If set, qTox will start when you login on your computer. +* _Light icon:_ If set, qTox will use a different icon, which is easier to read on black backgrounds. +* _Show system tray icon:_ If set, qTox will show its icon in your system tray. + * _Start in tray:_ On start, qTox will only show its tray icon and no window. + * _Minimize to tray:_ The minimize button on the top right, will minimize qTox to its tray icon. There won't be a taskbar item. + +* _Auto away after (0 to disable):_ After the specified amount of time, qTox will set your Status to "Away". A setting of 0 will never change your status. +* _Default directory to save files:_ You can set the directory where qTox puts files you recieved here. +* _Autoaccept files:_ If set, qTox will automatically accept filetransfers and put them in the directory specified above. + +#### Chat +* _Play sound:_ If checked, qTox will play a sound when you get a new message. +* _Open window:_ If checked, the qTox window will be opened. + * _Focus window:_ If checked, the qTox window will additionally be focused. +* _Show contacts' status changes:_ ??? +* _Group chats always notify:_ ??? +* _Place groupchats at top of friend list:_ If checked, your groupchats will be at the top of the contacts list. +* _Faux offline messaging:_ If enabled, qTox will attempt to send messages when a currently offline contact comes online again. +* _Compact contact list:_ If set, qTox will use a contact list layout which takes up less screen space. +* _Multiple windows mode:_ If enabled, the qTox user interface will be split into multiple independent windows. For details see TODO. + * _Open each chat in an individual window:_ If checked, a new window will be opened for every chat you open. + +#### Theme +* _Use emoticons:_ If enabled, qTox will replace simleys ( e.g. :-) ) with Unicode emoticons. +* _Smiley Pack:_ You can choose from different sets of shiped emoticon styles. You can also install your own, see ??? for details +* _Emoticon size:_ You can change the size of the emoticons here. +* _Style:_ Changes the appearance of qTox. +* _Theme color:_ Changes the colors qTox uses. +* _Timestamp format:_ Change the format in which qTox displays message timestamps. +* _Date format:_ Same as above for the date. + +#### Connection Settings +* _Enable IPv6 (recommended):_ If enabled, qTox will use IPv4 and IPv6 protocols, whichever is available. If disabled, qTox will only use IPv4. +* _Enable UDP (recommended):_ If enabled, qTox will use TCP and UDP protocols. If disabled, qTox will only use TCP. +* _Proxy type:_ If you want to use a proxy, set the type here. "None" disables the proxy. +* _Address:_ If you use a proxy, enter the address here. +* _Port:_ If you use a proxy, enter the port here. +* _Reconnect:_ Reconnect to the tox network, e.g. if you changed the proxy settings. + +### Privacy + +* _Send typing notifications:_ If enabled, notify your chat partner when you are currently typing. +* _Keep chat history:_ If enabled, qTox will save your sent and recieved messages. Encrypt your profile, if you want to encrypt the chat history. + +#### NoSpam + +NoSpam is a feature of Tox to prevent someone spamming you with friend requests. If you get spammed, enter or generate a new NoSpam value, this will alter your Tox ID. You don't need to tell your existing contacts your new Tox ID, but you have to tell new contacts your new Tox ID. Your Tox ID can be found ??? + +### Audio/Video +#### Audio Settings +* _Playback device:_ Select the device qTox should use for all audio output (notifications, calls,..). +* _Playback:_ Here you can adjust the playback volume to your needs. +* _Capture device:_ Select the device qTox should use for audio input in calls. +* _Microphone:_ Set the input volume of your microphone with this slider. When you are talking normaly, the the display should be in the green range. +* _Filter audio_ If enabled, qTox will try to remove noise and echo from your audio input. + +#### Video Settings +* _Video device:_ Select the video device qTox should use for video calls. "None" will show a dummy picture to your chat partner. "Desktop" will stream the content of your screen. +* _Resolution:_ You can select from the available resolutions and framerates here. Higher resolutions provide more quality, but if the bandwidth of your connection is low, the video may get choppy. + + If you set up everything correctly, you should see the preview of your video device in the box. + +* _Rescan devices_ Use this button to search for newly attached devices, e.g. you plugged in a webcam. + +### Advanced +* _Make Tox portable:_ ??? +* _Reset to default settings_ Use this button to delete any changes you made to the qTox settings. + +### About +* _Version_ The version of qTox and the libraries it depends on. Please append this information to every bugreport. +* _License_ The license under which the code of qTox is available. +* _Authors_ The people who developed this shiny piece of software. +* _Known Issues_ Links to our list of known issues and improvements. + +## Groupchats + +Groupchats are a way to talk with multiple friends at the same time, like when you are standing together in a group. To create a groupchat click the groupchat icon and set a name. Now you can invite people by right clicking on the contact and selecting "Invite to group". Currently, if the last person leaves the chat, it is closed and you have to create a new one. + +## Keyboard Shortcuts + +The following shortcuts are currently supported: + + + +| Shortcut | Action | +|----------|--------| +| ``CTRL`` + ``P`` | Push to talk | +| ``Arrow up`` | Paste last message | +| ``CTRL`` + ``SHIFT`` + ``L`` | Clear chat | +| ``CTRL`` + ``q`` | Quit qTox | +| `CTRL` + `Page Down` | Switch to the next contact | +| `CTRL` + `Page Up` | Switch to the previous contact| +| `CTRL` + `TAB` | Switch to the next contact | +| `CTRL` + `SHIFT` + `TAB` | Switch to the previous contact| From aeb80f1e78fc35f1dbc88cadd613fa3740d95c14 Mon Sep 17 00:00:00 2001 From: sudden6 Date: Sat, 9 Jan 2016 19:28:43 +0100 Subject: [PATCH 082/210] remove html version --- doc/user_manual_en.html | 114 ---------------------------------------- 1 file changed, 114 deletions(-) delete mode 100644 doc/user_manual_en.html diff --git a/doc/user_manual_en.html b/doc/user_manual_en.html deleted file mode 100644 index 16f0d5212..000000000 --- a/doc/user_manual_en.html +++ /dev/null @@ -1,114 +0,0 @@ - - - - - - -qTox User Manual - - - -

qTox User Manual

-

Index

-
    -
  1. Settings
  2. -
  3. Groupchats
  4. -
  5. Multi Window Mode
  6. -
  7. Keyboard Shortcuts
  8. -
- -
    -

  1. Settings
  2. -
      -

    • General
    • -
        -

        General Settings

        -
      • Language: Changes which language the qTox interface uses.

      • -
      • Autostart: If set, qTox will start when you login on your computer.

      • -
      • Light icon: If set, qTox will use a different icon, which is easier to read on black backgrounds.

      • -
      • Show system tray icon: If set, qTox will show its icon in your system tray.

      • -
          -
        • Start in tray: On start, qTox will only show its tray icon and no window.

        • -
        • Minimize to tray: The minimize button on the top right, will minimize qTox to its tray icon. There won't be a taskbar item.

        • -
        • Close to tray The close button on the top right, will minimize qTox to its tray icon.

        • -
        -
      • Auto away after (0 to disable): After the specified amount of time, qTox will set your Status to away. A setting of 0 will never set your status.

      • -
      • Default directory to save files: You can set the directory where qTox puts files you recieved here.

      • -
      • Autoaccept files: If set, qTox will automatically accept filetransfers and put them in the directory specified above.

      • - -

        Chat

        -
      • Play sound: If checked, qTox will play a sound when you get a new message.

      • -
      • Open window: If checked, the qTox window will be opened.

      • -
          -
        • Focus window: If checked, the qTox window will additionally be focused.

        • -
        -
      • Show contacts' status changes: ???

      • -
      • Group chats always notify: ???

      • -
      • Place groupchats at top of friend list: If checked, your groupchats will be at the top of the contacts list.

      • -
      • Faux offline messaging: If enabled, qTox will attempt to send messages when a currently offline contact comes online again.

      • -
      • Compact contact list: If set, qTox will use a contact list layout which takes up less screen space.

      • -
      • Multiple windows mode: If enabled, the qTox user interface will be split into multiple independent windows. For details see TODO.

      • -
          -
        • Open each chat in an individual window: If checked, a new window will be opened for every chat you open.

        • -
        - -

        Theme

        -
      • Use emoticons: If enabled, qTox will replace simleys ( e.g. :-) ) with Unicode emoticons.

      • -
      • Smiley Pack: You can choose from different sets of shiped emoticon styles. You can also install your own, see ??? for details

      • -
      • Emoticon size: You can change the size of the emoticons here.

      • -
      • Style: Changes the appearance of qTox.

      • -
      • Theme color: Changes the colors qTox uses.

      • -
      • Timestamp format: Change the format in which qTox displays message timestamps.

      • -
      • Date format: Same as above for the date.

      • - -

        Connection Settings

        -
      • Enable IPv6 (recommended): If enabled, qTox will use IPv4 and IPv6 protocols, whichever is available. If disabled, qTox will only use IPv4.

      • -
      • Enable UDP (recommended): If enabled, qTox will use TCP and UDP protocols. If disabled, qTox will only use TCP.

      • -
      • Proxy type: If you want to use a proxy, set the type here. "None" disables the proxy.

      • -
      • Address: If you use a proxy, enter the address here.

      • -
      • Port: If you use a proxy, enter the port here.

      • -
      • Reconnect: Reconnect to the tox network, e.g. if you changed the proxy settings.

      • -
      -

    • Privacy
    • -
        -
      • Send typing notifications: If enabled, notify your chat partner when you are currently typing.

      • -
      • Keep chat history: If enabled, qTox will save your sent and recieved messages. Encrypt your profile, if you want to encrypt the chat history.

      • - -
      • NoSpam

      • - - NoSpam is a feature of Tox to prevent someone spamming you with friend requests. If you get spammed, enter or generate a new NoSpam value, this will alter your Tox ID. You don't need to tell your existing contacts your new Tox ID, but you have to tell new contacts your new Tox ID. Your Tox ID can be found ??? - -
      -

    • Audio/Video
    • -
        -

        Audio Settings

        -
      • Playback device: Select the device qTox should use for all audio output (notifications, calls,..).

      • -
      • Playback: Here you can adjust the playback volume to your needs.

      • -
      • Capture device: Select the device qTox should use for audio input in calls.

      • -
      • Microphone: Set the input volume of your microphone with this slider. When you are talking normaly, the the display should be in the green range.

      • -
      • Filter audio If enabled, qTox will try to remove noise and echo from your audio input.

      • - -

        Video Settings

        -
      • Video device: Select the video device qTox should use for video calls. "None" will show a dummy picture to your chat partner. "Desktop" will stream the content of your screen.

      • -
      • Resolution: You can select from the available resolutions and framerates here. Higher resolutions provide more quality, but if the bandwidth of your connection is low, the video may get choppy.

      • - - If you set up everything correctly, you should see the preview of your video device in the box. - -
      • Rescan devices Use this button to search for newly attached devices, e.g. you plugged in a webcam.

      • -
      -

    • Advanced
    • -
        -
      • Make Tox portable: ???

      • -
      • Reset to default settings Use this button to delete any changes you made to the qTox settings.

      • -
      -

    • About
    • -
        -
      • Version The version of qTox and the libraries it depends on. Please append this information to every bugreport.

      • -
      • License The license under which the code of qTox is available.

      • -
      • Authors The people who developed this shiny piece of software.

      • -
      • Known Issues Links to our list of known issues and improvements.

      • -
      -
    -
- - \ No newline at end of file From 861697d86e5c8832b4825a843f33193ca1e39d2f Mon Sep 17 00:00:00 2001 From: sudden6 Date: Sat, 9 Jan 2016 22:23:19 +0100 Subject: [PATCH 083/210] Update user_manual_en.md --- doc/user_manual_en.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/user_manual_en.md b/doc/user_manual_en.md index 10fbafd1c..dd5dae35c 100644 --- a/doc/user_manual_en.md +++ b/doc/user_manual_en.md @@ -3,8 +3,8 @@ * [Settings](#Settings) * [Groupchats](#Groupchats) -* Multi Window Mode -* Keyboard Shortcuts +* [Multi Window Mode](#multi-window-mode) +* [Keyboard Shortcuts](#keyboard-shortcuts) ## Settings ### General @@ -89,6 +89,10 @@ NoSpam is a feature of Tox to prevent someone spamming you with friend requests. Groupchats are a way to talk with multiple friends at the same time, like when you are standing together in a group. To create a groupchat click the groupchat icon and set a name. Now you can invite people by right clicking on the contact and selecting "Invite to group". Currently, if the last person leaves the chat, it is closed and you have to create a new one. +## Multi Window Mode + +If you activated this mode in the [settings](#Settings), qTox will seperata its main window into a contact list and chat windows, which allows you to have multiple conversations on your screen on the same time. + ## Keyboard Shortcuts The following shortcuts are currently supported: From 13b2ec54aa99d52072c287b5fd4daa771358bc62 Mon Sep 17 00:00:00 2001 From: Taha Date: Sat, 9 Jan 2016 19:55:03 -0500 Subject: [PATCH 084/210] Removed static modifier --- src/persistence/settings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/persistence/settings.cpp b/src/persistence/settings.cpp index 95b2b0136..16f9fde6d 100644 --- a/src/persistence/settings.cpp +++ b/src/persistence/settings.cpp @@ -192,7 +192,7 @@ void Settings::loadGlobal() s.endGroup(); s.beginGroup("GUI"); - static const QString DEFAULT_SMILEYS = ":/smileys/Universe/emoticons.xml"; + const QString DEFAULT_SMILEYS = ":/smileys/Universe/emoticons.xml"; smileyPack = s.value("smileyPack", DEFAULT_SMILEYS).toString(); if (!SmileyPack::isValid(smileyPack)) { From 1921a9887e9c843f5be42ca3dddd23a9be690961 Mon Sep 17 00:00:00 2001 From: Zetok Zalbavar Date: Mon, 11 Jan 2016 19:00:43 +0000 Subject: [PATCH 085/210] Remove empty src/main.h (closes #2792) Looks like it was accidentally introduced in 99050424341bdbb8ef0fe218b5c78b578db73189 --- src/main.h | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/main.h diff --git a/src/main.h b/src/main.h deleted file mode 100644 index e69de29bb..000000000 From 71bdb23246722a34c57f386c40092dfb76d7457b Mon Sep 17 00:00:00 2001 From: sudden6 Date: Mon, 11 Jan 2016 23:46:37 +0100 Subject: [PATCH 086/210] update user manual with @zetok s suggestions --- doc/user_manual_en.md | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/doc/user_manual_en.md b/doc/user_manual_en.md index dd5dae35c..77b4f2370 100644 --- a/doc/user_manual_en.md +++ b/doc/user_manual_en.md @@ -11,8 +11,8 @@ #### General Settings * _Language:_ Changes which language the qTox interface uses. -* _Autostart:_ If set, qTox will start when you login on your computer. -* _Light icon:_ If set, qTox will use a different icon, which is easier to read on black backgrounds. +* _Autostart:_ If set, qTox will start when you login on your computer. qTox will also autmatically open the profile which was active when you ticked the checkbox, but this only works if your profile isn't encrypted (has no password set). +* _Light icon:_ If set, qTox will use a different icon, which is easier to see on black backgrounds. * _Show system tray icon:_ If set, qTox will show its icon in your system tray. * _Start in tray:_ On start, qTox will only show its tray icon and no window. * _Minimize to tray:_ The minimize button on the top right, will minimize qTox to its tray icon. There won't be a taskbar item. @@ -23,28 +23,30 @@ #### Chat * _Play sound:_ If checked, qTox will play a sound when you get a new message. -* _Open window:_ If checked, the qTox window will be opened. +* _Open window:_ If checked, the qTox window will be opened. If you use the multiple windows mode, see [Multi Window Mode](#multi-window-mode) for details. * _Focus window:_ If checked, the qTox window will additionally be focused. -* _Show contacts' status changes:_ ??? -* _Group chats always notify:_ ??? -* _Place groupchats at top of friend list:_ If checked, your groupchats will be at the top of the contacts list. -* _Faux offline messaging:_ If enabled, qTox will attempt to send messages when a currently offline contact comes online again. +* _Show contacts' status changes:_ If set, qTox will show contact status changes in your chat history. +* _Group chats always notify:_ If set, qTox will notify you on every new message in a groupchat. +* _Place groupchats at top of friend list:_ If checked, your groupchats will be at the top of the contacts list, else they will be sorted with your other contacts. +* _Faux offline messaging:_ If enabled, qTox will attempt to send messages when a currently offline contact comes online again. * _Compact contact list:_ If set, qTox will use a contact list layout which takes up less screen space. -* _Multiple windows mode:_ If enabled, the qTox user interface will be split into multiple independent windows. For details see TODO. - * _Open each chat in an individual window:_ If checked, a new window will be opened for every chat you open. +* _Multiple windows mode:_ If enabled, the qTox user interface will be split into multiple independent windows. For details see [Multi Window Mode](#multi-window-mode). + * _Open each chat in an individual window:_ If checked, a new window will be opened for every chat you open. If you manually grouped the chat into another window, the window which hosts the chat will be focused. #### Theme * _Use emoticons:_ If enabled, qTox will replace simleys ( e.g. :-) ) with Unicode emoticons. * _Smiley Pack:_ You can choose from different sets of shiped emoticon styles. You can also install your own, see ??? for details * _Emoticon size:_ You can change the size of the emoticons here. -* _Style:_ Changes the appearance of qTox. -* _Theme color:_ Changes the colors qTox uses. +* _Style:_ Changes the appearance of qTox. +* _Theme color:_ Changes the colors qTox uses. * _Timestamp format:_ Change the format in which qTox displays message timestamps. * _Date format:_ Same as above for the date. #### Connection Settings * _Enable IPv6 (recommended):_ If enabled, qTox will use IPv4 and IPv6 protocols, whichever is available. If disabled, qTox will only use IPv4. -* _Enable UDP (recommended):_ If enabled, qTox will use TCP and UDP protocols. If disabled, qTox will only use TCP. +* _Enable UDP (recommended):_ If enabled, qTox will use TCP and UDP protocols. If disabled, qTox will only use TCP, which is supposed to lower the amount of traffic, but is also slower and puts more load on other network participants. +Most users will want the two settings enabled, but if qTox crashes your router, you can try to disable them. + * _Proxy type:_ If you want to use a proxy, set the type here. "None" disables the proxy. * _Address:_ If you use a proxy, enter the address here. * _Port:_ If you use a proxy, enter the port here. @@ -76,7 +78,7 @@ NoSpam is a feature of Tox to prevent someone spamming you with friend requests. * _Rescan devices_ Use this button to search for newly attached devices, e.g. you plugged in a webcam. ### Advanced -* _Make Tox portable:_ ??? +* _Make Tox portable:_ If enabled, qTox will load/save user data from the working directory, instead of ``` ~/.config/tox/ ```. * _Reset to default settings_ Use this button to delete any changes you made to the qTox settings. ### About @@ -97,11 +99,8 @@ If you activated this mode in the [settings](#Settings), qTox will seperata its The following shortcuts are currently supported: - - | Shortcut | Action | |----------|--------| -| ``CTRL`` + ``P`` | Push to talk | | ``Arrow up`` | Paste last message | | ``CTRL`` + ``SHIFT`` + ``L`` | Clear chat | | ``CTRL`` + ``q`` | Quit qTox | From 212f97fd4143662a34376fc27a33cc74cee08442 Mon Sep 17 00:00:00 2001 From: sudden6 Date: Mon, 11 Jan 2016 23:52:28 +0100 Subject: [PATCH 087/210] fix some links and better wording in user manual --- doc/user_manual_en.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/user_manual_en.md b/doc/user_manual_en.md index 77b4f2370..87862159b 100644 --- a/doc/user_manual_en.md +++ b/doc/user_manual_en.md @@ -1,8 +1,8 @@ # qTox User Manual ## Index -* [Settings](#Settings) -* [Groupchats](#Groupchats) +* [Settings](#settings) +* [Groupchats](#groupchats) * [Multi Window Mode](#multi-window-mode) * [Keyboard Shortcuts](#keyboard-shortcuts) @@ -66,7 +66,7 @@ NoSpam is a feature of Tox to prevent someone spamming you with friend requests. * _Playback device:_ Select the device qTox should use for all audio output (notifications, calls,..). * _Playback:_ Here you can adjust the playback volume to your needs. * _Capture device:_ Select the device qTox should use for audio input in calls. -* _Microphone:_ Set the input volume of your microphone with this slider. When you are talking normaly, the the display should be in the green range. +* _Microphone:_ Set the input volume of your microphone with this slider. When you are talking normaly, the display should be in the green range. * _Filter audio_ If enabled, qTox will try to remove noise and echo from your audio input. #### Video Settings @@ -93,7 +93,7 @@ Groupchats are a way to talk with multiple friends at the same time, like when y ## Multi Window Mode -If you activated this mode in the [settings](#Settings), qTox will seperata its main window into a contact list and chat windows, which allows you to have multiple conversations on your screen on the same time. +If you activated this mode in the [settings](#settings), qTox will seperata its main window into a contact list and chat windows, which allows you to have multiple conversations on your screen on the same time. Additionally you can manually group chats into a window by dragging and dropping them onto eachother. ## Keyboard Shortcuts From ccfb81b2e4c4729b3c3818e5647086abd8179066 Mon Sep 17 00:00:00 2001 From: Zetok Zalbavar Date: Thu, 14 Jan 2016 20:21:00 +0000 Subject: [PATCH 088/210] Add some basic documentation about Tox ID in source Lets not make plaintext gods angry by linking to a dead html page. --- src/core/toxid.h | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/core/toxid.h b/src/core/toxid.h index 10fc3c728..b107f6762 100644 --- a/src/core/toxid.h +++ b/src/core/toxid.h @@ -23,9 +23,18 @@ #include -/*! - * \brief This class represents a Tox ID as specified at: - * https://libtoxcore.so/core_concepts.html +/* + * This class represents a Tox ID. + * An ID is composed of 32 bytes long public key, 4 bytes long NoSpam + * and 2 bytes long checksum. + * + * e.g. + * + * | C7719C6808C14B77348004956D1D98046CE09A34370E7608150EAD74C3815D30 | C8BA3AB9 | BEB9 + * | / | + * | / NoSpam | Checksum + * | Public Key (PK), 32 bytes, 64 characters / 4 bytes | 2 bytes + * | | 8 characters| 4 characters */ class ToxId { From 38313d1e0a65de990b11680b33d32783f2ee44ae Mon Sep 17 00:00:00 2001 From: sudden6 Date: Fri, 15 Jan 2016 15:34:35 +0100 Subject: [PATCH 089/210] Add section about user profile to manual --- doc/user_manual_en.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/doc/user_manual_en.md b/doc/user_manual_en.md index 87862159b..0215ba973 100644 --- a/doc/user_manual_en.md +++ b/doc/user_manual_en.md @@ -1,11 +1,39 @@ # qTox User Manual ## Index +* [User Profile](#user-profile) * [Settings](#settings) * [Groupchats](#groupchats) * [Multi Window Mode](#multi-window-mode) * [Keyboard Shortcuts](#keyboard-shortcuts) +## User Profile +Your User Profile contains everything you share with other people on Tox. You can open it by clicking the picture on the top right corner. It contains the following settings: + +### Public Information +* _Name:_ This is your nickname which everyone who has your Tox ID can see. +* _Status:_ You can post a status message here, which again everyone on who has your ToxID can see. + +### Tox ID + +The long code in hexadecimal format is your Tox ID, share this with everyone you want to talk to. Click it to copy it to your clipboard. +Your Tox ID is also shown as QR-Code to easily share it with friends over a smartphone. + +The "Save image" button saves the QR-Code into a image file, while the "Copy image" button copies into your clipboard. + +### Profile + +qTox allows you to use multiple Tox IDs with different profiles, which each can have different nicknames, status messages and friends. + ++ _Current profile:_ Shows the filename which stores your information. ++ _Current profile locatation:_ Shows the path to the profile file. ++ _Rename_ This button allows you to rename your profile. Your nickname and profile name don't have to be the same. ++ _Delete_ This button deletes your profile. ++ _Export_ Allows you to export your profile in a format compatible with other Tox clients. You can also manually backup your *.tox files. ++ _Logout_ Close your current profile and show the login window. ++ _Remove password_ If you set a password for your profile, you can remove it with this button. ++ _Change password_ If you set a password for your profile, you can change the password with this button. You can also set a password for unencrypted profiles here. + ## Settings ### General From 3645e39b89739c76b0202799d399b707d2132677 Mon Sep 17 00:00:00 2001 From: tux3 Date: Fri, 15 Jan 2016 17:38:40 +0100 Subject: [PATCH 090/210] Updater compatibility with Windows XP With some LoadLibrary/GetProcAddress shenanigans --- updater/widget.cpp | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/updater/widget.cpp b/updater/widget.cpp index 0a141b520..bb3a86aa8 100644 --- a/updater/widget.cpp +++ b/updater/widget.cpp @@ -154,14 +154,29 @@ void Widget::startQToxAndExit() SecureZeroMemory(&pi, sizeof(pi)); si.cb = sizeof(si); - if (!CreateProcessWithTokenW(hPrimaryToken, 0, QTOX_PATH.toStdWString().c_str(), 0, 0, 0, 0, &si, &pi)) + bool unelevateOk = true; + + auto advapi32H = LoadLibrary(TEXT("advapi32.dll")); + if ((unelevateOk = (advapi32H != nullptr))) + { + auto CreateProcessWithTokenWH = (decltype(&CreateProcessWithTokenW)) + GetProcAddress(advapi32H, "CreateProcessWithTokenW"); + if ((unelevateOk = (CreateProcessWithTokenWH != nullptr))) + { + if (!CreateProcessWithTokenWH(hPrimaryToken, 0, QTOX_PATH.toStdWString().c_str(), 0, 0, 0, 0, &si, &pi)) + unelevateOk = false; + } + } + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + + if (!unelevateOk) { qWarning() << "Failed to start unelevated qTox"; QProcess::startDetached(QTOX_PATH); } - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); #else QProcess::startDetached(QTOX_PATH); #endif @@ -187,8 +202,24 @@ QString Widget::getSettingsDirPath() #ifdef Q_OS_WIN wchar_t* path; - SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, hPrimaryToken, &path); - QString pathStr = QString::fromStdWString(path); + wchar_t pathOld[MAX_PATH]; + bool isOld = false; // If true, we have to use pathOld and older Windows API. + + auto shell32H = LoadLibrary(TEXT("shell32.dll")); + if (!(isOld = (shell32H == nullptr))) + { + auto SHGetKnownFolderPathH = (decltype(&SHGetKnownFolderPath)) + GetProcAddress(shell32H, "SHGetKnownFolderPath"); + if (!(isOld = (SHGetKnownFolderPathH == nullptr))) + SHGetKnownFolderPathH(FOLDERID_RoamingAppData, 0, hPrimaryToken, &path); + } + if (isOld) + { + qDebug() << "Falling back to legacy APIs..."; + SHGetFolderPathW(nullptr, CSIDL_APPDATA, nullptr, 0, pathOld); + } + + QString pathStr = QString::fromStdWString(isOld ? pathOld : path); pathStr.replace("\\", "/"); return pathStr + "/tox"; #else From 6b4f081fdf3e11e27c955ab304ea602353b57110 Mon Sep 17 00:00:00 2001 From: tux3 Date: Fri, 15 Jan 2016 17:40:12 +0100 Subject: [PATCH 091/210] dos2unix the updater --- updater/main.cpp | 208 ++++----- updater/update.cpp | 286 ++++++------ updater/update.h | 120 ++--- updater/updater.pro | 80 ++-- updater/widget.cpp | 676 +++++++++++++-------------- updater/widget.h | 134 +++--- updater/widget.ui | 278 +++++------ updater/windows/updater.exe.manifest | 22 +- updater/windows/updater.rc | 2 +- 9 files changed, 903 insertions(+), 903 deletions(-) diff --git a/updater/main.cpp b/updater/main.cpp index 6688f98c1..68067a60b 100644 --- a/updater/main.cpp +++ b/updater/main.cpp @@ -1,104 +1,104 @@ -/* - Copyright © 2014 by The qTox Project - - This file is part of qTox, a Qt-based graphical interface for Tox. - - qTox is libre software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - qTox is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with qTox. If not, see -*/ - - -#include "widget.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static std::unique_ptr logFileStream {nullptr}; -static std::unique_ptr logFileFile {nullptr}; -static QMutex mutex; - -void logMessageHandler(QtMsgType type, const QMessageLogContext& ctxt, const QString& msg) -{ - // Silence qWarning spam due to bug in QTextBrowser (trying to open a file for base64 images) - if (ctxt.function == QString("virtual bool QFSFileEngine::open(QIODevice::OpenMode)") - && msg == QString("QFSFileEngine::open: No file name specified")) - return; - - QString LogMsg = QString("[%1] %2:%3 : ") - .arg(QTime::currentTime().toString("HH:mm:ss.zzz")).arg(ctxt.file).arg(ctxt.line); - switch (type) - { - case QtDebugMsg: - LogMsg += "Debug"; - break; - case QtWarningMsg: - LogMsg += "Warning"; - break; - case QtCriticalMsg: - LogMsg += "Critical"; - break; - case QtFatalMsg: - LogMsg += "Fatal"; - break; - default: - break; - } - - LogMsg += ": " + msg + "\n"; - - QTextStream out(stderr, QIODevice::WriteOnly); - out << LogMsg; - - if (!logFileStream) - return; - - QMutexLocker locker(&mutex); - *logFileStream << LogMsg; - logFileStream->flush(); -} - -int main(int argc, char *argv[]) -{ - qInstallMessageHandler(logMessageHandler); - QApplication a(argc, argv); - - logFileStream.reset(new QTextStream); - logFileFile.reset(new QFile(QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + QDir::separator() - + "AppData" + QDir::separator() + "Roaming" + QDir::separator() + "tox")+QDir::separator()+"qtox.log")); - if (logFileFile->open(QIODevice::Append)) - { - logFileStream->setDevice(logFileFile.get()); - *logFileStream << QDateTime::currentDateTime().toString("\nyyyy-MM-dd HH:mm:ss' Updater file logger starting\n'"); - } - else - { - qWarning() << "Couldn't open log file!\n"; - logFileStream.release(); - } - - long unsigned int bufsize=100; - char buf[100]; - GetUserNameA(buf, &bufsize); - qDebug() << "Updater running as user" << buf; - - Widget w; - w.show(); - - return a.exec(); -} +/* + Copyright © 2014 by The qTox Project + + This file is part of qTox, a Qt-based graphical interface for Tox. + + qTox is libre software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + qTox is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with qTox. If not, see +*/ + + +#include "widget.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static std::unique_ptr logFileStream {nullptr}; +static std::unique_ptr logFileFile {nullptr}; +static QMutex mutex; + +void logMessageHandler(QtMsgType type, const QMessageLogContext& ctxt, const QString& msg) +{ + // Silence qWarning spam due to bug in QTextBrowser (trying to open a file for base64 images) + if (ctxt.function == QString("virtual bool QFSFileEngine::open(QIODevice::OpenMode)") + && msg == QString("QFSFileEngine::open: No file name specified")) + return; + + QString LogMsg = QString("[%1] %2:%3 : ") + .arg(QTime::currentTime().toString("HH:mm:ss.zzz")).arg(ctxt.file).arg(ctxt.line); + switch (type) + { + case QtDebugMsg: + LogMsg += "Debug"; + break; + case QtWarningMsg: + LogMsg += "Warning"; + break; + case QtCriticalMsg: + LogMsg += "Critical"; + break; + case QtFatalMsg: + LogMsg += "Fatal"; + break; + default: + break; + } + + LogMsg += ": " + msg + "\n"; + + QTextStream out(stderr, QIODevice::WriteOnly); + out << LogMsg; + + if (!logFileStream) + return; + + QMutexLocker locker(&mutex); + *logFileStream << LogMsg; + logFileStream->flush(); +} + +int main(int argc, char *argv[]) +{ + qInstallMessageHandler(logMessageHandler); + QApplication a(argc, argv); + + logFileStream.reset(new QTextStream); + logFileFile.reset(new QFile(QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + QDir::separator() + + "AppData" + QDir::separator() + "Roaming" + QDir::separator() + "tox")+QDir::separator()+"qtox.log")); + if (logFileFile->open(QIODevice::Append)) + { + logFileStream->setDevice(logFileFile.get()); + *logFileStream << QDateTime::currentDateTime().toString("\nyyyy-MM-dd HH:mm:ss' Updater file logger starting\n'"); + } + else + { + qWarning() << "Couldn't open log file!\n"; + logFileStream.release(); + } + + long unsigned int bufsize=100; + char buf[100]; + GetUserNameA(buf, &bufsize); + qDebug() << "Updater running as user" << buf; + + Widget w; + w.show(); + + return a.exec(); +} diff --git a/updater/update.cpp b/updater/update.cpp index 6e6e4d47b..4cd0b8978 100644 --- a/updater/update.cpp +++ b/updater/update.cpp @@ -1,143 +1,143 @@ -/* - Copyright © 2014 by The qTox Project - - This file is part of qTox, a Qt-based graphical interface for Tox. - - qTox is libre software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - qTox is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with qTox. If not, see -*/ - - -#include "update.h" -#include "serialize.h" -#include "widget.h" -#include -#include -#include -#include -#include - -unsigned char key[crypto_sign_PUBLICKEYBYTES] = -{ - 0x20, 0x89, 0x39, 0xaa, 0x9a, 0xe8, 0xb5, 0x21, 0x0e, 0xac, 0x02, 0xa9, 0xc4, 0x92, 0xd9, 0xa2, - 0x17, 0x83, 0xbd, 0x78, 0x0a, 0xda, 0x33, 0xcd, 0xa5, 0xc6, 0x44, 0xc7, 0xfc, 0xed, 0x00, 0x13 -}; - -QByteArray getLocalFlist() -{ - QByteArray flist; - - QFile flistFile("flist"); - if (!flistFile.open(QIODevice::ReadOnly)) - { - qWarning() << "getLocalFlist: Can't open local flist"; - return flist; - } - - flist = flistFile.readAll(); - flistFile.close(); - - return flist; -} - -bool isUpToDate(UpdateFileMeta fileMeta) -{ - QString appDir = qApp->applicationDirPath(); - QFile file(appDir+QDir::separator()+fileMeta.installpath); - if (!file.open(QIODevice::ReadOnly)) - return false; - - // If the data we have is corrupted or old, mark it for update - QByteArray data = file.readAll(); - if (crypto_sign_verify_detached(fileMeta.sig, (unsigned char*)data.data(), data.size(), key) != 0) - return false; - - return true; -} - -QList genUpdateDiff(QList updateFlist, Widget* w) -{ - QList diff; - - float progressDiff = 45; - float progress = 5; - - for (UpdateFileMeta file : updateFlist) - { - if (!isUpToDate(file)) - diff += file; - progress += progressDiff / updateFlist.size(); - w->setProgress(progress); - } - - return diff; -} - -QList parseFlist(QByteArray flistData) -{ - QList flist; - - if (flistData.isEmpty()) - { - qWarning() << "AutoUpdater::parseflist: Empty data"; - return flist; - } - - // Check version - if (flistData[0] != '1') - { - qWarning() << "AutoUpdater: parseflist: Bad version "<<(uint8_t)flistData[0]; - return flist; - } - flistData = flistData.mid(1); - - // Check signature - if (flistData.size() < (int)(crypto_sign_BYTES)) - { - qWarning() << "AutoUpdater::parseflist: Truncated data"; - return flist; - } - else - { - QByteArray msgData = flistData.mid(crypto_sign_BYTES); - unsigned char* msg = (unsigned char*)msgData.data(); - if (crypto_sign_verify_detached((unsigned char*)flistData.data(), msg, msgData.size(), key) != 0) - { - qCritical() << "AutoUpdater: parseflist: FORGED FLIST FILE"; - return flist; - } - flistData = flistData.mid(crypto_sign_BYTES); - } - - // Parse. We assume no errors handling needed since the signature is valid. - while (!flistData.isEmpty()) - { - UpdateFileMeta newFile; - - memcpy(newFile.sig, flistData.data(), crypto_sign_BYTES); - flistData = flistData.mid(crypto_sign_BYTES); - - newFile.id = dataToString(flistData); - flistData = flistData.mid(newFile.id.size() + getVUint32Size(flistData)); - - newFile.installpath = dataToString(flistData); - flistData = flistData.mid(newFile.installpath.size() + getVUint32Size(flistData)); - - newFile.size = dataToUint64(flistData); - flistData = flistData.mid(8); - - flist += newFile; - } - - return flist; -} +/* + Copyright © 2014 by The qTox Project + + This file is part of qTox, a Qt-based graphical interface for Tox. + + qTox is libre software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + qTox is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with qTox. If not, see +*/ + + +#include "update.h" +#include "serialize.h" +#include "widget.h" +#include +#include +#include +#include +#include + +unsigned char key[crypto_sign_PUBLICKEYBYTES] = +{ + 0x20, 0x89, 0x39, 0xaa, 0x9a, 0xe8, 0xb5, 0x21, 0x0e, 0xac, 0x02, 0xa9, 0xc4, 0x92, 0xd9, 0xa2, + 0x17, 0x83, 0xbd, 0x78, 0x0a, 0xda, 0x33, 0xcd, 0xa5, 0xc6, 0x44, 0xc7, 0xfc, 0xed, 0x00, 0x13 +}; + +QByteArray getLocalFlist() +{ + QByteArray flist; + + QFile flistFile("flist"); + if (!flistFile.open(QIODevice::ReadOnly)) + { + qWarning() << "getLocalFlist: Can't open local flist"; + return flist; + } + + flist = flistFile.readAll(); + flistFile.close(); + + return flist; +} + +bool isUpToDate(UpdateFileMeta fileMeta) +{ + QString appDir = qApp->applicationDirPath(); + QFile file(appDir+QDir::separator()+fileMeta.installpath); + if (!file.open(QIODevice::ReadOnly)) + return false; + + // If the data we have is corrupted or old, mark it for update + QByteArray data = file.readAll(); + if (crypto_sign_verify_detached(fileMeta.sig, (unsigned char*)data.data(), data.size(), key) != 0) + return false; + + return true; +} + +QList genUpdateDiff(QList updateFlist, Widget* w) +{ + QList diff; + + float progressDiff = 45; + float progress = 5; + + for (UpdateFileMeta file : updateFlist) + { + if (!isUpToDate(file)) + diff += file; + progress += progressDiff / updateFlist.size(); + w->setProgress(progress); + } + + return diff; +} + +QList parseFlist(QByteArray flistData) +{ + QList flist; + + if (flistData.isEmpty()) + { + qWarning() << "AutoUpdater::parseflist: Empty data"; + return flist; + } + + // Check version + if (flistData[0] != '1') + { + qWarning() << "AutoUpdater: parseflist: Bad version "<<(uint8_t)flistData[0]; + return flist; + } + flistData = flistData.mid(1); + + // Check signature + if (flistData.size() < (int)(crypto_sign_BYTES)) + { + qWarning() << "AutoUpdater::parseflist: Truncated data"; + return flist; + } + else + { + QByteArray msgData = flistData.mid(crypto_sign_BYTES); + unsigned char* msg = (unsigned char*)msgData.data(); + if (crypto_sign_verify_detached((unsigned char*)flistData.data(), msg, msgData.size(), key) != 0) + { + qCritical() << "AutoUpdater: parseflist: FORGED FLIST FILE"; + return flist; + } + flistData = flistData.mid(crypto_sign_BYTES); + } + + // Parse. We assume no errors handling needed since the signature is valid. + while (!flistData.isEmpty()) + { + UpdateFileMeta newFile; + + memcpy(newFile.sig, flistData.data(), crypto_sign_BYTES); + flistData = flistData.mid(crypto_sign_BYTES); + + newFile.id = dataToString(flistData); + flistData = flistData.mid(newFile.id.size() + getVUint32Size(flistData)); + + newFile.installpath = dataToString(flistData); + flistData = flistData.mid(newFile.installpath.size() + getVUint32Size(flistData)); + + newFile.size = dataToUint64(flistData); + flistData = flistData.mid(8); + + flist += newFile; + } + + return flist; +} diff --git a/updater/update.h b/updater/update.h index 13f8db17a..436d6f7d3 100644 --- a/updater/update.h +++ b/updater/update.h @@ -1,60 +1,60 @@ -/* - Copyright © 2014 by The qTox Project - - This file is part of qTox, a Qt-based graphical interface for Tox. - - qTox is libre software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - qTox is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with qTox. If not, see -*/ - - -#ifndef UPDATE_H -#define UPDATE_H - -#include -#include -#include - -class Widget; - -struct UpdateFileMeta -{ - unsigned char sig[crypto_sign_BYTES]; ///< Signature of the file (ed25519) - QString id; ///< Unique id of the file - QString installpath; ///< Local path including the file name. May be relative to qtox-updater or absolute - uint64_t size; ///< Size in bytes of the file - - bool operator==(const UpdateFileMeta& other) - { - return (size == other.size - && id == other.id && installpath == other.installpath - && memcmp(sig, other.sig, crypto_sign_BYTES) == 0); - } -}; - -struct UpdateFile -{ - UpdateFileMeta metadata; - QByteArray data; -}; - -/// Gets the local flist. Returns an empty array on error -QByteArray getLocalFlist(); -/// Parses and validates a flist file. Returns an empty list on error -QList parseFlist(QByteArray flistData); -/// Generates a list of files we need to update -QList genUpdateDiff(QList updateFlist, Widget *w); - -extern unsigned char key[crypto_sign_PUBLICKEYBYTES]; - -#endif // UPDATE_H +/* + Copyright © 2014 by The qTox Project + + This file is part of qTox, a Qt-based graphical interface for Tox. + + qTox is libre software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + qTox is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with qTox. If not, see +*/ + + +#ifndef UPDATE_H +#define UPDATE_H + +#include +#include +#include + +class Widget; + +struct UpdateFileMeta +{ + unsigned char sig[crypto_sign_BYTES]; ///< Signature of the file (ed25519) + QString id; ///< Unique id of the file + QString installpath; ///< Local path including the file name. May be relative to qtox-updater or absolute + uint64_t size; ///< Size in bytes of the file + + bool operator==(const UpdateFileMeta& other) + { + return (size == other.size + && id == other.id && installpath == other.installpath + && memcmp(sig, other.sig, crypto_sign_BYTES) == 0); + } +}; + +struct UpdateFile +{ + UpdateFileMeta metadata; + QByteArray data; +}; + +/// Gets the local flist. Returns an empty array on error +QByteArray getLocalFlist(); +/// Parses and validates a flist file. Returns an empty list on error +QList parseFlist(QByteArray flistData); +/// Generates a list of files we need to update +QList genUpdateDiff(QList updateFlist, Widget *w); + +extern unsigned char key[crypto_sign_PUBLICKEYBYTES]; + +#endif // UPDATE_H diff --git a/updater/updater.pro b/updater/updater.pro index 5373d1a72..c52a12459 100644 --- a/updater/updater.pro +++ b/updater/updater.pro @@ -1,40 +1,40 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2014-11-09T21:09:08 -# -#------------------------------------------------- - -QT += core gui - -greaterThan(QT_MAJOR_VERSION, 4): QT += widgets - -TARGET = qtox-updater -TEMPLATE = app - -CONFIG += c++11 - -QMAKE_CXXFLAGS += -fno-exceptions - -SOURCES += main.cpp\ - widget.cpp \ - update.cpp \ - serialize.cpp - -HEADERS += widget.h \ - update.h \ - serialize.h - -FORMS += widget.ui - -RESOURCES += \ - res.qrc - -INCLUDEPATH += libs/include - -RC_FILE = windows/updater.rc - -LIBS += -L$$PWD/libs/lib/ -lsodium - -win32 { - LIBS += -lshell32 -luuid -} +#------------------------------------------------- +# +# Project created by QtCreator 2014-11-09T21:09:08 +# +#------------------------------------------------- + +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = qtox-updater +TEMPLATE = app + +CONFIG += c++11 + +QMAKE_CXXFLAGS += -fno-exceptions + +SOURCES += main.cpp\ + widget.cpp \ + update.cpp \ + serialize.cpp + +HEADERS += widget.h \ + update.h \ + serialize.h + +FORMS += widget.ui + +RESOURCES += \ + res.qrc + +INCLUDEPATH += libs/include + +RC_FILE = windows/updater.rc + +LIBS += -L$$PWD/libs/lib/ -lsodium + +win32 { + LIBS += -lshell32 -luuid +} diff --git a/updater/widget.cpp b/updater/widget.cpp index bb3a86aa8..7ea863c46 100644 --- a/updater/widget.cpp +++ b/updater/widget.cpp @@ -1,338 +1,338 @@ -/* - Copyright © 2014 by The qTox Project - - This file is part of qTox, a Qt-based graphical interface for Tox. - - qTox is libre software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - qTox is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with qTox. If not, see -*/ - - -#include "widget.h" -#include "ui_widget.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "update.h" - -#ifdef Q_OS_WIN -#ifdef _WIN32_WINNT -#undef _WIN32_WINNT -#endif -#define _WIN32_WINNT 0x0600 // Vista for SHGetKnownFolderPath -#include -#include -#include -#include - -const bool supported = true; -const QString QTOX_PATH = "qtox.exe"; -#else -const bool supported = false; -const QString QTOX_PATH; -#endif -const QString SETTINGS_FILE = "settings.ini"; - -Widget::Widget(QWidget *parent) : - QWidget(parent), - ui(new Ui::Widget) -{ - ui->setupUi(this); - - // Updates only for supported platforms - if (!supported) - fatalError(tr("The qTox updater is not supported on this platform.")); - -#ifdef Q_OS_WIN - // Get a primary unelevated token of the actual user - hPrimaryToken = nullptr; - HANDLE hShellProcess = nullptr, hShellProcessToken = nullptr; - const DWORD dwTokenRights = TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_ASSIGN_PRIMARY - | TOKEN_DUPLICATE | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID; - DWORD dwPID = 0; - HWND hwnd = nullptr; - DWORD dwLastErr = 0; - - // Enable SeIncreaseQuotaPrivilege - HANDLE hProcessToken = NULL; - if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hProcessToken)) - goto unelevateFail; - TOKEN_PRIVILEGES tkp; - tkp.PrivilegeCount = 1; - LookupPrivilegeValueW(NULL, SE_INCREASE_QUOTA_NAME, &tkp.Privileges[0].Luid); - tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - AdjustTokenPrivileges(hProcessToken, FALSE, &tkp, 0, NULL, NULL); - dwLastErr = GetLastError(); - CloseHandle(hProcessToken); - if (ERROR_SUCCESS != dwLastErr) - goto unelevateFail; - - // Get a primary copy of the desktop shell's token, - // we're assuming the shell is running as the actual user - hwnd = GetShellWindow(); - if (!hwnd) - goto unelevateFail; - GetWindowThreadProcessId(hwnd, &dwPID); - if (!dwPID) - goto unelevateFail; - hShellProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPID); - if (!hShellProcess) - goto unelevateFail; - if (!OpenProcessToken(hShellProcess, TOKEN_DUPLICATE, &hShellProcessToken)) - goto unelevateFail; - - // Duplicate the shell's process token to get a primary token. - // Based on experimentation, this is the minimal set of rights required for CreateProcessWithTokenW (contrary to current documentation). - if (!DuplicateTokenEx(hShellProcessToken, dwTokenRights, NULL, SecurityImpersonation, TokenPrimary, &hPrimaryToken)) - goto unelevateFail; - - qDebug() << "Unelevated primary access token acquired"; - goto unelevateCleanup; -unelevateFail: - qWarning() << "Unelevate failed, couldn't get access token"; -unelevateCleanup: - CloseHandle(hShellProcessToken); - CloseHandle(hShellProcess); -#endif - - QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection); -} - -Widget::~Widget() -{ -#ifdef Q_OS_WIN - CloseHandle(hPrimaryToken); -#endif - delete ui; -} - -void Widget::setProgress(int value) -{ - ui->progress->setValue(value); - ui->progress->repaint(); - qApp->processEvents(); -} - -void Widget::fatalError(QString message) -{ - qCritical() << "Update aborted with error:"< updateFlist = parseFlist(updateFlistData); - setProgress(5); - - /// 2. Generate a diff (5-50%) - QList diff = genUpdateDiff(updateFlist, this); - for (UpdateFileMeta fileMeta : diff) - if (!QFile::exists(updateDirStr+fileMeta.installpath)) - fatalError(tr("The update is incomplete.")); - - if (diff.size() == 0) - fatalError(tr("The update is empty!")); - setProgress(50); - qDebug() << "Diff generated,"< +*/ + + +#include "widget.h" +#include "ui_widget.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "update.h" + +#ifdef Q_OS_WIN +#ifdef _WIN32_WINNT +#undef _WIN32_WINNT +#endif +#define _WIN32_WINNT 0x0600 // Vista for SHGetKnownFolderPath +#include +#include +#include +#include + +const bool supported = true; +const QString QTOX_PATH = "qtox.exe"; +#else +const bool supported = false; +const QString QTOX_PATH; +#endif +const QString SETTINGS_FILE = "settings.ini"; + +Widget::Widget(QWidget *parent) : + QWidget(parent), + ui(new Ui::Widget) +{ + ui->setupUi(this); + + // Updates only for supported platforms + if (!supported) + fatalError(tr("The qTox updater is not supported on this platform.")); + +#ifdef Q_OS_WIN + // Get a primary unelevated token of the actual user + hPrimaryToken = nullptr; + HANDLE hShellProcess = nullptr, hShellProcessToken = nullptr; + const DWORD dwTokenRights = TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_ASSIGN_PRIMARY + | TOKEN_DUPLICATE | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID; + DWORD dwPID = 0; + HWND hwnd = nullptr; + DWORD dwLastErr = 0; + + // Enable SeIncreaseQuotaPrivilege + HANDLE hProcessToken = NULL; + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hProcessToken)) + goto unelevateFail; + TOKEN_PRIVILEGES tkp; + tkp.PrivilegeCount = 1; + LookupPrivilegeValueW(NULL, SE_INCREASE_QUOTA_NAME, &tkp.Privileges[0].Luid); + tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + AdjustTokenPrivileges(hProcessToken, FALSE, &tkp, 0, NULL, NULL); + dwLastErr = GetLastError(); + CloseHandle(hProcessToken); + if (ERROR_SUCCESS != dwLastErr) + goto unelevateFail; + + // Get a primary copy of the desktop shell's token, + // we're assuming the shell is running as the actual user + hwnd = GetShellWindow(); + if (!hwnd) + goto unelevateFail; + GetWindowThreadProcessId(hwnd, &dwPID); + if (!dwPID) + goto unelevateFail; + hShellProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPID); + if (!hShellProcess) + goto unelevateFail; + if (!OpenProcessToken(hShellProcess, TOKEN_DUPLICATE, &hShellProcessToken)) + goto unelevateFail; + + // Duplicate the shell's process token to get a primary token. + // Based on experimentation, this is the minimal set of rights required for CreateProcessWithTokenW (contrary to current documentation). + if (!DuplicateTokenEx(hShellProcessToken, dwTokenRights, NULL, SecurityImpersonation, TokenPrimary, &hPrimaryToken)) + goto unelevateFail; + + qDebug() << "Unelevated primary access token acquired"; + goto unelevateCleanup; +unelevateFail: + qWarning() << "Unelevate failed, couldn't get access token"; +unelevateCleanup: + CloseHandle(hShellProcessToken); + CloseHandle(hShellProcess); +#endif + + QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection); +} + +Widget::~Widget() +{ +#ifdef Q_OS_WIN + CloseHandle(hPrimaryToken); +#endif + delete ui; +} + +void Widget::setProgress(int value) +{ + ui->progress->setValue(value); + ui->progress->repaint(); + qApp->processEvents(); +} + +void Widget::fatalError(QString message) +{ + qCritical() << "Update aborted with error:"< updateFlist = parseFlist(updateFlistData); + setProgress(5); + + /// 2. Generate a diff (5-50%) + QList diff = genUpdateDiff(updateFlist, this); + for (UpdateFileMeta fileMeta : diff) + if (!QFile::exists(updateDirStr+fileMeta.installpath)) + fatalError(tr("The update is incomplete.")); + + if (diff.size() == 0) + fatalError(tr("The update is empty!")); + setProgress(50); + qDebug() << "Diff generated,"< -*/ - - -#ifndef WIDGET_H -#define WIDGET_H - -#include - -#ifdef Q_OS_WIN -#include -#endif - -namespace Ui { -class Widget; -} - -class Widget : public QWidget -{ - Q_OBJECT - -public: - explicit Widget(QWidget *parent = 0); - ~Widget(); - - // Utilities - void deleteBackups(); - void restoreBackups(); - void setProgress(int value); - QString getSettingsDirPath(); - bool isToxPortableEnabled(); - - // Noreturn - void fatalError(QString message); ///< Calls deleteUpdate and startQToxAndExit - void deleteUpdate(); - void startQToxAndExit(); - -public slots: - // Finds and applies the update - void update(); - -private: - Ui::Widget *ui; - QStringList backups; - -#ifdef Q_OS_WIN - HANDLE hPrimaryToken; -#endif -}; - -#endif // WIDGET_H +/* + Copyright © 2014 by The qTox Project + + This file is part of qTox, a Qt-based graphical interface for Tox. + + qTox is libre software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + qTox is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with qTox. If not, see +*/ + + +#ifndef WIDGET_H +#define WIDGET_H + +#include + +#ifdef Q_OS_WIN +#include +#endif + +namespace Ui { +class Widget; +} + +class Widget : public QWidget +{ + Q_OBJECT + +public: + explicit Widget(QWidget *parent = 0); + ~Widget(); + + // Utilities + void deleteBackups(); + void restoreBackups(); + void setProgress(int value); + QString getSettingsDirPath(); + bool isToxPortableEnabled(); + + // Noreturn + void fatalError(QString message); ///< Calls deleteUpdate and startQToxAndExit + void deleteUpdate(); + void startQToxAndExit(); + +public slots: + // Finds and applies the update + void update(); + +private: + Ui::Widget *ui; + QStringList backups; + +#ifdef Q_OS_WIN + HANDLE hPrimaryToken; +#endif +}; + +#endif // WIDGET_H diff --git a/updater/widget.ui b/updater/widget.ui index b7959ea0b..507ff9f04 100644 --- a/updater/widget.ui +++ b/updater/widget.ui @@ -1,139 +1,139 @@ - - - Widget - - - - 0 - 0 - 401 - 224 - - - - qTox Updater - - - - :/res/qtox-256x256.png:/res/qtox-256x256.png - - - - - 0 - 13 - 191 - 191 - - - - - - - :/res/qtox-256x256.png - - - true - - - - - - 206 - 95 - 171 - 20 - - - - 0 - - - 0 - - - Qt::AlignCenter - - - false - - - - - - 205 - 115 - 171 - 20 - - - - Updating qTox ... - - - Qt::AlignCenter - - - - - - 201 - 170 - 181 - 20 - - - - <html><head/><body><p><a href="https://tox.chat"><span style=" text-decoration: underline; color:#0000ff;">https://tox.chat</span></a></p></body></html> - - - Qt::AlignCenter - - - true - - - - - - 200 - 183 - 181 - 20 - - - - <a href="https://github.com/tux3/qtox">https://github.com/tux3/qtox</a> - - - Qt::AlignCenter - - - - - - 195 - 32 - 191 - 31 - - - - - 14 - - - - qTox Update - - - Qt::AlignCenter - - - - - - - - - + + + Widget + + + + 0 + 0 + 401 + 224 + + + + qTox Updater + + + + :/res/qtox-256x256.png:/res/qtox-256x256.png + + + + + 0 + 13 + 191 + 191 + + + + + + + :/res/qtox-256x256.png + + + true + + + + + + 206 + 95 + 171 + 20 + + + + 0 + + + 0 + + + Qt::AlignCenter + + + false + + + + + + 205 + 115 + 171 + 20 + + + + Updating qTox ... + + + Qt::AlignCenter + + + + + + 201 + 170 + 181 + 20 + + + + <html><head/><body><p><a href="https://tox.chat"><span style=" text-decoration: underline; color:#0000ff;">https://tox.chat</span></a></p></body></html> + + + Qt::AlignCenter + + + true + + + + + + 200 + 183 + 181 + 20 + + + + <a href="https://github.com/tux3/qtox">https://github.com/tux3/qtox</a> + + + Qt::AlignCenter + + + + + + 195 + 32 + 191 + 31 + + + + + 14 + + + + qTox Update + + + Qt::AlignCenter + + + + + + + + + diff --git a/updater/windows/updater.exe.manifest b/updater/windows/updater.exe.manifest index 626d284d9..a6e206c80 100644 --- a/updater/windows/updater.exe.manifest +++ b/updater/windows/updater.exe.manifest @@ -1,12 +1,12 @@ - - - - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/updater/windows/updater.rc b/updater/windows/updater.rc index e47abcc22..80d03bd3a 100644 --- a/updater/windows/updater.rc +++ b/updater/windows/updater.rc @@ -1,2 +1,2 @@ -ID_ICON ICON DISCARDABLE "updater.ico" +ID_ICON ICON DISCARDABLE "updater.ico" 1 24 "updater.exe.manifest" \ No newline at end of file From 94e467e561db2b85c21e849a2b610ec0218dd741 Mon Sep 17 00:00:00 2001 From: Zetok Zalbavar Date: Fri, 15 Jan 2016 16:49:54 +0000 Subject: [PATCH 092/210] INSTALL.md: correct link and mention sqlcipher for fedora dependencies --- INSTALL.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/INSTALL.md b/INSTALL.md index 1ad602402..8a152932f 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -192,11 +192,16 @@ sudo apt-get install build-essential qt5-qmake qt5-default qttools5-dev-tools li
#### Fedora: +**Note that sqlcipher is not included in Fedora(!).** + +**This means that you have to compile sqlcipher yourself, otherwise compiling qTox will fail.** ```bash sudo dnf group install "Development Tools" sudo dnf install qt-devel qt-doc qt-creator qt5-qtsvg qt5-qtsvg-devel openal-soft-devel libXScrnSaver-devel qrencode-devel ffmpeg-devel qtsingleapplication qt5-linguist gtk2-devel ``` +**Go to [sqlcipher](#sqlcipher) section to compile it.** + #### openSUSE: @@ -372,7 +377,7 @@ sudo make install ### sqlcipher -If you are not using Fedora, skip this section, and go directly to installing [**toxcore**](#toxcore-dependencies). +If you are not using Fedora, skip this section, and go directly to compiling [**toxcore**](#toxcore-compiling). ```bash git clone https://github.com/sqlcipher/sqlcipher From 4806e684faf6510f55f909b0470190f30408519b Mon Sep 17 00:00:00 2001 From: tux3 Date: Fri, 15 Jan 2016 17:56:51 +0100 Subject: [PATCH 093/210] Cherry-pick HTTP(S) toxme lookups from #2753 Implementation by @Diadlo --- src/net/toxme.cpp | 241 +++++++++++++++++++++++++----- src/net/toxme.h | 30 +++- src/widget/form/addfriendform.cpp | 1 + 3 files changed, 225 insertions(+), 47 deletions(-) diff --git a/src/net/toxme.cpp b/src/net/toxme.cpp index 3b92cd354..8fdbe4fb3 100644 --- a/src/net/toxme.cpp +++ b/src/net/toxme.cpp @@ -17,7 +17,6 @@ along with qTox. If not, see . */ - #include "toxme.h" #include "src/core/core.h" #include @@ -29,25 +28,69 @@ #include #include -const QString Toxme::apiUrl{"https://toxme.se/api"}; - -const unsigned char Toxme::pinnedPk[] = {0x5D, 0x72, 0xC5, 0x17, 0xDF, 0x6A, 0xEC, 0x54, 0xF1, 0xE9, 0x77, 0xA6, 0xB6, 0xF2, 0x59, 0x14, - 0xEA, 0x4C, 0xF7, 0x27, 0x7A, 0x85, 0x02, 0x7C, 0xD9, 0xF5, 0x19, 0x6D, 0xF1, 0x7E, 0x0B, 0x13}; - -QByteArray Toxme::makeJsonRequest(QString json) +QByteArray Toxme::makeJsonRequest(QString url, QString json, QNetworkReply::NetworkError &error) { - QNetworkAccessManager netman; - QNetworkRequest request{apiUrl}; - request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + if (error) + return QByteArray(); + QNetworkAccessManager netman; + QNetworkRequest request{url}; + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); QNetworkReply* reply = netman.post(request,json.toUtf8()); - while (!reply->isFinished()) + + while (reply->isRunning()) { + error = reply->error(); + if (error) + break; + + reply->waitForReadyRead(100); qApp->processEvents(); + } return reply->readAll(); } -QByteArray Toxme::prepareEncryptedJson(int action, QString payload) +QByteArray Toxme::getServerPubkey(QString url, QNetworkReply::NetworkError &error) +{ + if (error) + return QByteArray(); + + // Get key + QNetworkAccessManager netman; + QNetworkRequest request{url}; + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + QNetworkReply* reply = netman.get(request); + + while (reply->isRunning()) { + error = reply->error(); + if (error) + break; + + reply->waitForReadyRead(100); + qApp->processEvents(); + } + + // Extract key + static const QByteArray pattern{"key\":\""}; + + QString json = reply->readAll(); + json = json.remove(' '); + int start = json.indexOf(pattern) + pattern.length(); + int end = json.indexOf("\"", start); + int pubkeySize = (end - start) / 2; + QString rawKey = json.mid(start, pubkeySize*2); + + QByteArray key; + // I think, exist more easy way to convert key to ByteArray + for (int i = 0; i < pubkeySize; i++) { + QString byte = rawKey.mid(i*2, 2); + key[i] = byte.toInt(nullptr, 16); + } + + return key; +} + +QByteArray Toxme::prepareEncryptedJson(QString url, int action, QString payload) { QPair keypair = Core::getInstance()->getKeypair(); if (keypair.first.isEmpty() || keypair.second.isEmpty()) @@ -56,6 +99,11 @@ QByteArray Toxme::prepareEncryptedJson(int action, QString payload) return QByteArray(); } + QNetworkReply::NetworkError error = QNetworkReply::NoError; + QByteArray key = getServerPubkey(url, error); + if (error != QNetworkReply::NoError) + return QByteArray(); + QByteArray nonce(crypto_box_NONCEBYTES, 0); randombytes((uint8_t*)nonce.data(), crypto_box_NONCEBYTES); @@ -63,8 +111,13 @@ QByteArray Toxme::prepareEncryptedJson(int action, QString payload) const size_t cypherlen = crypto_box_MACBYTES+payloadData.size(); unsigned char* payloadEnc = new unsigned char[cypherlen]; - crypto_box_easy(payloadEnc,(uint8_t*)payloadData.data(),payloadData.size(), - (uint8_t*)nonce.data(),pinnedPk,(uint8_t*)keypair.second.data()); + int cryptResult = crypto_box_easy(payloadEnc,(uint8_t*)payloadData.data(),payloadData.size(), + (uint8_t*)nonce.data(),(unsigned char*)key.constData(), + (uint8_t*)keypair.second.data()); + + if (cryptResult != 0) // error + return QByteArray(); + QByteArray payloadEncData(reinterpret_cast(payloadEnc), cypherlen); delete[] payloadEnc; @@ -78,88 +131,196 @@ QByteArray Toxme::prepareEncryptedJson(int action, QString payload) ToxId Toxme::lookup(QString address) { // JSON injection ? + address = address.trimmed(); address.replace('\\',"\\\\"); address.replace('"',"\""); - ToxId id; const QString json{"{\"action\":3,\"name\":\""+address+"\"}"}; - static const QByteArray pattern{"public_key\""}; - QByteArray response = makeJsonRequest(json); + QString apiUrl = "https://" + address.split(QLatin1Char('@')).last() + "/api"; + QNetworkReply::NetworkError error = QNetworkReply::NoError; + QByteArray response = makeJsonRequest(apiUrl, json, error); + + if (error != QNetworkReply::NoError) + return ToxId(); + + static const QByteArray pattern{"tox_id\""}; const int index = response.indexOf(pattern); if (index == -1) - return id; + return ToxId(); response = response.mid(index+pattern.size()); const int idStart = response.indexOf('"'); if (idStart == -1) - return id; + return ToxId(); response = response.mid(idStart+1); const int idEnd = response.indexOf('"'); if (idEnd == -1) - return id; + return ToxId(); response.truncate(idEnd); - id = ToxId(response); - return id; + return ToxId(response); } -int Toxme::extractError(QString json) +Toxme::ExecCode Toxme::extractError(QString json) { static const QByteArray pattern{"c\":"}; + if (json.isEmpty()) + return ServerError; + json = json.remove(' '); - const int index = json.indexOf(pattern); - if (index == -1) - return INT_MIN; + const int start = json.indexOf(pattern); + if (start == -1) + return ServerError; - json = json.mid(index+pattern.size()); - - const int end = json.indexOf('}'); + json = json.mid(start+pattern.size()); + int end = json.indexOf(","); if (end == -1) - return INT_MIN; + { + end = json.indexOf("}"); + if (end == -1) + return IncorrectResponce; + } json.truncate(end); - bool ok; int r = json.toInt(&ok); if (!ok) - return INT_MIN; + return IncorrectResponce; - return r; + return ExecCode(r); } -bool Toxme::createAddress(ToxId id, QString address, - bool keepPrivate, QString bio) +QString Toxme::createAddress(ExecCode &code, QString server, ToxId id, QString address, + bool keepPrivate, QString bio) { int privacy = keepPrivate ? 0 : 2; // JSON injection ? bio.replace('\\',"\\\\"); bio.replace('"',"\""); + address.replace('\\',"\\\\"); address.replace('"',"\""); + bio = bio.trimmed(); + address = address.trimmed(); + server = server.trimmed(); + if (!server.contains("://")) + server = "https://" + server; + const QString payload{"{\"tox_id\":\""+id.toString()+"\"," "\"name\":\""+address+"\"," "\"privacy\":"+QString().setNum(privacy)+"," "\"bio\":\""+bio+"\"," "\"timestamp\":"+QString().setNum(time(0))+"}"}; - QByteArray response = makeJsonRequest(prepareEncryptedJson(1,payload)); + qDebug() << payload; + QString pubkeyUrl = server + "/pk"; + QString apiUrl = server + "/api"; + QNetworkReply::NetworkError error = QNetworkReply::NoError; + QByteArray response = makeJsonRequest(apiUrl, prepareEncryptedJson(pubkeyUrl, 1, payload), error); + qDebug() << response; - return (extractError(response) == 0); + code = extractError(response); + if ((code != Registered && code != Updated) || error != QNetworkReply::NoError) + return QString(); + + return getPass(response, code); } -bool Toxme::deleteAddress(ToxId id) +QString Toxme::getPass(QString json, ExecCode &code) { + static const QByteArray pattern{"password\":"}; + + json = json.remove(' '); + const int start = json.indexOf(pattern); + if (start == -1) + { + code = NoPassword; + return QString(); + } + + json = json.mid(start+pattern.size()); + if (json.startsWith("null")) + { + code = Updated; + return QString(); + } + + json = json.mid(1, json.length()); + int end = json.indexOf("\""); + if (end == -1) + { + code = IncorrectResponce; + return QString(); + } + + json.truncate(end); + + return json; +} + +int Toxme::deleteAddress(QString server, ToxId id) { const QString payload{"{\"public_key\":\""+id.toString().left(64)+"\"," "\"timestamp\":"+QString().setNum(time(0))+"}"}; - QByteArray response = makeJsonRequest(prepareEncryptedJson(2,payload)); + server = server.trimmed(); + if (!server.contains("://")) + server = "https://" + server; - return (extractError(response) == 0); + QString pubkeyUrl = server + "/pk"; + QString apiUrl = server + "/api"; + QNetworkReply::NetworkError error = QNetworkReply::NoError; + QByteArray response = makeJsonRequest(apiUrl, prepareEncryptedJson(pubkeyUrl, 2, payload), error); + if (error != QNetworkReply::NoError) + return error; + + return extractError(response); +} + +QString Toxme::getErrorMessage(int errorCode) +{ + switch (errorCode) { + case IncorrectResponce: + return QObject::tr("Incorrect responce"); + case NoPassword: + return QObject::tr("No password in response"); + case ServerError: + return QObject::tr("Server doesn't support Toxme"); + case -1: + return QObject::tr("You must send POST requests to /api"); + case -2: + return QObject::tr("Please try again using a HTTPS connection"); + case -3: + return QObject::tr("I was unable to read your encrypted payload"); + case -4: + return QObject::tr("You're making too many requests. Wait an hour and try again"); + case -25: + return QObject::tr("This name is already in use"); + case -26: + return QObject::tr("This Tox ID is already registered under another name"); + case -27: + return QObject::tr("Please don't use a space in your name"); + case -28: + return QObject::tr("Password incorrect"); + case -29: + return QObject::tr("You can't use this name"); + case -30: + return QObject::tr("Name not found"); + case -31: + return QObject::tr("Tox ID not sent"); + case -41: + return QObject::tr("Lookup failed because the other server replied with invalid data"); + case -42: + return QObject::tr("That user does not exist"); + case -43: + return QObject::tr("Internal lookup error. Please file a bug"); + default: + return QObject::tr("Unknown error (%1)").arg(errorCode); + } } diff --git a/src/net/toxme.h b/src/net/toxme.h index 2e98f9257..4f36806e1 100644 --- a/src/net/toxme.h +++ b/src/net/toxme.h @@ -22,7 +22,9 @@ #define TOXME_H #include +#include #include +#include #include #include "src/core/toxid.h" @@ -34,25 +36,39 @@ class QNetworkAccessManager; class Toxme { public: + enum ExecCode { + ExecError = -50, + Registered = 0, + Updated = 1, + ServerError = 2, + IncorrectResponce = 3, + NoPassword = 4 + }; + /// Converts a toxme.se address to a Tox ID, returns an empty ID on error static ToxId lookup(QString address); /// Creates a new toxme.se address associated with a Tox ID. /// If keepPrivate, the address will not be published on toxme.se /// The bio is a short optional description of yourself if you want to publish your address. - static bool createAddress(ToxId id, QString address, + /// If it passed without error, return password, else return errorCode in QString + static QString createAddress(ExecCode &code, QString server, ToxId id, QString address, bool keepPrivate=true, QString bio=QString()); /// Deletes the address associated with your current Tox ID - static bool deleteAddress(ToxId id); + static int deleteAddress(QString server, ToxId id); + /// Return string of the corresponding error code + static QString getErrorMessage(int errorCode); private: Toxme()=delete; - static QByteArray makeJsonRequest(QString json); - static QByteArray prepareEncryptedJson(int action, QString payload); - static int extractError(QString json); + static QByteArray makeJsonRequest(QString url, QString json, QNetworkReply::NetworkError &error); + static QByteArray prepareEncryptedJson(QString url, int action, QString payload); + static QByteArray getServerPubkey(QString url, QNetworkReply::NetworkError &error); + static QString getPass(QString json, ExecCode &code); + static ExecCode extractError(QString json); private: - static const QString apiUrl; - static const unsigned char pinnedPk[]; + static const QMap pubkeyUrls; + static const QMap apiUrls; }; #endif // TOXME_H diff --git a/src/widget/form/addfriendform.cpp b/src/widget/form/addfriendform.cpp index b55aa8389..cf62b6bb2 100644 --- a/src/widget/form/addfriendform.cpp +++ b/src/widget/form/addfriendform.cpp @@ -34,6 +34,7 @@ #include "src/widget/gui.h" #include "src/widget/translator.h" #include "src/widget/contentlayout.h" +#include "src/net/toxme.h" #include AddFriendForm::AddFriendForm() From 7179ed472222846e5156b59722a00ac002c7cb29 Mon Sep 17 00:00:00 2001 From: Diadlo Date: Wed, 30 Dec 2015 23:00:20 +0300 Subject: [PATCH 094/210] Add Toxme lookup support qTox will try Toxme, and if Toxme not supported, ToxDNS --- src/widget/form/addfriendform.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/widget/form/addfriendform.cpp b/src/widget/form/addfriendform.cpp index cf62b6bb2..03d30c2bd 100644 --- a/src/widget/form/addfriendform.cpp +++ b/src/widget/form/addfriendform.cpp @@ -129,14 +129,16 @@ Ignore the proxy and connect to the Internet directly?"), QMessageBox::Yes|QMess return; } - ToxId toxId = ToxDNS::resolveToxAddress(id, true); - - if (toxId.toString().isEmpty()) + ToxId toxId = Toxme::lookup(id); // Try Toxme + if (toxId.toString().isEmpty()) // If it isn't supported { - GUI::showWarning(tr("Couldn't add friend"), tr("This Tox ID does not exist","DNS error")); - return; + toxId = ToxDNS::resolveToxAddress(id, true); // Use ToxDNS + if (toxId.toString().isEmpty()) + { + GUI::showWarning(tr("Couldn't add friend"), tr("This Tox ID does not exist","DNS error")); + return; + } } - emit friendRequested(toxId.toString(), getMessage()); this->toxId.clear(); this->message.clear(); From bb9b1a4e32db31a5bacd637368ba6453d45a3120 Mon Sep 17 00:00:00 2001 From: Diadlo Date: Thu, 31 Dec 2015 14:35:22 +0300 Subject: [PATCH 095/210] Add Toxme support in Toxuri handle --- src/net/toxuri.cpp | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/net/toxuri.cpp b/src/net/toxuri.cpp index a408a79c7..d4c8714cb 100644 --- a/src/net/toxuri.cpp +++ b/src/net/toxuri.cpp @@ -20,6 +20,7 @@ #include "src/net/toxuri.h" #include "src/net/toxdns.h" +#include "src/net/toxme.h" #include "src/widget/tool/friendrequestdialog.h" #include "src/nexus.h" #include "src/core/core.h" @@ -62,20 +63,22 @@ bool handleToxURI(const QString &toxURI) else toxaddr = toxURI.mid(4); - QString toxid = ToxDNS::resolveToxAddress(toxaddr, true).toString(); + QString toxId = Toxme::lookup(toxaddr).toString(); + if (toxId.isEmpty()) + { + toxId = ToxDNS::resolveToxAddress(toxaddr, true).toString(); + if (toxId.isEmpty()) + { + QMessageBox::warning(0, "qTox", toxaddr + " is not a valid Tox address."); + return false; + } + } - if (toxid.isEmpty()) - { - QMessageBox::warning(0, "qTox", toxaddr + " is not a valid Tox address."); - } - else - { - ToxURIDialog dialog(0, toxaddr, QObject::tr("%1 here! Tox me maybe?", - "Default message in Tox URI friend requests. Write something appropriate!") - .arg(Nexus::getCore()->getUsername())); - if (dialog.exec() == QDialog::Accepted) - Core::getInstance()->requestFriendship(toxid, dialog.getRequestMessage()); - } + ToxURIDialog dialog(0, toxaddr, QObject::tr("%1 here! Tox me maybe?", + "Default message in Tox URI friend requests. Write something appropriate!") + .arg(Nexus::getCore()->getUsername())); + if (dialog.exec() == QDialog::Accepted) + Core::getInstance()->requestFriendship(toxId, dialog.getRequestMessage()); return true; } From 50081a51d2237fc850e4a720a3cb6059fb9c8a77 Mon Sep 17 00:00:00 2001 From: sudden6 Date: Fri, 15 Jan 2016 22:04:39 +0100 Subject: [PATCH 096/210] remove last todos --- doc/user_manual_en.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/user_manual_en.md b/doc/user_manual_en.md index 0215ba973..2ddb10321 100644 --- a/doc/user_manual_en.md +++ b/doc/user_manual_en.md @@ -28,7 +28,7 @@ qTox allows you to use multiple Tox IDs with different profiles, which each can + _Current profile:_ Shows the filename which stores your information. + _Current profile locatation:_ Shows the path to the profile file. + _Rename_ This button allows you to rename your profile. Your nickname and profile name don't have to be the same. -+ _Delete_ This button deletes your profile. ++ _Delete_ This button deletes your profile and the corresponding chat history. + _Export_ Allows you to export your profile in a format compatible with other Tox clients. You can also manually backup your *.tox files. + _Logout_ Close your current profile and show the login window. + _Remove password_ If you set a password for your profile, you can remove it with this button. @@ -63,7 +63,7 @@ qTox allows you to use multiple Tox IDs with different profiles, which each can #### Theme * _Use emoticons:_ If enabled, qTox will replace simleys ( e.g. :-) ) with Unicode emoticons. -* _Smiley Pack:_ You can choose from different sets of shiped emoticon styles. You can also install your own, see ??? for details +* _Smiley Pack:_ You can choose from different sets of shiped emoticon styles. * _Emoticon size:_ You can change the size of the emoticons here. * _Style:_ Changes the appearance of qTox. * _Theme color:_ Changes the colors qTox uses. @@ -87,7 +87,7 @@ Most users will want the two settings enabled, but if qTox crashes your router, #### NoSpam -NoSpam is a feature of Tox to prevent someone spamming you with friend requests. If you get spammed, enter or generate a new NoSpam value, this will alter your Tox ID. You don't need to tell your existing contacts your new Tox ID, but you have to tell new contacts your new Tox ID. Your Tox ID can be found ??? +NoSpam is a feature of Tox to prevent someone spamming you with friend requests. If you get spammed, enter or generate a new NoSpam value, this will alter your Tox ID. You don't need to tell your existing contacts your new Tox ID, but you have to tell new contacts your new Tox ID. Your Tox ID can be found in your [User Profile](#user-profile) ### Audio/Video #### Audio Settings @@ -117,7 +117,7 @@ NoSpam is a feature of Tox to prevent someone spamming you with friend requests. ## Groupchats -Groupchats are a way to talk with multiple friends at the same time, like when you are standing together in a group. To create a groupchat click the groupchat icon and set a name. Now you can invite people by right clicking on the contact and selecting "Invite to group". Currently, if the last person leaves the chat, it is closed and you have to create a new one. +Groupchats are a way to talk with multiple friends at the same time, like when you are standing together in a group. To create a groupchat click the groupchat icon and set a name. Now you can invite people by right clicking on the contact and selecting "Invite to group". Currently, if the last person leaves the chat, it is closed and you have to create a new one. Sending files and videochats are currently unsupported in groupchats. ## Multi Window Mode From 376d685b25b7a6156a352dbfae19defb730979bb Mon Sep 17 00:00:00 2001 From: sudden6 Date: Fri, 15 Jan 2016 22:53:55 +0100 Subject: [PATCH 097/210] slight clarifications in manual --- doc/user_manual_en.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/user_manual_en.md b/doc/user_manual_en.md index 2ddb10321..bd5b0a849 100644 --- a/doc/user_manual_en.md +++ b/doc/user_manual_en.md @@ -47,13 +47,13 @@ qTox allows you to use multiple Tox IDs with different profiles, which each can * _Auto away after (0 to disable):_ After the specified amount of time, qTox will set your Status to "Away". A setting of 0 will never change your status. * _Default directory to save files:_ You can set the directory where qTox puts files you recieved here. -* _Autoaccept files:_ If set, qTox will automatically accept filetransfers and put them in the directory specified above. +* _Autoaccept files:_ If set, qTox will automatically accept file transfers and put them in the directory specified above. #### Chat * _Play sound:_ If checked, qTox will play a sound when you get a new message. * _Open window:_ If checked, the qTox window will be opened. If you use the multiple windows mode, see [Multi Window Mode](#multi-window-mode) for details. * _Focus window:_ If checked, the qTox window will additionally be focused. -* _Show contacts' status changes:_ If set, qTox will show contact status changes in your chat history. +* _Show contacts' status changes:_ If set, qTox will show contact status changes in your chat window. * _Group chats always notify:_ If set, qTox will notify you on every new message in a groupchat. * _Place groupchats at top of friend list:_ If checked, your groupchats will be at the top of the contacts list, else they will be sorted with your other contacts. * _Faux offline messaging:_ If enabled, qTox will attempt to send messages when a currently offline contact comes online again. From c408cf404541490ea88277dac3e77e550dc2c1c7 Mon Sep 17 00:00:00 2001 From: sudden6 Date: Fri, 15 Jan 2016 22:56:34 +0100 Subject: [PATCH 098/210] Add user manual in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6c00c362f..9dba892ca 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ qTox [![Build Status](https://travis-ci.org/tux3/qTox.svg)](https://travis-ci.org/tux3/qTox) ====== - [**Compile**](/INSTALL.md) **⦁** [**Contribute**](https://github.com/tux3/qTox/wiki#contributing) **⦁** [**Report bugs**](https://github.com/tux3/qTox/wiki/Writing-Useful-Bug-Reports) **⦁** [**Translate**](https://github.com/tux3/qTox/wiki/Translating) **⦁** [**Jenkins builds**](https://build.tox.chat/) **⦁** [**Keyboard shortcuts**](https://github.com/tux3/qTox/wiki/Keyboard-shortcuts) **⦁** [**Mailing list**](https://lists.tox.chat) **⦁** **IRC Channel:** [#qtox@freenode](https://webchat.freenode.net/?channels=qtox) + [**User Manual**](/doc/user_manual_en.md) **⦁** [**Compile**](/INSTALL.md) **⦁** [**Contribute**](https://github.com/tux3/qTox/wiki#contributing) **⦁** [**Report bugs**](https://github.com/tux3/qTox/wiki/Writing-Useful-Bug-Reports) **⦁** [**Translate**](https://github.com/tux3/qTox/wiki/Translating) **⦁** [**Jenkins builds**](https://build.tox.chat/) **⦁** [**Keyboard shortcuts**](https://github.com/tux3/qTox/wiki/Keyboard-shortcuts) **⦁** [**Mailing list**](https://lists.tox.chat) **⦁** **IRC Channel:** [#qtox@freenode](https://webchat.freenode.net/?channels=qtox) **qTox is a powerful Tox client that follows the Tox design guidelines while running on all major platforms.** From 878b3d65bdcd8417cc04c035f5443d27cc7dc149 Mon Sep 17 00:00:00 2001 From: sudden6 Date: Fri, 15 Jan 2016 23:19:03 +0100 Subject: [PATCH 099/210] fix formatting in manual --- doc/user_manual_en.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/user_manual_en.md b/doc/user_manual_en.md index bd5b0a849..b3c508153 100644 --- a/doc/user_manual_en.md +++ b/doc/user_manual_en.md @@ -73,6 +73,7 @@ qTox allows you to use multiple Tox IDs with different profiles, which each can #### Connection Settings * _Enable IPv6 (recommended):_ If enabled, qTox will use IPv4 and IPv6 protocols, whichever is available. If disabled, qTox will only use IPv4. * _Enable UDP (recommended):_ If enabled, qTox will use TCP and UDP protocols. If disabled, qTox will only use TCP, which is supposed to lower the amount of traffic, but is also slower and puts more load on other network participants. + Most users will want the two settings enabled, but if qTox crashes your router, you can try to disable them. * _Proxy type:_ If you want to use a proxy, set the type here. "None" disables the proxy. @@ -110,7 +111,7 @@ NoSpam is a feature of Tox to prevent someone spamming you with friend requests. * _Reset to default settings_ Use this button to delete any changes you made to the qTox settings. ### About -* _Version_ The version of qTox and the libraries it depends on. Please append this information to every bugreport. +* _Version_ The version of qTox and the libraries it depends on. Please append this information to every bug report. * _License_ The license under which the code of qTox is available. * _Authors_ The people who developed this shiny piece of software. * _Known Issues_ Links to our list of known issues and improvements. @@ -129,7 +130,7 @@ The following shortcuts are currently supported: | Shortcut | Action | |----------|--------| -| ``Arrow up`` | Paste last message | +| ``Arrow up`` | Paste last sent message | | ``CTRL`` + ``SHIFT`` + ``L`` | Clear chat | | ``CTRL`` + ``q`` | Quit qTox | | `CTRL` + `Page Down` | Switch to the next contact | From 225e442961b54b2ddf00e2fbe7ca7df86964260b Mon Sep 17 00:00:00 2001 From: TheNain38 Date: Fri, 15 Jan 2016 23:37:22 +0100 Subject: [PATCH 100/210] Fix typo in user manual --- doc/user_manual_en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/user_manual_en.md b/doc/user_manual_en.md index b3c508153..185939bdf 100644 --- a/doc/user_manual_en.md +++ b/doc/user_manual_en.md @@ -122,7 +122,7 @@ Groupchats are a way to talk with multiple friends at the same time, like when y ## Multi Window Mode -If you activated this mode in the [settings](#settings), qTox will seperata its main window into a contact list and chat windows, which allows you to have multiple conversations on your screen on the same time. Additionally you can manually group chats into a window by dragging and dropping them onto eachother. +If you activated this mode in the [settings](#settings), qTox will seperate its main window into a contact list and chat windows, which allows you to have multiple conversations on your screen on the same time. Additionally you can manually group chats into a window by dragging and dropping them onto eachother. ## Keyboard Shortcuts From c576a1485a6d0a1fed8911f1341709bff08bd96c Mon Sep 17 00:00:00 2001 From: tux3 Date: Sat, 16 Jan 2016 02:23:56 +0100 Subject: [PATCH 101/210] Scan-build cleanup --- src/chatlog/chatline.cpp | 10 ++++++---- src/core/core.cpp | 10 +++++----- src/core/coreencryption.cpp | 3 +-- src/platform/camera/v4l2.cpp | 3 +++ src/widget/about/aboutuser.cpp | 3 +-- src/widget/groupwidget.cpp | 2 +- src/widget/notificationscrollarea.cpp | 4 ++-- src/widget/widget.cpp | 1 - 8 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/chatlog/chatline.cpp b/src/chatlog/chatline.cpp index e52956568..27653ae97 100644 --- a/src/chatlog/chatline.cpp +++ b/src/chatlog/chatline.cpp @@ -167,13 +167,16 @@ void ChatLine::replaceContent(int col, ChatLineContent *lineContent) void ChatLine::layout(qreal w, QPointF scenePos) { + if (!content.size()) + return; + width = w; bbox.setTopLeft(scenePos); qreal fixedWidth = (content.size()-1) * columnSpacing; qreal varWidth = 0.0; // used for normalisation - for (int i = 0; i < static_cast(format.size()); ++i) + for (size_t i = 0; i < format.size(); ++i) { if (format[i].policy == ColumnFormat::FixedSize) fixedWidth += format[i].size; @@ -190,8 +193,7 @@ void ChatLine::layout(qreal w, QPointF scenePos) qreal xOffset = 0.0; qreal xPos[content.size()]; - - for (int i = 0; i < static_cast(content.size()); ++i) + for (size_t i = 0; i < content.size(); ++i) { // calculate the effective width of the current column qreal width; @@ -225,7 +227,7 @@ void ChatLine::layout(qreal w, QPointF scenePos) maxVOffset = qMax(maxVOffset, content[i]->getAscent()); } - for (int i = 0; i < static_cast(content.size()); ++i) + for (size_t i = 0; i < content.size(); ++i) { // calculate vertical alignment // vertical alignment may depend on width, so we do it in a second pass diff --git a/src/core/core.cpp b/src/core/core.cpp index 2aabd8eaa..94393c9dc 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -973,20 +973,20 @@ QList Core::getGroupPeerNames(int groupId) const { QList names; int nPeers = getGroupNumberPeers(groupId); - if (nPeers == -1) + if (nPeers < 0) { qWarning() << "getGroupPeerNames: Unable to get number of peers"; return names; } - uint8_t namesArray[nPeers][TOX_MAX_NAME_LENGTH]; - uint16_t* lengths = new uint16_t[nPeers]; - int result = tox_group_get_names(tox, groupId, namesArray, lengths, nPeers); + std::unique_ptr namesArray{new uint8_t[nPeers][TOX_MAX_NAME_LENGTH]}; + std::unique_ptr lengths{new uint16_t[nPeers]}; + int result = tox_group_get_names(tox, groupId, namesArray.get(), lengths.get(), nPeers); if (result != nPeers) { qWarning() << "getGroupPeerNames: Unexpected result"; return names; } - for (int i=0; i(data.data()), salt)) { qWarning() << "can't get salt from" << filename << "header"; @@ -110,7 +110,6 @@ QByteArray Core::getSaltFromFile(QString filename) } QByteArray res(reinterpret_cast(salt), TOX_PASS_SALT_LENGTH); - delete[] salt; return res; } diff --git a/src/platform/camera/v4l2.cpp b/src/platform/camera/v4l2.cpp index 7daf1034e..172bd4695 100644 --- a/src/platform/camera/v4l2.cpp +++ b/src/platform/camera/v4l2.cpp @@ -122,6 +122,9 @@ QVector v4l2::getDeviceModes(QString devName) case V4L2_FRMSIZE_TYPE_STEPWISE: mode.width = vfse.stepwise.max_width; mode.height = vfse.stepwise.max_height; + break; + default: + continue; } QVector rates = getDeviceModeFramerates(fd, mode.width, mode.height, vfd.pixelformat); for (unsigned short rate : rates) diff --git a/src/widget/about/aboutuser.cpp b/src/widget/about/aboutuser.cpp index c71f21075..00a649545 100644 --- a/src/widget/about/aboutuser.cpp +++ b/src/widget/about/aboutuser.cpp @@ -99,8 +99,7 @@ void AboutUser::onRemoveHistoryClicked() History* history = Nexus::getProfile()->getHistory(); if (history) history->removeFriendHistory(toxId.publicKey); - QMessageBox::StandardButton reply; - reply = QMessageBox::information(this, + QMessageBox::information(this, tr("History removed"), tr("Chat history with %1 removed!").arg(ui->userName->text().toHtmlEscaped()), QMessageBox::Ok); diff --git a/src/widget/groupwidget.cpp b/src/widget/groupwidget.cpp index cd113e416..a4cbec9e6 100644 --- a/src/widget/groupwidget.cpp +++ b/src/widget/groupwidget.cpp @@ -83,7 +83,7 @@ void GroupWidget::contextMenuEvent(QContextMenuEvent* event) if (contentDialog == nullptr || notAlone) openChatWindow = menu.addAction(tr("Open chat in new window")); - if (contentDialog->hasGroupWidget(groupId, this)) + if (contentDialog && contentDialog->hasGroupWidget(groupId, this)) removeChatWindow = menu.addAction(tr("Remove chat from this window")); menu.addSeparator(); diff --git a/src/widget/notificationscrollarea.cpp b/src/widget/notificationscrollarea.cpp index 4432d1503..dc03586a8 100644 --- a/src/widget/notificationscrollarea.cpp +++ b/src/widget/notificationscrollarea.cpp @@ -116,7 +116,7 @@ void NotificationScrollArea::resizeEvent(QResizeEvent *event) void NotificationScrollArea::findNextWidget() { - int value; + int value = 0; GenericChatroomWidget* next = nullptr; QHash::iterator i = trackedWidgets.begin(); @@ -151,7 +151,7 @@ void NotificationScrollArea::findNextWidget() void NotificationScrollArea::findPreviousWidget() { - int value; + int value = 0; GenericChatroomWidget* next = nullptr; QHash::iterator i = trackedWidgets.begin(); diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index 97ca9a497..8898d4c45 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -1486,7 +1486,6 @@ void Widget::onGroupNamelistChanged(int groupnumber, int peernumber, uint8_t Cha } else if (change == TOX_CHAT_CHANGE_PEER_NAME) // core overwrites old name before telling us it changed... { - qDebug() << "UPDATING PEER"; g->updatePeer(peernumber, name); } } From 19814ffb75c81e2b80b6443cd14d46e5173b060b Mon Sep 17 00:00:00 2001 From: Corey Sheldon Date: Sat, 16 Jan 2016 00:17:21 -0500 Subject: [PATCH 102/210] Update libsodium (again) As of December 25,2015, libsodium bumped up to 1.0.8 --- INSTALL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/INSTALL.md b/INSTALL.md index 8a152932f..2cf0299fe 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -338,7 +338,7 @@ You will need to install manually `libsodium`: ``` git clone git://github.com/jedisct1/libsodium.git cd libsodium -git checkout tags/1.0.7 +git checkout tags/1.0.8 ./autogen.sh ./configure && make check sudo checkinstall --install --pkgname libsodium --pkgversion 1.0.0 --nodoc From 203274f6d192f7e32e055e8bd07b1e9d1e3d5bee Mon Sep 17 00:00:00 2001 From: agilob Date: Sat, 16 Jan 2016 14:31:34 +0000 Subject: [PATCH 103/210] Unify window icons --- src/widget/widget.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index 9c7f4a50d..4e020c3a9 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -785,7 +785,7 @@ void Widget::onSettingsClicked() settingsWidget->show(createContentDialog(SettingDialog)); setActiveToolMenuButton(Widget::None); - settingsWidget->setWindowIcon(QIcon(":/img/settings.svg")); + settingsWidget->setWindowIcon(QIcon(":/img/icons/qtox.svg")); } else { @@ -1370,7 +1370,7 @@ ContentLayout* Widget::createContentDialog(DialogType type) void retranslateUi() { setWindowTitle(Core::getInstance()->getUsername() + QStringLiteral(" - ") + Widget::fromDialogType(type)); - setWindowIcon(QIcon(":/img/settings.svg")); + setWindowIcon(QIcon(":/img/icons/qtox.svg")); } protected: From 38c68658e032a10f792f225cc7eeb9c46cf4f504 Mon Sep 17 00:00:00 2001 From: tux3 Date: Sat, 16 Jan 2016 20:08:43 +0100 Subject: [PATCH 104/210] Fix personnal->personal typo Closes #2810 --- src/nexus.cpp | 2 +- src/persistence/profile.cpp | 2 +- src/persistence/settings.cpp | 10 +++++----- src/persistence/settings.h | 6 +++--- src/persistence/settingsserializer.cpp | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/nexus.cpp b/src/nexus.cpp index 4c42e00c3..237dafbe9 100644 --- a/src/nexus.cpp +++ b/src/nexus.cpp @@ -275,7 +275,7 @@ void Nexus::setProfile(Profile* profile) { getInstance().profile = profile; if (profile) - Settings::getInstance().loadPersonnal(profile); + Settings::getInstance().loadpersonal(profile); } AndroidGUI* Nexus::getAndroidGUI() diff --git a/src/persistence/profile.cpp b/src/persistence/profile.cpp index a69757a19..0741225cf 100644 --- a/src/persistence/profile.cpp +++ b/src/persistence/profile.cpp @@ -48,7 +48,7 @@ Profile::Profile(QString name, QString password, bool isNewProfile) s.setCurrentProfile(name); s.saveGlobal(); - // At this point it's too early to load the personnal settings (Nexus will do it), so we always load + // At this point it's too early to load the personal settings (Nexus will do it), so we always load // the history, and if it fails we can't change the setting now, but we keep a nullptr history.reset(new History{name, password}); if (!history->isValid()) diff --git a/src/persistence/settings.cpp b/src/persistence/settings.cpp index 16f9fde6d..5ea0716b2 100644 --- a/src/persistence/settings.cpp +++ b/src/persistence/settings.cpp @@ -265,18 +265,18 @@ void Settings::loadGlobal() loaded = true; } -void Settings::loadPersonnal() +void Settings::loadpersonal() { Profile* profile = Nexus::getProfile(); if (!profile) { - qCritical() << "No active profile, couldn't load personnal settings"; + qCritical() << "No active profile, couldn't load personal settings"; return; } - loadPersonnal(profile); + loadpersonal(profile); } -void Settings::loadPersonnal(Profile* profile) +void Settings::loadpersonal(Profile* profile) { QMutexLocker locker{&bigLock}; @@ -288,7 +288,7 @@ void Settings::loadPersonnal(Profile* profile) if (QFile(tmp).exists()) // otherwise, filePath remains the global file filePath = tmp; - qDebug()<<"Loading personnal settings from"<getPassword()); ps.load(); diff --git a/src/persistence/settings.h b/src/persistence/settings.h index 23c466370..59b8cc87b 100644 --- a/src/persistence/settings.h +++ b/src/persistence/settings.h @@ -43,14 +43,14 @@ public: QString getSettingsDirPath(); ///< The returned path ends with a directory separator void createSettingsDir(); ///< Creates a path to the settings dir, if it doesn't already exist - void createPersonal(QString basename); ///< Write a default personnal .ini settings file for a profile + void createPersonal(QString basename); ///< Write a default personal .ini settings file for a profile void savePersonal(); ///< Asynchronous, saves the current profile void savePersonal(Profile *profile); ///< Asynchronous void loadGlobal(); - void loadPersonnal(); - void loadPersonnal(Profile *profile); + void loadpersonal(); + void loadpersonal(Profile *profile); public slots: void saveGlobal(); ///< Asynchronous diff --git a/src/persistence/settingsserializer.cpp b/src/persistence/settingsserializer.cpp index ede8a639e..8aaf0e420 100644 --- a/src/persistence/settingsserializer.cpp +++ b/src/persistence/settingsserializer.cpp @@ -373,7 +373,7 @@ void SettingsSerializer::readSerialized() stream >> sizeData; if (sizeData.isEmpty()) { - qWarning("The personnal save file is corrupted!"); + qWarning("The personal save file is corrupted!"); return; } quint64 size = dataToVUint(sizeData); @@ -386,7 +386,7 @@ void SettingsSerializer::readSerialized() stream >> indexData; if (indexData.isEmpty()) { - qWarning("The personnal save file is corrupted!"); + qWarning("The personal save file is corrupted!"); return; } quint64 index = dataToVUint(indexData); From f27214f13119b95a9e6f3380d4afdeb6946702b0 Mon Sep 17 00:00:00 2001 From: tux3 Date: Sat, 16 Jan 2016 20:31:01 +0100 Subject: [PATCH 105/210] Depend on Qt >= 5.3 (instead of 5.2) Fixes #2812 --- INSTALL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/INSTALL.md b/INSTALL.md index 2cf0299fe..d92434a7d 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -43,7 +43,7 @@ | Name | Version | Modules | |--------------|-------------|-------------------------------------------------- | -| Qt | >= 5.2.0 | core, gui, network, opengl, sql, svg, widget, xml | +| Qt | >= 5.3.0 | core, gui, network, opengl, sql, svg, widget, xml | | GCC/MinGW | >= 4.8 | C++11 enabled | | toxcore | most recent | core, av | | FFmpeg | >= 2.6.0 | avformat, avdevice, avcodec, avutil, swscale | From 251d53f340f63f536e00204ae447dbaa514ff360 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sun, 17 Jan 2016 11:00:52 +0100 Subject: [PATCH 106/210] temporary remove audio gain metering --- src/widget/form/settings/avsettings.ui | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/widget/form/settings/avsettings.ui b/src/widget/form/settings/avsettings.ui index af0673364..f197788b6 100644 --- a/src/widget/form/settings/avsettings.ui +++ b/src/widget/form/settings/avsettings.ui @@ -48,7 +48,7 @@ - + Filter sound from your microphone, so that people hearing you would get better sound. @@ -109,6 +109,9 @@ + + + @@ -129,9 +132,6 @@ - - - @@ -139,9 +139,6 @@ - - - @@ -236,12 +233,6 @@ which may lead to problems with video calls.
src/widget/form/settings/verticalonlyscroller.h
1 - - MicFeedbackWidget - QWidget -
src/widget/tool/micfeedbackwidget.h
- 1 -
From 59ac2e54e15e4058e0afb0c9d2309243967150e5 Mon Sep 17 00:00:00 2001 From: tux3 Date: Sun, 17 Jan 2016 16:27:22 +0100 Subject: [PATCH 107/210] Fix updater search paths on XP Fixes #2807 --- updater/widget.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/updater/widget.cpp b/updater/widget.cpp index 7ea863c46..4ea315f69 100644 --- a/updater/widget.cpp +++ b/updater/widget.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include "update.h" @@ -202,8 +203,7 @@ QString Widget::getSettingsDirPath() #ifdef Q_OS_WIN wchar_t* path; - wchar_t pathOld[MAX_PATH]; - bool isOld = false; // If true, we have to use pathOld and older Windows API. + bool isOld = false; // If true, we can't unelevate and just return the path for our current home auto shell32H = LoadLibrary(TEXT("shell32.dll")); if (!(isOld = (shell32H == nullptr))) @@ -213,15 +213,18 @@ QString Widget::getSettingsDirPath() if (!(isOld = (SHGetKnownFolderPathH == nullptr))) SHGetKnownFolderPathH(FOLDERID_RoamingAppData, 0, hPrimaryToken, &path); } + if (isOld) { - qDebug() << "Falling back to legacy APIs..."; - SHGetFolderPathW(nullptr, CSIDL_APPDATA, nullptr, 0, pathOld); + return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + QDir::separator() + + "AppData" + QDir::separator() + "Roaming" + QDir::separator() + "tox" + QDir::separator()); + } + else + { + QString pathStr = QString::fromStdWString(path); + pathStr.replace("\\", "/"); + return pathStr + "/tox"; } - - QString pathStr = QString::fromStdWString(isOld ? pathOld : path); - pathStr.replace("\\", "/"); - return pathStr + "/tox"; #else return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QDir::separator() + "tox"); #endif From dc93d7f3ca3271bd1f6447b5602780a6e7917b72 Mon Sep 17 00:00:00 2001 From: Dhruv Khattar Date: Sun, 17 Jan 2016 23:00:21 +0530 Subject: [PATCH 108/210] Issue 2813 solved --- doc/user_manual_en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/user_manual_en.md b/doc/user_manual_en.md index 185939bdf..2eb1fa854 100644 --- a/doc/user_manual_en.md +++ b/doc/user_manual_en.md @@ -74,7 +74,7 @@ qTox allows you to use multiple Tox IDs with different profiles, which each can * _Enable IPv6 (recommended):_ If enabled, qTox will use IPv4 and IPv6 protocols, whichever is available. If disabled, qTox will only use IPv4. * _Enable UDP (recommended):_ If enabled, qTox will use TCP and UDP protocols. If disabled, qTox will only use TCP, which is supposed to lower the amount of traffic, but is also slower and puts more load on other network participants. -Most users will want the two settings enabled, but if qTox crashes your router, you can try to disable them. +Most users will want the two settings enabled, but if qTox crashes your router, you can try to disable them. * _Proxy type:_ If you want to use a proxy, set the type here. "None" disables the proxy. * _Address:_ If you use a proxy, enter the address here. From dba7a53ec78127aaf0a077170f223dbe286cd0f5 Mon Sep 17 00:00:00 2001 From: a68366 Date: Mon, 18 Jan 2016 16:45:29 +0300 Subject: [PATCH 109/210] Fixes #2522 --- src/persistence/offlinemsgengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/persistence/offlinemsgengine.cpp b/src/persistence/offlinemsgengine.cpp index 48e911cb0..683bc7620 100644 --- a/src/persistence/offlinemsgengine.cpp +++ b/src/persistence/offlinemsgengine.cpp @@ -83,6 +83,7 @@ void OfflineMsgEngine::deliverOfflineMsgs() QMap msgs = undeliveredMsgs; removeAllReciepts(); + undeliveredMsgs.clear(); for (auto iter = msgs.begin(); iter != msgs.end(); ++iter) { @@ -110,5 +111,4 @@ void OfflineMsgEngine::removeAllReciepts() QMutexLocker ml(&mutex); receipts.clear(); - undeliveredMsgs.clear(); } From 65421e8992262e36578c5cb37280629bc6329562 Mon Sep 17 00:00:00 2001 From: a68366 Date: Mon, 18 Jan 2016 16:50:11 +0300 Subject: [PATCH 110/210] Fix a typo in function name --- src/persistence/offlinemsgengine.cpp | 4 ++-- src/persistence/offlinemsgengine.h | 2 +- src/widget/form/chatform.cpp | 2 +- src/widget/widget.cpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/persistence/offlinemsgengine.cpp b/src/persistence/offlinemsgengine.cpp index 683bc7620..65527946f 100644 --- a/src/persistence/offlinemsgengine.cpp +++ b/src/persistence/offlinemsgengine.cpp @@ -82,7 +82,7 @@ void OfflineMsgEngine::deliverOfflineMsgs() return; QMap msgs = undeliveredMsgs; - removeAllReciepts(); + removeAllReceipts(); undeliveredMsgs.clear(); for (auto iter = msgs.begin(); iter != msgs.end(); ++iter) @@ -106,7 +106,7 @@ void OfflineMsgEngine::deliverOfflineMsgs() } } -void OfflineMsgEngine::removeAllReciepts() +void OfflineMsgEngine::removeAllReceipts() { QMutexLocker ml(&mutex); diff --git a/src/persistence/offlinemsgengine.h b/src/persistence/offlinemsgengine.h index 386262a5c..933eb3f51 100644 --- a/src/persistence/offlinemsgengine.h +++ b/src/persistence/offlinemsgengine.h @@ -43,7 +43,7 @@ public: public slots: void deliverOfflineMsgs(); - void removeAllReciepts(); + void removeAllReceipts(); private: struct MsgPtr { diff --git a/src/widget/form/chatform.cpp b/src/widget/form/chatform.cpp index ac970f844..50f9e8092 100644 --- a/src/widget/form/chatform.cpp +++ b/src/widget/form/chatform.cpp @@ -110,7 +110,7 @@ ChatForm::ChatForm(Friend* chatFriend) connect(msgEdit, &ChatTextEdit::enterPressed, this, &ChatForm::onSendTriggered); connect(msgEdit, &ChatTextEdit::textChanged, this, &ChatForm::onTextEditChanged); connect(core, &Core::fileSendFailed, this, &ChatForm::onFileSendFailed); - connect(this, &ChatForm::chatAreaCleared, getOfflineMsgEngine(), &OfflineMsgEngine::removeAllReciepts); + connect(this, &ChatForm::chatAreaCleared, getOfflineMsgEngine(), &OfflineMsgEngine::removeAllReceipts); connect(&typingTimer, &QTimer::timeout, this, [=]{ Core::getInstance()->sendTyping(f->getFriendID(), false); isTyping = false; diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index 0f92883e0..7501ab776 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -1848,7 +1848,7 @@ void Widget::clearAllReceipts() { QList frnds = FriendList::getAllFriends(); for (Friend *f : frnds) - f->getChatForm()->getOfflineMsgEngine()->removeAllReciepts(); + f->getChatForm()->getOfflineMsgEngine()->removeAllReceipts(); } void Widget::reloadTheme() From e70303908d9ff364adac299faeb54f0dde80df32 Mon Sep 17 00:00:00 2001 From: LittleVulpix Date: Mon, 18 Jan 2016 14:36:56 +0100 Subject: [PATCH 111/210] User manual wording+changes Misleading information The profile is actually in the top left corner, not the top right. Updated and reworded the profile section The section was given a unified look and some options were reworded to either be more clear or to fix grammatical errors. Minor rewording of the general settings section No capital S in status Updated and reworded the chat section Updated and reworded the theme section simleys->smileys Also they are not being replaced with unicode emoticons but instead with actual images, rectified. Updated and reworded the connection settings section Minor rewording of the NoSpam section Minor rewording of the audio+video section Minor rewording of the advanced section Updated and reworded the groupchats section Updated and reworded the multi window mode section normaly->normally if profile->if the profile --- doc/user_manual_en.md | 55 +++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/doc/user_manual_en.md b/doc/user_manual_en.md index 2eb1fa854..c74d0aa20 100644 --- a/doc/user_manual_en.md +++ b/doc/user_manual_en.md @@ -8,7 +8,7 @@ * [Keyboard Shortcuts](#keyboard-shortcuts) ## User Profile -Your User Profile contains everything you share with other people on Tox. You can open it by clicking the picture on the top right corner. It contains the following settings: +Your User Profile contains everything you share with other people on Tox. You can open it by clicking the picture in the top left corner. It contains the following settings: ### Public Information * _Name:_ This is your nickname which everyone who has your Tox ID can see. @@ -23,16 +23,16 @@ The "Save image" button saves the QR-Code into a image file, while the "Copy ima ### Profile -qTox allows you to use multiple Tox IDs with different profiles, which each can have different nicknames, status messages and friends. +qTox allows you to use multiple Tox IDs with different profiles, each of which can have different nicknames, status messages and friends. + _Current profile:_ Shows the filename which stores your information. + _Current profile locatation:_ Shows the path to the profile file. -+ _Rename_ This button allows you to rename your profile. Your nickname and profile name don't have to be the same. -+ _Delete_ This button deletes your profile and the corresponding chat history. -+ _Export_ Allows you to export your profile in a format compatible with other Tox clients. You can also manually backup your *.tox files. -+ _Logout_ Close your current profile and show the login window. -+ _Remove password_ If you set a password for your profile, you can remove it with this button. -+ _Change password_ If you set a password for your profile, you can change the password with this button. You can also set a password for unencrypted profiles here. ++ _Rename:_ Allows you to rename your profile. Your nickname and profile name don't have to be the same. ++ _Delete:_ Deletes your profile and the corresponding chat history. ++ _Export:_ Allows you to export your profile in a format compatible with other Tox clients. You can also manually back up your *.tox files. ++ _Logout:_ Close your current profile and show the login window. ++ _Remove password:_ Removes the existing password for your profile. If the profile already has no password, you will be notified. ++ _Change password:_ Allows you to either change an existing password, or create a new password if your profile does not have one. ## Settings ### General @@ -44,27 +44,26 @@ qTox allows you to use multiple Tox IDs with different profiles, which each can * _Show system tray icon:_ If set, qTox will show its icon in your system tray. * _Start in tray:_ On start, qTox will only show its tray icon and no window. * _Minimize to tray:_ The minimize button on the top right, will minimize qTox to its tray icon. There won't be a taskbar item. - -* _Auto away after (0 to disable):_ After the specified amount of time, qTox will set your Status to "Away". A setting of 0 will never change your status. -* _Default directory to save files:_ You can set the directory where qTox puts files you recieved here. +* _Auto away after (0 to disable):_ After the specified amount of time, qTox will set your status to "Away". A setting of 0 will never change your status. +* _Default directory to save files:_ Allows you to specify the default destination for incoming filetransfers. * _Autoaccept files:_ If set, qTox will automatically accept file transfers and put them in the directory specified above. #### Chat * _Play sound:_ If checked, qTox will play a sound when you get a new message. -* _Open window:_ If checked, the qTox window will be opened. If you use the multiple windows mode, see [Multi Window Mode](#multi-window-mode) for details. - * _Focus window:_ If checked, the qTox window will additionally be focused. +* _Open window:_ If checked, the qTox window will be opened when you receive a new message. If you use the multiple windows mode, see [Multi Window Mode](#multi-window-mode) for details. + * _Focus window:_ If checked, the qTox window will additionally be focused when you receive a new message. * _Show contacts' status changes:_ If set, qTox will show contact status changes in your chat window. * _Group chats always notify:_ If set, qTox will notify you on every new message in a groupchat. -* _Place groupchats at top of friend list:_ If checked, your groupchats will be at the top of the contacts list, else they will be sorted with your other contacts. +* _Place groupchats at top of friend list:_ If checked, your groupchats will be at the top of the contacts list instead of being sorted with your other contacts. * _Faux offline messaging:_ If enabled, qTox will attempt to send messages when a currently offline contact comes online again. * _Compact contact list:_ If set, qTox will use a contact list layout which takes up less screen space. * _Multiple windows mode:_ If enabled, the qTox user interface will be split into multiple independent windows. For details see [Multi Window Mode](#multi-window-mode). * _Open each chat in an individual window:_ If checked, a new window will be opened for every chat you open. If you manually grouped the chat into another window, the window which hosts the chat will be focused. #### Theme -* _Use emoticons:_ If enabled, qTox will replace simleys ( e.g. :-) ) with Unicode emoticons. -* _Smiley Pack:_ You can choose from different sets of shiped emoticon styles. -* _Emoticon size:_ You can change the size of the emoticons here. +* _Use emoticons:_ If enabled, qTox will replace smileys ( e.g. :-) ) with corresponding graphical emoticons. +* _Smiley Pack:_ Allows you to choose from different sets of shipped emoticon styles. +* _Emoticon size:_ Allows you to change the size of the emoticons. * _Style:_ Changes the appearance of qTox. * _Theme color:_ Changes the colors qTox uses. * _Timestamp format:_ Change the format in which qTox displays message timestamps. @@ -72,9 +71,9 @@ qTox allows you to use multiple Tox IDs with different profiles, which each can #### Connection Settings * _Enable IPv6 (recommended):_ If enabled, qTox will use IPv4 and IPv6 protocols, whichever is available. If disabled, qTox will only use IPv4. -* _Enable UDP (recommended):_ If enabled, qTox will use TCP and UDP protocols. If disabled, qTox will only use TCP, which is supposed to lower the amount of traffic, but is also slower and puts more load on other network participants. +* _Enable UDP (recommended):_ If enabled, qTox will use TCP and UDP protocols. If disabled, qTox will only use TCP, which lowers the amount of open connections and slightly decreases required bandwidth, but is also slower and puts more load on other network participants. -Most users will want the two settings enabled, but if qTox crashes your router, you can try to disable them. +Most users will want both options enabled, but if qTox negatively impacts your router or connection, you can try to disable them. * _Proxy type:_ If you want to use a proxy, set the type here. "None" disables the proxy. * _Address:_ If you use a proxy, enter the address here. @@ -88,41 +87,41 @@ Most users will want the two settings enabled, but if qTox crashes your router, #### NoSpam -NoSpam is a feature of Tox to prevent someone spamming you with friend requests. If you get spammed, enter or generate a new NoSpam value, this will alter your Tox ID. You don't need to tell your existing contacts your new Tox ID, but you have to tell new contacts your new Tox ID. Your Tox ID can be found in your [User Profile](#user-profile) +NoSpam is a feature of Tox that prevents a malicious user from spamming you with friend requests. If you get spammed, enter or generate a new NoSpam value. This will alter your Tox ID. You don't need to tell your existing contacts your new Tox ID, but you have to tell new contacts your new Tox ID. Your Tox ID can be found in your [User Profile](#user-profile) ### Audio/Video #### Audio Settings * _Playback device:_ Select the device qTox should use for all audio output (notifications, calls,..). * _Playback:_ Here you can adjust the playback volume to your needs. * _Capture device:_ Select the device qTox should use for audio input in calls. -* _Microphone:_ Set the input volume of your microphone with this slider. When you are talking normaly, the display should be in the green range. +* _Microphone:_ Set the input volume of your microphone with this slider. When you are talking normally, the displayed volume incidator should be in the green range. * _Filter audio_ If enabled, qTox will try to remove noise and echo from your audio input. #### Video Settings * _Video device:_ Select the video device qTox should use for video calls. "None" will show a dummy picture to your chat partner. "Desktop" will stream the content of your screen. * _Resolution:_ You can select from the available resolutions and framerates here. Higher resolutions provide more quality, but if the bandwidth of your connection is low, the video may get choppy. - If you set up everything correctly, you should see the preview of your video device in the box. + If you set up everything correctly, you should see the preview of your video device in the box below. * _Rescan devices_ Use this button to search for newly attached devices, e.g. you plugged in a webcam. ### Advanced * _Make Tox portable:_ If enabled, qTox will load/save user data from the working directory, instead of ``` ~/.config/tox/ ```. -* _Reset to default settings_ Use this button to delete any changes you made to the qTox settings. +* _Reset to default settings_ Use this button to revert any changes you made to the qTox settings. ### About -* _Version_ The version of qTox and the libraries it depends on. Please append this information to every bug report. -* _License_ The license under which the code of qTox is available. -* _Authors_ The people who developed this shiny piece of software. +* _Version_ Shows the version of qTox and the libraries it depends on. Please append this information to every bug report. +* _License_ Shows the license under which the code of qTox is available. +* _Authors_ Lists the people who developed this shiny piece of software. * _Known Issues_ Links to our list of known issues and improvements. ## Groupchats -Groupchats are a way to talk with multiple friends at the same time, like when you are standing together in a group. To create a groupchat click the groupchat icon and set a name. Now you can invite people by right clicking on the contact and selecting "Invite to group". Currently, if the last person leaves the chat, it is closed and you have to create a new one. Sending files and videochats are currently unsupported in groupchats. +Groupchats are a way to talk with multiple friends at the same time, like when you are standing together in a group. To create a groupchat click the groupchat icon in the bottom left corner and set a name. Now you can invite your contacts by right-clicking on the contact and selecting "Invite to group". Currently, if the last person leaves the chat, it is closed and you have to create a new one. Videochats and filetransfers are currently unsupported in groupchats. ## Multi Window Mode -If you activated this mode in the [settings](#settings), qTox will seperate its main window into a contact list and chat windows, which allows you to have multiple conversations on your screen on the same time. Additionally you can manually group chats into a window by dragging and dropping them onto eachother. +In this mode, qTox will seperate its main window into a single contact list and one or multiple chat windows, which allows you to have multiple conversations on your screen on the same time. Additionally you can manually group chats into a window by dragging and dropping them onto eachother. This mode can be activated and configured in [settings](#settings). ## Keyboard Shortcuts From d10761b6f250b3fb49feb6385e94bdb41ce79abd Mon Sep 17 00:00:00 2001 From: LittleVulpix Date: Mon, 18 Jan 2016 17:09:26 +0100 Subject: [PATCH 112/210] Some minor grammar seperate->separate on the same time->at the same time --- doc/user_manual_en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/user_manual_en.md b/doc/user_manual_en.md index c74d0aa20..bcb7ed34b 100644 --- a/doc/user_manual_en.md +++ b/doc/user_manual_en.md @@ -121,7 +121,7 @@ Groupchats are a way to talk with multiple friends at the same time, like when y ## Multi Window Mode -In this mode, qTox will seperate its main window into a single contact list and one or multiple chat windows, which allows you to have multiple conversations on your screen on the same time. Additionally you can manually group chats into a window by dragging and dropping them onto eachother. This mode can be activated and configured in [settings](#settings). +In this mode, qTox will separate its main window into a single contact list and one or multiple chat windows, which allows you to have multiple conversations on your screen at the same time. Additionally you can manually group chats into a window by dragging and dropping them onto eachother. This mode can be activated and configured in [settings](#settings). ## Keyboard Shortcuts From f7c262fb07a749b254bf95b7e4b88db707542f6b Mon Sep 17 00:00:00 2001 From: Rowen Stipe Date: Mon, 18 Jan 2016 14:36:35 -0500 Subject: [PATCH 113/210] Touchups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit has several touch ups that only effect the OS X clients. `info.plist` and `qt.pro` are now configured to create an automatic short version to help distinguish between clients clearly and include a referenced file not put into the build when compiled. `./img/icon/qtox_profile.icns’ `info.plist` also had it’s bundle version to be updated to the 1.2.2 tag and supported languages added and fixed referenced file. The default save location has also been moved to comply with the Tox Client Standard. (Previous location was ~/Library/Prefrences/tox ) A basic bash profile mover has also been included to show I did think of that. --- OSX-Migrater.sh | 15 +++++++++++ osx/info.plist | 49 ++++++++++++++++++++++-------------- qtox.pro | 7 ++++++ src/persistence/settings.cpp | 3 +++ 4 files changed, 55 insertions(+), 19 deletions(-) create mode 100755 OSX-Migrater.sh diff --git a/OSX-Migrater.sh b/OSX-Migrater.sh new file mode 100755 index 000000000..b63eb0134 --- /dev/null +++ b/OSX-Migrater.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +# A qTox profile migrater for OSX +echo "Figuring out if action is required ..." +if [ -d ~/Library/Prefrences/tox] + echo "Moving profile(s) ..." + cp -r ~/Library/Preferences/tox ~/Library/Application\ Support/ + mv ~/Library/Application\ Support/tox/ ~/Library/Application\ Support/Tox + mv ~/Library/Preferences/tox ~/.Tox-Backup + echo "Done! You profile(s) have been moved! A back up coppy still exists at:" + echo "~/.Tox-Backup" +else + echo "Cannot locate old profile directory, profile migration not performed" +fi +exit 0 \ No newline at end of file diff --git a/osx/info.plist b/osx/info.plist index a6ff7ab5d..d6138ae2e 100644 --- a/osx/info.plist +++ b/osx/info.plist @@ -9,7 +9,7 @@ CFBundlePackageType APPL CFBundleSignature - ???? + toxq CFBundleExecutable qtox CFBundleDisplayName @@ -17,9 +17,9 @@ CFBundleName qTox CFBundleVersion - 1.0.0 + 1.2.2 CFBundleShortVersionString - 1.0.0-EXPERIMENTIAL + @SHORT_VERSION@ CFBundleIdentifier chat.tox.qtox CFBundleURLTypes @@ -34,7 +34,7 @@ tox CFBundleURLIconFile - qtox_profile.icns + qtox_profile CFBundleDocumentTypes @@ -49,7 +49,7 @@ CFBundleTypeRole Editor CFBundleTypeIconFile - qtox_profile.icns + qtox_profile CFBundleTypeMIMETypes application/x-tox.profile @@ -84,19 +84,30 @@ - CFBundleLocalizations - - en_US - en - bg_BG - de_DE - fi_FI - fr_FR - it_IT - pl_PL - ru_RU - uk_UA - sv - + CFBundleLocalizations + + en_US + bg_BG + cs + de_DE + el + es_MX + fi_FI + fr_FR + hr_HR + hu_HU + it_IT + lt_LT + nl_NL + nb_NO + pl_PL + pt_BR + ru_RU + sl + sv + tr_TR + uk_UA + zh_CH + diff --git a/qtox.pro b/qtox.pro index 84ffa9dc8..5924e62cd 100644 --- a/qtox.pro +++ b/qtox.pro @@ -164,6 +164,13 @@ win32 { LIBS += -lqrencode -lsqlcipher contains(DEFINES, QTOX_PLATFORM_EXT) { LIBS += -framework IOKit -framework CoreFoundation } contains(DEFINES, QTOX_FILTER_AUDIO) { LIBS += -lfilteraudio } + #Files to be includes into the qTox.app/Contents/Resources folder + APP_RESOURCE.files = img/icons/qtox_profile.icns + APP_RESOURCE.path = Contents/Resources + QMAKE_BUNDLE_DATA += APP_RESOURCE + #Dynamic versioning for Info.plist + INFO_PLIST_PATH = $$shell_quote($${OUT_PWD}/$${TARGET}.app/Contents/Info.plist) + QMAKE_POST_LINK += /usr/libexec/PlistBuddy -c \"Set :CFBundleShortVersionString $${GIT_DESCRIBE}\" $${INFO_PLIST_PATH} } else { android { LIBS += -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns diff --git a/src/persistence/settings.cpp b/src/persistence/settings.cpp index 5ea0716b2..0839e4303 100644 --- a/src/persistence/settings.cpp +++ b/src/persistence/settings.cpp @@ -537,6 +537,9 @@ QString Settings::getSettingsDirPath() #ifdef Q_OS_WIN return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + QDir::separator() + "AppData" + QDir::separator() + "Roaming" + QDir::separator() + "tox")+QDir::separator(); +#elif defined(Q_OS_OSX) + return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + QDir::separator() + + "Library" + QDir::separator() + "Application Support" + QDir::separator() + "Tox")+QDir::separator(); #else return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QDir::separator() + "tox")+QDir::separator(); From 2e0e8f778f808727b8b211f3f0326ae2b229a754 Mon Sep 17 00:00:00 2001 From: Zetok Zalbavar Date: Mon, 18 Jan 2016 11:11:59 +0000 Subject: [PATCH 114/210] Login window: disable `Load automatically` if profile is encrypted --- src/widget/loginscreen.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/widget/loginscreen.cpp b/src/widget/loginscreen.cpp index 29e12455b..d3ba80921 100644 --- a/src/widget/loginscreen.cpp +++ b/src/widget/loginscreen.cpp @@ -172,11 +172,18 @@ void LoginScreen::onLoginUsernameSelected(const QString &name) { ui->loginPasswordLabel->show(); ui->loginPassword->show(); + // there is no way to do autologin if profile is encrypted, and + // visible option confuses users into thinking that it is possible, + // thus disable it (and hope that users won't think that it's a bug) + ui->autoLoginCB->setEnabled(false); + ui->autoLoginCB->setToolTip(tr("Password protected profile can't be loaded automatically.")); } else { ui->loginPasswordLabel->hide(); ui->loginPassword->hide(); + ui->autoLoginCB->setEnabled(true); + ui->autoLoginCB->setToolTip(""); } } From f14bc8316c7a6affa7da78791b863c4563295d75 Mon Sep 17 00:00:00 2001 From: sudden6 Date: Tue, 19 Jan 2016 00:19:07 +0100 Subject: [PATCH 115/210] Add proxy support to toxme and autouptdate --- src/net/autoupdate.cpp | 3 +++ src/net/toxme.cpp | 3 +++ src/persistence/settings.cpp | 24 ++++++++++++++++++++++++ src/persistence/settings.h | 3 +++ 4 files changed, 33 insertions(+) diff --git a/src/net/autoupdate.cpp b/src/net/autoupdate.cpp index 0088b7b81..fe40ea143 100644 --- a/src/net/autoupdate.cpp +++ b/src/net/autoupdate.cpp @@ -108,6 +108,7 @@ AutoUpdater::VersionInfo AutoUpdater::getUpdateVersion() QNetworkAccessManager *manager = new QNetworkAccessManager; QNetworkReply* reply = manager->get(QNetworkRequest(QUrl(checkURI))); + manager->setProxy(Settings::getInstance().getProxy()); while (!reply->isFinished()) { if (abortFlag) @@ -222,6 +223,7 @@ QByteArray AutoUpdater::getUpdateFlist() QNetworkAccessManager *manager = new QNetworkAccessManager; QNetworkReply* reply = manager->get(QNetworkRequest(QUrl(flistURI))); + manager->setProxy(Settings::getInstance().getProxy()); while (!reply->isFinished()) { if (abortFlag) @@ -277,6 +279,7 @@ AutoUpdater::UpdateFile AutoUpdater::getUpdateFile(UpdateFileMeta fileMeta, file.metadata = fileMeta; QNetworkAccessManager *manager = new QNetworkAccessManager; + manager->setProxy(Settings::getInstance().getProxy()); QNetworkReply* reply = manager->get(QNetworkRequest(QUrl(filesURI+fileMeta.id))); QObject::connect(reply, &QNetworkReply::downloadProgress, progressCallback); while (!reply->isFinished()) diff --git a/src/net/toxme.cpp b/src/net/toxme.cpp index 8fdbe4fb3..2bd175061 100644 --- a/src/net/toxme.cpp +++ b/src/net/toxme.cpp @@ -19,6 +19,7 @@ #include "toxme.h" #include "src/core/core.h" +#include #include #include #include @@ -34,6 +35,7 @@ QByteArray Toxme::makeJsonRequest(QString url, QString json, QNetworkReply::Netw return QByteArray(); QNetworkAccessManager netman; + netman.setProxy(Settings::getInstance().getProxy()); QNetworkRequest request{url}; request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); QNetworkReply* reply = netman.post(request,json.toUtf8()); @@ -57,6 +59,7 @@ QByteArray Toxme::getServerPubkey(QString url, QNetworkReply::NetworkError &erro // Get key QNetworkAccessManager netman; + netman.setProxy(Settings::getInstance().getProxy()); QNetworkRequest request{url}; request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); QNetworkReply* reply = netman.get(request); diff --git a/src/persistence/settings.cpp b/src/persistence/settings.cpp index 5ea0716b2..8cc592513 100644 --- a/src/persistence/settings.cpp +++ b/src/persistence/settings.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #define SHOW_SYSTEM_TRAY_DEFAULT (bool) true @@ -770,6 +771,29 @@ void Settings::setForceTCP(bool newValue) forceTCP = newValue; } +QNetworkProxy Settings::getProxy() const +{ + QNetworkProxy proxy; + switch(Settings::getProxyType()) + { + case ProxyType::ptNone: + proxy.setType(QNetworkProxy::NoProxy); + break; + case ProxyType::ptSOCKS5: + proxy.setType(QNetworkProxy::Socks5Proxy); + break; + case ProxyType::ptHTTP: + proxy.setType(QNetworkProxy::HttpProxy); + break; + default: + proxy.setType(QNetworkProxy::NoProxy); + qWarning() << "Invalid Proxy type, setting to NoProxy"; + } + proxy.setHostName(Settings::getProxyAddr()); + proxy.setPort(Settings::getProxyPort()); + return proxy; +} + ProxyType Settings::getProxyType() const { QMutexLocker locker{&bigLock}; diff --git a/src/persistence/settings.h b/src/persistence/settings.h index 59b8cc87b..025aaf53b 100644 --- a/src/persistence/settings.h +++ b/src/persistence/settings.h @@ -26,6 +26,7 @@ #include #include #include +#include #include "src/core/corestructs.h" class ToxId; @@ -109,6 +110,8 @@ public: bool getForceTCP() const; void setForceTCP(bool newValue); + QNetworkProxy getProxy() const; + QString getProxyAddr() const; void setProxyAddr(const QString& newValue); From df792b074812ad785d3256dbb5503deaca899d4a Mon Sep 17 00:00:00 2001 From: kehugter Date: Tue, 19 Jan 2016 02:59:14 +0100 Subject: [PATCH 116/210] Check spelling, standardise punctuation and terms, small markdown fixes --- doc/user_manual_en.md | 48 +++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/doc/user_manual_en.md b/doc/user_manual_en.md index bcb7ed34b..98736115f 100644 --- a/doc/user_manual_en.md +++ b/doc/user_manual_en.md @@ -12,24 +12,24 @@ Your User Profile contains everything you share with other people on Tox. You ca ### Public Information * _Name:_ This is your nickname which everyone who has your Tox ID can see. -* _Status:_ You can post a status message here, which again everyone on who has your ToxID can see. +* _Status:_ You can post a status message here, which again everyone on who has your Tox ID can see. ### Tox ID The long code in hexadecimal format is your Tox ID, share this with everyone you want to talk to. Click it to copy it to your clipboard. -Your Tox ID is also shown as QR-Code to easily share it with friends over a smartphone. +Your Tox ID is also shown as QR code to easily share it with friends over a smartphone. -The "Save image" button saves the QR-Code into a image file, while the "Copy image" button copies into your clipboard. +The "Save image" button saves the QR code into a image file, while the "Copy image" button copies into your clipboard. ### Profile qTox allows you to use multiple Tox IDs with different profiles, each of which can have different nicknames, status messages and friends. + _Current profile:_ Shows the filename which stores your information. -+ _Current profile locatation:_ Shows the path to the profile file. ++ _Current profile location:_ Shows the path to the profile file. + _Rename:_ Allows you to rename your profile. Your nickname and profile name don't have to be the same. + _Delete:_ Deletes your profile and the corresponding chat history. -+ _Export:_ Allows you to export your profile in a format compatible with other Tox clients. You can also manually back up your *.tox files. ++ _Export:_ Allows you to export your profile in a format compatible with other Tox clients. You can also manually back up your \*.tox files. + _Logout:_ Close your current profile and show the login window. + _Remove password:_ Removes the existing password for your profile. If the profile already has no password, you will be notified. + _Change password:_ Allows you to either change an existing password, or create a new password if your profile does not have one. @@ -39,13 +39,13 @@ qTox allows you to use multiple Tox IDs with different profiles, each of which c #### General Settings * _Language:_ Changes which language the qTox interface uses. -* _Autostart:_ If set, qTox will start when you login on your computer. qTox will also autmatically open the profile which was active when you ticked the checkbox, but this only works if your profile isn't encrypted (has no password set). +* _Autostart:_ If set, qTox will start when you login on your computer. qTox will also automatically open the profile which was active when you ticked the checkbox, but this only works if your profile isn't encrypted (has no password set). * _Light icon:_ If set, qTox will use a different icon, which is easier to see on black backgrounds. * _Show system tray icon:_ If set, qTox will show its icon in your system tray. * _Start in tray:_ On start, qTox will only show its tray icon and no window. * _Minimize to tray:_ The minimize button on the top right, will minimize qTox to its tray icon. There won't be a taskbar item. * _Auto away after (0 to disable):_ After the specified amount of time, qTox will set your status to "Away". A setting of 0 will never change your status. -* _Default directory to save files:_ Allows you to specify the default destination for incoming filetransfers. +* _Default directory to save files:_ Allows you to specify the default destination for incoming file transfers. * _Autoaccept files:_ If set, qTox will automatically accept file transfers and put them in the directory specified above. #### Chat @@ -61,7 +61,7 @@ qTox allows you to use multiple Tox IDs with different profiles, each of which c * _Open each chat in an individual window:_ If checked, a new window will be opened for every chat you open. If you manually grouped the chat into another window, the window which hosts the chat will be focused. #### Theme -* _Use emoticons:_ If enabled, qTox will replace smileys ( e.g. :-) ) with corresponding graphical emoticons. +* _Use emoticons:_ If enabled, qTox will replace smileys ( e.g. `:-)` ) with corresponding graphical emoticons. * _Smiley Pack:_ Allows you to choose from different sets of shipped emoticon styles. * _Emoticon size:_ Allows you to change the size of the emoticons. * _Style:_ Changes the appearance of qTox. @@ -78,50 +78,50 @@ Most users will want both options enabled, but if qTox negatively impacts your r * _Proxy type:_ If you want to use a proxy, set the type here. "None" disables the proxy. * _Address:_ If you use a proxy, enter the address here. * _Port:_ If you use a proxy, enter the port here. -* _Reconnect:_ Reconnect to the tox network, e.g. if you changed the proxy settings. +* _Reconnect:_ Reconnect to the Tox network, e.g. if you changed the proxy settings. ### Privacy * _Send typing notifications:_ If enabled, notify your chat partner when you are currently typing. -* _Keep chat history:_ If enabled, qTox will save your sent and recieved messages. Encrypt your profile, if you want to encrypt the chat history. +* _Keep chat history:_ If enabled, qTox will save your sent and received messages. Encrypt your profile, if you want to encrypt the chat history. #### NoSpam -NoSpam is a feature of Tox that prevents a malicious user from spamming you with friend requests. If you get spammed, enter or generate a new NoSpam value. This will alter your Tox ID. You don't need to tell your existing contacts your new Tox ID, but you have to tell new contacts your new Tox ID. Your Tox ID can be found in your [User Profile](#user-profile) +NoSpam is a feature of Tox that prevents a malicious user from spamming you with friend requests. If you get spammed, enter or generate a new NoSpam value. This will alter your Tox ID. You don't need to tell your existing contacts your new Tox ID, but you have to tell new contacts your new Tox ID. Your Tox ID can be found in your [User Profile](#user-profile). ### Audio/Video #### Audio Settings -* _Playback device:_ Select the device qTox should use for all audio output (notifications, calls,..). +* _Playback device:_ Select the device qTox should use for all audio output (notifications, calls, etc). * _Playback:_ Here you can adjust the playback volume to your needs. * _Capture device:_ Select the device qTox should use for audio input in calls. -* _Microphone:_ Set the input volume of your microphone with this slider. When you are talking normally, the displayed volume incidator should be in the green range. -* _Filter audio_ If enabled, qTox will try to remove noise and echo from your audio input. +* _Microphone:_ Set the input volume of your microphone with this slider. When you are talking normally, the displayed volume indicator should be in the green range. +* _Filter audio:_ If enabled, qTox will try to remove noise and echo from your audio input. #### Video Settings * _Video device:_ Select the video device qTox should use for video calls. "None" will show a dummy picture to your chat partner. "Desktop" will stream the content of your screen. -* _Resolution:_ You can select from the available resolutions and framerates here. Higher resolutions provide more quality, but if the bandwidth of your connection is low, the video may get choppy. +* _Resolution:_ You can select from the available resolutions and frame rates here. Higher resolutions provide more quality, but if the bandwidth of your connection is low, the video may get choppy. If you set up everything correctly, you should see the preview of your video device in the box below. -* _Rescan devices_ Use this button to search for newly attached devices, e.g. you plugged in a webcam. +* _Rescan devices:_ Use this button to search for newly attached devices, e.g. you plugged in a webcam. ### Advanced -* _Make Tox portable:_ If enabled, qTox will load/save user data from the working directory, instead of ``` ~/.config/tox/ ```. -* _Reset to default settings_ Use this button to revert any changes you made to the qTox settings. +* _Make Tox portable:_ If enabled, qTox will load/save user data from the working directory, instead of ` ~/.config/tox/ `. +* _Reset to default settings:_ Use this button to revert any changes you made to the qTox settings. ### About -* _Version_ Shows the version of qTox and the libraries it depends on. Please append this information to every bug report. -* _License_ Shows the license under which the code of qTox is available. -* _Authors_ Lists the people who developed this shiny piece of software. -* _Known Issues_ Links to our list of known issues and improvements. +* _Version:_ Shows the version of qTox and the libraries it depends on. Please append this information to every bug report. +* _License:_ Shows the license under which the code of qTox is available. +* _Authors:_ Lists the people who developed this shiny piece of software. +* _Known Issues:_ Links to our list of known issues and improvements. ## Groupchats -Groupchats are a way to talk with multiple friends at the same time, like when you are standing together in a group. To create a groupchat click the groupchat icon in the bottom left corner and set a name. Now you can invite your contacts by right-clicking on the contact and selecting "Invite to group". Currently, if the last person leaves the chat, it is closed and you have to create a new one. Videochats and filetransfers are currently unsupported in groupchats. +Groupchats are a way to talk with multiple friends at the same time, like when you are standing together in a group. To create a groupchat click the groupchat icon in the bottom left corner and set a name. Now you can invite your contacts by right-clicking on the contact and selecting "Invite to group". Currently, if the last person leaves the chat, it is closed and you have to create a new one. Videochats and file transfers are currently unsupported in groupchats. ## Multi Window Mode -In this mode, qTox will separate its main window into a single contact list and one or multiple chat windows, which allows you to have multiple conversations on your screen at the same time. Additionally you can manually group chats into a window by dragging and dropping them onto eachother. This mode can be activated and configured in [settings](#settings). +In this mode, qTox will separate its main window into a single contact list and one or multiple chat windows, which allows you to have multiple conversations on your screen at the same time. Additionally you can manually group chats into a window by dragging and dropping them onto each other. This mode can be activated and configured in [settings](#settings). ## Keyboard Shortcuts From 77e9f231ea27ac00366caf000741c547fb295ab1 Mon Sep 17 00:00:00 2001 From: kehugter Date: Tue, 19 Jan 2016 03:49:03 +0100 Subject: [PATCH 117/210] Update Spanish translation --- translations/es.ts | 145 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 111 insertions(+), 34 deletions(-) diff --git a/translations/es.ts b/translations/es.ts index ff116759d..730eaec23 100644 --- a/translations/es.ts +++ b/translations/es.ts @@ -109,6 +109,15 @@ se pueden producir problemas con las videollamadas. Qt version: Versión de Qt: + + Restart qTox to install version %1 + Reinicia qTox para instalar la version %1 + + + qTox is downloading update %1 + %1 is the version of the update + qTox está descargando la actualización %1 + AboutSettings @@ -116,27 +125,23 @@ se pueden producir problemas con las videollamadas. Version Versión + + You are using qTox version $GIT_DESCRIBE. + Estás usando qTox versión $GIT_DESCRIBE. + + + Downloading update: %p% + Descargando actualización: %p% + License Licencia - - You are using a qTox nightly build. - Estás usando una nightly build de qTox. - - - Commit hash: <a href="https://github.com/tux3/qTox/commit/$GIT_VERSION">$GIT_VERSION</a> - Commit hash: <a href="https://github.com/tux3/qTox/commit/$GIT_VERSION">$GIT_VERSION</a> - - - toxcore version: $TOXCOREVERSION - Versión de toxcore: $TOXCOREVERSION - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Oxygen-Sans'; font-size:10pt; font-weight:400; font-style:normal;"> +</style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; color:#000000;">Copyright © 2014-2015 by The qTox Project</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu';">qTox is a Qt-based graphical interface for Tox.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';">qTox is libre software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.</span></p> @@ -145,13 +150,21 @@ p, li { white-space: pre-wrap; } <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Oxygen-Sans'; font-size:10pt; font-weight:400; font-style:normal;"> +</style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; color:#000000;">Copyright © 2014-2015 by The qTox Project</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu';">qTox is a Qt-based graphical interface for Tox.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';">qTox is libre software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';">qTox is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. </span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu';">You should have received a copy of the GNU General Public License along with this program. If not, see </span><a href="https://www.gnu.org/copyleft/gpl.html"><span style=" font-family:'Ubuntu'; text-decoration: underline; color:#007af4;">https://www.gnu.org/copyleft/gpl.html</span></a><span style=" font-family:'Ubuntu';">.</span></p></body></html> + + Commit hash: <a href="https://github.com/tux3/qTox/commit/$GIT_VERSION">$GIT_VERSION</a> + Commit hash: <a href="https://github.com/tux3/qTox/commit/$GIT_VERSION">$GIT_VERSION</a> + + + toxcore version: $TOXCOREVERSION + Versión de toxcore: $TOXCOREVERSION + Authors Autores @@ -298,18 +311,6 @@ Ignore the proxy and connect to the Internet directly? Advanced Avanzado - - Synchronized - safe (recommended) - Sincronizada - seguro (recomendado) - - - Partially async - risky (20% faster) - Parcialmente asíncrona - riesgoso (20% más rápido) - - - Asynchronous - dangerous (fastest) - Asíncrona - peligroso (lo más rápido) - AdvancedSettings @@ -331,14 +332,6 @@ Ignore the proxy and connect to the Internet directly? Reset to default settings Restablecer configuración por defecto - - Chat history - Historial de Chat - - - <html><head/><body><p><a href="http://www.sqlite.org/pragma.html#pragma_synchronous"><span style=" text-decoration: underline; color:#0000ff;">Writing to DB</span></a></p></body></html> - <html><head/><body><p><a href="http://www.sqlite.org/pragma.html#pragma_synchronous"><span style=" text-decoration: underline; color:#0000ff;">Escritura a la BD</span></a></p></body></html> - Android @@ -1801,6 +1794,10 @@ Compártelo con tus amigos para poder comunicarte. %1.tox was successfully imported %1.tox ha sido importado exitosamente + + Version %1, %2 + Versión %1, %2 + Update The title of a message box @@ -1867,6 +1864,86 @@ Será instalada cuando reinicies qTox. Desktop as a camera input for screen sharing Pantalla + + Incorrect responce + Respuesta erronea + + + No password in response + Respuesta sin contraseña + + + Server doesn't support Toxme + El servidor no soporta Toxme + + + You must send POST requests to /api + Tienes que mandar una petición POST a /api + + + Please try again using a HTTPS connection + Inténtalo de nuevo usando una conexión HTTPS + + + I was unable to read your encrypted payload + No fue posible leer tu payload cifrado + + + You're making too many requests. Wait an hour and try again + Estás haciendo demasiadas peticiones. Inténtalo de nuevo en una hora + + + This name is already in use + Ese nombre ya está en uso + + + This Tox ID is already registered under another name + Esta Tox ID ya fue registrada bajo otro nombre + + + Please don't use a space in your name + Espacios en el nombre no están permitidos + + + Password incorrect + Contraseña incorrecta + + + You can't use this name + No puedes usar ese nombre + + + Name not found + Nombre no encontrado + + + Tox ID not sent + No se envió la Tox ID + + + Lookup failed because the other server replied with invalid data + La consulta falló debido a datos invalidos enviados por otro servidor + + + That user does not exist + Ese usuario no existe + + + Internal lookup error. Please file a bug + Fallo interno en la consulta. Por favor reporta este error + + + Unknown error (%1) + Error desconocido (%1) + + + Error + Error + + + qTox couldn't open your chat logs, they will be disabled. + qTox no pudo abrir tus historiales de chat, serán deshabilitados. + RemoveFriendDialog From e05e736d336f7ab2c48c68765b7178e9156fcdaf Mon Sep 17 00:00:00 2001 From: Rowen Stipe Date: Tue, 19 Jan 2016 04:36:41 -0500 Subject: [PATCH 118/210] Performed auto-indentation Ran an auto indentation script included in one of my text editors (TextMate:greenheart:) --- osx/info.plist | 218 ++++++++++++++++++++++++------------------------- 1 file changed, 109 insertions(+), 109 deletions(-) diff --git a/osx/info.plist b/osx/info.plist index d6138ae2e..f9b22ce8a 100644 --- a/osx/info.plist +++ b/osx/info.plist @@ -1,113 +1,113 @@ - - NSPrincipalClass - NSApplication - CFBundleIconFile - qtox.icns - CFBundlePackageType - APPL - CFBundleSignature - toxq - CFBundleExecutable - qtox - CFBundleDisplayName - qTox - CFBundleName - qTox - CFBundleVersion - 1.2.2 - CFBundleShortVersionString - @SHORT_VERSION@ - CFBundleIdentifier - chat.tox.qtox - CFBundleURLTypes - - - CFBundleURLName - Tox URL - CFBundleTypeRole - Viewer - CFBundleURLSchemes - - tox - - CFBundleURLIconFile - qtox_profile - - - CFBundleDocumentTypes - - - CFBundleTypeExtensions - - tox - - CFBundleTypeName - Tox profile - CFBundleTypeRole - Editor - CFBundleTypeIconFile - qtox_profile - CFBundleTypeMIMETypes - - application/x-tox.profile - - LSHandlerRank - Owner - LSItemContentTypes - - public.tox - - - - UTImportedTypeDeclarations - - - UTTypeConformsTo - - public.data - - UTTypeIdentifier - public.tox - UTTypeTagSpecification - - com.apple.ostype - TOX - public.filename-extension - - tox - - public.mime-type - tox/x-profile - - - - CFBundleLocalizations - - en_US - bg_BG - cs - de_DE - el - es_MX - fi_FI - fr_FR - hr_HR - hu_HU - it_IT - lt_LT - nl_NL - nb_NO - pl_PL - pt_BR - ru_RU - sl - sv - tr_TR - uk_UA - zh_CH - - + + NSPrincipalClass + NSApplication + CFBundleIconFile + qtox.icns + CFBundlePackageType + APPL + CFBundleSignature + toxq + CFBundleExecutable + qtox + CFBundleDisplayName + qTox + CFBundleName + qTox + CFBundleVersion + 1.2.2 + CFBundleShortVersionString + @SHORT_VERSION@ + CFBundleIdentifier + chat.tox.qtox + CFBundleURLTypes + + + CFBundleURLName + Tox URL + CFBundleTypeRole + Viewer + CFBundleURLSchemes + + tox + + CFBundleURLIconFile + qtox_profile + + + CFBundleDocumentTypes + + + CFBundleTypeExtensions + + tox + + CFBundleTypeName + Tox profile + CFBundleTypeRole + Editor + CFBundleTypeIconFile + qtox_profile + CFBundleTypeMIMETypes + + application/x-tox.profile + + LSHandlerRank + Owner + LSItemContentTypes + + public.tox + + + + UTImportedTypeDeclarations + + + UTTypeConformsTo + + public.data + + UTTypeIdentifier + public.tox + UTTypeTagSpecification + + com.apple.ostype + TOX + public.filename-extension + + tox + + public.mime-type + tox/x-profile + + + + CFBundleLocalizations + + en_US + bg_BG + cs + de_DE + el + es_MX + fi_FI + fr_FR + hr_HR + hu_HU + it_IT + lt_LT + nl_NL + nb_NO + pl_PL + pt_BR + ru_RU + sl + sv + tr_TR + uk_UA + zh_CH + + From 27fda2e579f7da5cdf82afa67999df4fdede3b28 Mon Sep 17 00:00:00 2001 From: Rowen Stipe Date: Tue, 19 Jan 2016 06:36:15 -0500 Subject: [PATCH 119/210] Added basic migration compatibility code. This code works if the ~/Library/Application Support/Tox directory does not already exist. --- src/main.cpp | 11 ++++++----- src/platform/install_osx.cpp | 26 ++++++++++++++++++++++++++ src/platform/install_osx.h | 3 ++- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 324dc418c..05abac6e8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -38,7 +38,7 @@ #include -#if defined(Q_OS_MACX) && defined(QT_RELEASE) +#if defined(Q_OS_OSX) #include "platform/install_osx.h" #endif @@ -98,6 +98,11 @@ int main(int argc, char *argv[]) a.setOrganizationName("Tox"); a.setApplicationVersion("\nGit commit: " + QString(GIT_VERSION)); +#if defined(Q_OS_OSX) + //osx::moveToAppFolder(); TODO: Add setting to enable this feature. + osx::migrateProfiles(); +#endif + #ifdef HIGH_DPI a.setAttribute(Qt::AA_UseHighDpiPixmaps, true); #endif @@ -143,10 +148,6 @@ int main(int argc, char *argv[]) qDebug() << "built on: " << __TIME__ << __DATE__ << "(" << TIMESTAMP << ")"; qDebug() << "commit: " << GIT_VERSION << "\n"; -#if defined(Q_OS_MACX) && defined(QT_RELEASE) - osx::moveToAppFolder(); -#endif - // Install Unicode 6.1 supporting font QFontDatabase::addApplicationFont("://DejaVuSans.ttf"); diff --git a/src/platform/install_osx.cpp b/src/platform/install_osx.cpp index 4638a0168..86e11cdbb 100644 --- a/src/platform/install_osx.cpp +++ b/src/platform/install_osx.cpp @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include @@ -82,3 +84,27 @@ void osx::moveToAppFolder() } } } + +void osx::migrateProfiles() +{ + QString oldPath = QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + QDir::separator() + + "Library" + QDir::separator() + "Preferences" + QDir::separator() + "tox"); + QFileInfo checkDir(oldPath); + + QString newPath = QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + QDir::separator() + + "Library" + QDir::separator() + "Application Support" + QDir::separator() + "Tox"); + QDir dir; + + if (checkDir.exists() && checkDir.isDir()) + { + qDebug() << "OS X: Old settings directory detected migrating to default"; + if( !dir.rename(oldPath, newPath) ) + { + qDebug() << "OS X: Profile migration failed. ~/Library/Application Support/Tox already exists."; + } + } + else + { + qDebug() << "OS X: Old settings directory not detected"; + } +} diff --git a/src/platform/install_osx.h b/src/platform/install_osx.h index 115fabd60..aaab8dde9 100644 --- a/src/platform/install_osx.h +++ b/src/platform/install_osx.h @@ -21,7 +21,7 @@ #include -#ifndef Q_OS_MACX +#ifndef Q_OS_OSX #error "This file is only meant to be compiled for Mac OSX targets" #endif @@ -31,6 +31,7 @@ namespace osx static constexpr int EXIT_UPDATE_MACX_FAIL = 216; void moveToAppFolder(); + void migrateProfiles(); } #endif // INSTALLOSX_H From f79bb2402436ca51849233577dcba63368536800 Mon Sep 17 00:00:00 2001 From: tux3 Date: Tue, 19 Jan 2016 16:28:42 +0100 Subject: [PATCH 120/210] Fix ODR violation in SettingsSerializer Fixes #2173 Also fixes some compilation errors in some situations --- src/persistence/settingsserializer.cpp | 85 +++++++++++--------------- src/persistence/settingsserializer.h | 4 +- 2 files changed, 36 insertions(+), 53 deletions(-) diff --git a/src/persistence/settingsserializer.cpp b/src/persistence/settingsserializer.cpp index 8aaf0e420..28eb5a8d8 100644 --- a/src/persistence/settingsserializer.cpp +++ b/src/persistence/settingsserializer.cpp @@ -31,17 +31,12 @@ using namespace std; const char SettingsSerializer::magic[] = {0x51,0x54,0x4F,0x58}; -inline QDataStream& operator<<(QDataStream& dataStream, const SettingsSerializer::RecordTag& tag) +QDataStream& writeStream(QDataStream& dataStream, const SettingsSerializer::RecordTag& tag) { return dataStream << static_cast(tag); } -inline QDataStream& operator<<(QDataStream& dataStream, const QString& str) -{ - return dataStream << str.toUtf8(); -} - -inline QDataStream& operator<<(QDataStream& dataStream, const QByteArray& data) +QDataStream& writeStream(QDataStream& dataStream, const QByteArray& data) { QByteArray size = vuintToData(data.size()); dataStream.writeRawData(size.data(), size.size()); @@ -49,12 +44,18 @@ inline QDataStream& operator<<(QDataStream& dataStream, const QByteArray& data) return dataStream; } -QDataStream& operator>>(QDataStream& dataStream, SettingsSerializer::RecordTag& tag) +QDataStream& writeStream(QDataStream& dataStream, const QString& str) +{ + return writeStream(dataStream, str.toUtf8()); +} + +QDataStream& readStream(QDataStream& dataStream, SettingsSerializer::RecordTag& tag) { return dataStream.operator >>((uint8_t&)tag); } -inline QDataStream& operator>>(QDataStream& dataStream, QByteArray& data) + +QDataStream& readStream(QDataStream& dataStream, QByteArray& data) { unsigned char num3; size_t num = 0; @@ -214,16 +215,6 @@ void SettingsSerializer::load() readSerialized(); else readIni(); - - /* Dump state for debugging - qDebug() << "SettingsSerializer data:"; - for (int i=0; i> tag; + readStream(stream, tag); if (tag == RecordTag::Value) { QByteArray key; QByteArray value; - stream >> key; - stream >> value; + readStream(stream, key); + readStream(stream, value); setValue(QString::fromUtf8(key), QVariant(QString::fromUtf8(value))); - //qDebug() << "!Got key"<> prefix; + readStream(stream, prefix); beginGroup(QString::fromUtf8(prefix)); - //qDebug()<<"!Group start"<> prefix; + readStream(stream, prefix); beginReadArray(QString::fromUtf8(prefix)); QByteArray sizeData; - stream >> sizeData; + readStream(stream, sizeData); if (sizeData.isEmpty()) { qWarning("The personal save file is corrupted!"); @@ -378,12 +364,11 @@ void SettingsSerializer::readSerialized() } quint64 size = dataToVUint(sizeData); arrays[array].size = max(size, arrays[array].size); - //qDebug()<<"!Array start"<> indexData; + readStream(stream, indexData); if (indexData.isEmpty()) { qWarning("The personal save file is corrupted!"); @@ -393,15 +378,13 @@ void SettingsSerializer::readSerialized() setArrayIndex(index); QByteArray key; QByteArray value; - stream >> key; - stream >> value; + readStream(stream, key); + readStream(stream, value); setValue(QString::fromUtf8(key), QVariant(QString::fromUtf8(value))); - //qDebug() << "!Got array key"<>(QDataStream& dataStream, SettingsSerializer::RecordTag& tag); + friend QDataStream& writeStream(QDataStream& dataStream, const SettingsSerializer::RecordTag& tag); + friend QDataStream& readStream(QDataStream& dataStream, SettingsSerializer::RecordTag& tag); struct Value { From aef447d7c700991e07043fddd57ce410053d29b3 Mon Sep 17 00:00:00 2001 From: tux3 Date: Tue, 19 Jan 2016 23:49:42 +0100 Subject: [PATCH 121/210] Have v4l2 read MJPEG video by default Fixes #2826 Thanks to @seanlaguna for finding a fix --- src/video/cameradevice.cpp | 1 + src/video/videoframe.cpp | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/video/cameradevice.cpp b/src/video/cameradevice.cpp index 77a685b6e..f774bfb12 100644 --- a/src/video/cameradevice.cpp +++ b/src/video/cameradevice.cpp @@ -164,6 +164,7 @@ CameraDevice* CameraDevice::open(QString devName, VideoMode mode) { av_dict_set(&options, "video_size", QString("%1x%2").arg(mode.width).arg(mode.height).toStdString().c_str(), 0); av_dict_set(&options, "framerate", QString().setNum(mode.FPS).toStdString().c_str(), 0); + av_dict_set(&options, "pixel_format", "mjpeg", 0); } #endif #ifdef Q_OS_OSX diff --git a/src/video/videoframe.cpp b/src/video/videoframe.cpp index 75c1d1d8a..427cfa8c8 100644 --- a/src/video/videoframe.cpp +++ b/src/video/videoframe.cpp @@ -32,6 +32,22 @@ VideoFrame::VideoFrame(AVFrame* frame, int w, int h, int fmt, std::functioncolor_range = AVCOL_RANGE_MPEG; + if (pixFmt == AV_PIX_FMT_YUVJ420P) + pixFmt = AV_PIX_FMT_YUV420P; + else if (pixFmt == AV_PIX_FMT_YUVJ411P) + pixFmt = AV_PIX_FMT_YUV411P; + else if (pixFmt == AV_PIX_FMT_YUVJ422P) + pixFmt = AV_PIX_FMT_YUV422P; + else if (pixFmt == AV_PIX_FMT_YUVJ444P) + pixFmt = AV_PIX_FMT_YUV444P; + else if (pixFmt == AV_PIX_FMT_YUVJ440P) + pixFmt = AV_PIX_FMT_YUV440P; + else + frame->color_range = AVCOL_RANGE_UNSPECIFIED; + if (pixFmt == AV_PIX_FMT_YUV420P) frameYUV420 = frame; else if (pixFmt == AV_PIX_FMT_RGB24) From a05310e15509627f68a0181ec0a27c197ce8231b Mon Sep 17 00:00:00 2001 From: Rowen Stipe Date: Wed, 20 Jan 2016 01:22:25 -0500 Subject: [PATCH 122/210] Added case for `/Application Support/Tox` already existing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I tried to get it done without bash… But this was the simplest method that works for this special case scenerio. --- OSX-Migrater.sh | 9 ++++++--- qtox.pro | 3 ++- src/platform/install_osx.cpp | 13 +++++++++++-- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/OSX-Migrater.sh b/OSX-Migrater.sh index b63eb0134..891fd6e9c 100755 --- a/OSX-Migrater.sh +++ b/OSX-Migrater.sh @@ -1,14 +1,17 @@ #!/usr/bin/env bash # A qTox profile migrater for OSX +now=$(date +"%m_%d_%Y-%H.%M.%S") +bak="~/.Tox-Backup-$now" + echo "Figuring out if action is required ..." -if [ -d ~/Library/Prefrences/tox] +if [ -d ~/Library/Preferences/tox ]; then echo "Moving profile(s) ..." cp -r ~/Library/Preferences/tox ~/Library/Application\ Support/ mv ~/Library/Application\ Support/tox/ ~/Library/Application\ Support/Tox - mv ~/Library/Preferences/tox ~/.Tox-Backup + mv ~/Library/Preferences/tox ~/.Tox-Backup-$now echo "Done! You profile(s) have been moved! A back up coppy still exists at:" - echo "~/.Tox-Backup" + echo "$bak" else echo "Cannot locate old profile directory, profile migration not performed" fi diff --git a/qtox.pro b/qtox.pro index 5924e62cd..e73351388 100644 --- a/qtox.pro +++ b/qtox.pro @@ -165,7 +165,8 @@ win32 { contains(DEFINES, QTOX_PLATFORM_EXT) { LIBS += -framework IOKit -framework CoreFoundation } contains(DEFINES, QTOX_FILTER_AUDIO) { LIBS += -lfilteraudio } #Files to be includes into the qTox.app/Contents/Resources folder - APP_RESOURCE.files = img/icons/qtox_profile.icns + #OSX-Migrater.sh part of migrateProfiles() compatabilty code + APP_RESOURCE.files = img/icons/qtox_profile.icns OSX-Migrater.sh APP_RESOURCE.path = Contents/Resources QMAKE_BUNDLE_DATA += APP_RESOURCE #Dynamic versioning for Info.plist diff --git a/src/platform/install_osx.cpp b/src/platform/install_osx.cpp index 86e11cdbb..a5a832bdd 100644 --- a/src/platform/install_osx.cpp +++ b/src/platform/install_osx.cpp @@ -84,7 +84,7 @@ void osx::moveToAppFolder() } } } - +// migrateProfiles() is compatabilty code that can be removed down the line when the time seems right. void osx::migrateProfiles() { QString oldPath = QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + QDir::separator() + @@ -100,7 +100,15 @@ void osx::migrateProfiles() qDebug() << "OS X: Old settings directory detected migrating to default"; if( !dir.rename(oldPath, newPath) ) { - qDebug() << "OS X: Profile migration failed. ~/Library/Application Support/Tox already exists."; + qDebug() << "OS X: Profile migration failed. ~/Library/Application Support/Tox already exists. Using alternate migration method."; + QString OSXMigrater = "../Resources/OSX-Migrater.sh" ; + QProcess::execute(OSXMigrater); + QMessageBox MigrateProfile; + MigrateProfile.setIcon(QMessageBox::Information); + MigrateProfile.setWindowModality(Qt::ApplicationModal); + MigrateProfile.setText("Alternate profile migration method used."); + MigrateProfile.setInformativeText("It has been detected that your profiles \nwhere migrated to the new settings directory; \nusing the alternate migration method. \n\nA backup can be found in your: \n/Users/[USER]/.Tox-Backup[DATE-TIME] \n\nJust in case. \r\n"); + MigrateProfile.exec(); } } else @@ -108,3 +116,4 @@ void osx::migrateProfiles() qDebug() << "OS X: Old settings directory not detected"; } } +// End migrateProfiles() compatibility code From df584531c847730ca186f2e6264e822e9f524fce Mon Sep 17 00:00:00 2001 From: Rowen Stipe Date: Wed, 20 Jan 2016 05:17:03 -0500 Subject: [PATCH 123/210] Enable OS X Auto-run at login --- src/platform/autorun_osx.cpp | 26 ++++++++++++++++++++++-- src/widget/form/settings/generalform.cpp | 3 --- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/platform/autorun_osx.cpp b/src/platform/autorun_osx.cpp index 99362e236..62344d6ad 100644 --- a/src/platform/autorun_osx.cpp +++ b/src/platform/autorun_osx.cpp @@ -19,16 +19,38 @@ #if defined(__APPLE__) && defined(__MACH__) #include "src/platform/autorun.h" +#include +#include +#include +#include +#include +int state ; bool Platform::setAutorun(bool on) { - return false; + QString qtoxPlist = QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + QDir::separator() + + "Library" + QDir::separator() + "LaunchAgents" + QDir::separator() + "chat.tox.qtox.autorun.plist"); + QString qtoxDir = QDir::cleanPath(QCoreApplication::applicationDirPath() + QDir::separator() + "qtox"); + QSettings autoRun(qtoxPlist, QSettings::NativeFormat); + autoRun.setValue("Label","chat.tox.qtox.autorun"); + autoRun.setValue("Program", qtoxDir); + + if (on) + { + autoRun.setValue("RunAtLoad",true); + state = true; + } + else + { + autoRun.setValue("RunAtLoad",false); + state = false; + } } bool Platform::getAutorun() { - return false; + return state; } #endif // defined(__APPLE__) && defined(__MACH__) diff --git a/src/widget/form/settings/generalform.cpp b/src/widget/form/settings/generalform.cpp index 8c88843ce..851c3057b 100644 --- a/src/widget/form/settings/generalform.cpp +++ b/src/widget/form/settings/generalform.cpp @@ -104,9 +104,6 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) : bodyUI->transComboBox->setCurrentIndex(locales.indexOf(Settings::getInstance().getTranslation())); bodyUI->cbAutorun->setChecked(Settings::getInstance().getAutorun()); -#if defined(__APPLE__) && defined(__MACH__) - bodyUI->cbAutorun->setEnabled(false); -#endif bool showSystemTray = Settings::getInstance().getShowSystemTray(); From 8769aa9d8cbf9542830df22c1ddf25b404e6ddc8 Mon Sep 17 00:00:00 2001 From: kehugter Date: Wed, 20 Jan 2016 23:30:32 +0100 Subject: [PATCH 124/210] Update Spanish translation with fixes by @aaannndddyyy --- translations/es.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/translations/es.ts b/translations/es.ts index 730eaec23..3872beddc 100644 --- a/translations/es.ts +++ b/translations/es.ts @@ -111,7 +111,7 @@ se pueden producir problemas con las videollamadas. Restart qTox to install version %1 - Reinicia qTox para instalar la version %1 + Reinicia qTox para instalar la versión %1 qTox is downloading update %1 @@ -1922,7 +1922,7 @@ Será instalada cuando reinicies qTox. Lookup failed because the other server replied with invalid data - La consulta falló debido a datos invalidos enviados por otro servidor + La consulta falló debido a datos inválidos enviados por el servidor That user does not exist From 789eeec77716188923528a6191127e8aececa08c Mon Sep 17 00:00:00 2001 From: sudden6 Date: Thu, 21 Jan 2016 00:29:54 +0100 Subject: [PATCH 125/210] fix toxme error handling fixes a bug in Toxme::deleteAddress returning a QNetworkReply::NetworkError adds some warning messages --- src/net/toxme.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/net/toxme.cpp b/src/net/toxme.cpp index 8fdbe4fb3..79fe81c1b 100644 --- a/src/net/toxme.cpp +++ b/src/net/toxme.cpp @@ -47,6 +47,10 @@ QByteArray Toxme::makeJsonRequest(QString url, QString json, QNetworkReply::Netw qApp->processEvents(); } + error = reply->error(); + if (error) + qWarning() << "makeJsonRequest: A network error occured:" << error.errorString(); + return reply->readAll(); } @@ -70,6 +74,10 @@ QByteArray Toxme::getServerPubkey(QString url, QNetworkReply::NetworkError &erro qApp->processEvents(); } + error = reply->error(); + if (error) + qWarning() << "getServerPubkey: A network error occured:" << error.errorString(); + // Extract key static const QByteArray pattern{"key\":\""}; @@ -277,8 +285,6 @@ int Toxme::deleteAddress(QString server, ToxId id) QString apiUrl = server + "/api"; QNetworkReply::NetworkError error = QNetworkReply::NoError; QByteArray response = makeJsonRequest(apiUrl, prepareEncryptedJson(pubkeyUrl, 2, payload), error); - if (error != QNetworkReply::NoError) - return error; return extractError(response); } From 641486d5070b92557af59657d192d111646eea08 Mon Sep 17 00:00:00 2001 From: sudden6 Date: Thu, 21 Jan 2016 01:11:47 +0100 Subject: [PATCH 126/210] Simpliefy code, return early on error --- src/net/toxme.cpp | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/net/toxme.cpp b/src/net/toxme.cpp index 79fe81c1b..9b384de6b 100644 --- a/src/net/toxme.cpp +++ b/src/net/toxme.cpp @@ -38,18 +38,17 @@ QByteArray Toxme::makeJsonRequest(QString url, QString json, QNetworkReply::Netw request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); QNetworkReply* reply = netman.post(request,json.toUtf8()); - while (reply->isRunning()) { - error = reply->error(); - if (error) - break; - - reply->waitForReadyRead(100); + while (!reply->isFinished()) + { qApp->processEvents(); } error = reply->error(); if (error) - qWarning() << "makeJsonRequest: A network error occured:" << error.errorString(); + { + qWarning() << "makeJsonRequest: A network error occured:" << reply->errorString(); + return QByteArray(); + } return reply->readAll(); } @@ -65,18 +64,17 @@ QByteArray Toxme::getServerPubkey(QString url, QNetworkReply::NetworkError &erro request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); QNetworkReply* reply = netman.get(request); - while (reply->isRunning()) { - error = reply->error(); - if (error) - break; - - reply->waitForReadyRead(100); + while (!reply->isFinished()) + { qApp->processEvents(); } error = reply->error(); if (error) - qWarning() << "getServerPubkey: A network error occured:" << error.errorString(); + { + qWarning() << "getServerPubkey: A network error occured:" << reply->errorString(); + return QByteArray(); + } // Extract key static const QByteArray pattern{"key\":\""}; From 93991368c6202fc9dfe474ad1e9ba5668c8a1e7b Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 20 Jan 2016 16:32:24 -0800 Subject: [PATCH 127/210] Added log rotation functionality. This is to prevent log files from ever exceeding a limit of 1MB each. Only the current and one other log file are kept, giving hopefully enough history for any neccessary debugging. --- src/main.cpp | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 05abac6e8..9e2479876 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -127,8 +128,27 @@ int main(int argc, char *argv[]) sodium_init(); // For the auto-updater #ifdef LOG_TO_FILE + QString logFileDir = Settings::getInstance().getSettingsDirPath(); logFileStream.reset(new QTextStream); - logFileFile.reset(new QFile(Settings::getInstance().getSettingsDirPath()+"qtox.log")); + logFileFile.reset(new QFile(logFileDir + "qtox.log")); + + // Trim log file if over 1MB + if (logFileFile->size() > 1000000) { + qDebug() << "Log file over 1MB, rotating..."; + + QDir dir (logFileDir); + + // Check if log.1 already exists, and if so, delete it + if (dir.exists(logFileDir + "qtox.log.1")) { + dir.remove("qtox.log.1"); + } + + dir.rename("qtox.log", "qtox.log.1"); + + // Return to original log file path + logFileFile->setFileName(logFileDir + "qtox.log"); + } + if (logFileFile->open(QIODevice::Append)) { logFileStream->setDevice(logFileFile.get()); @@ -247,6 +267,6 @@ int main(int argc, char *argv[]) Nexus::destroyInstance(); CameraSource::destroyInstance(); Settings::destroyInstance(); - qDebug() << "Clean exit with status"< Date: Wed, 20 Jan 2016 17:22:43 -0800 Subject: [PATCH 128/210] Removed inconsistancies with logFileDir and handle error on removal of old log file. --- qtox.log | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/main.cpp | 9 +++++---- 2 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 qtox.log diff --git a/qtox.log b/qtox.log new file mode 100644 index 000000000..bbd33499e --- /dev/null +++ b/qtox.log @@ -0,0 +1,45 @@ + +2016-01-20 17:15:57 qTox file logger starting +[17:15:57.226] src/main.cpp:169 : Debug: built on: 17:14:24 Jan 20 2016 ( 1453338437 ) +[17:15:57.226] src/main.cpp:170 : Debug: commit: 93991368c6202fc9dfe474ad1e9ba5668c8a1e7b + +[17:15:57.226] src/persistence/profile.cpp:86 : Debug: Loading tox save "/home/anoa/.config/tox/testing.tox" +[17:15:57.226] src/persistence/settings.cpp:350 : Debug: "Saving global settings at /home/anoa/.config/tox/qtox.ini" +[17:15:57.232] src/persistence/settings.cpp:291 : Debug: Loading personal settings from "/home/anoa/.config/tox/testing.ini" +[17:15:57.233] src/nexus.cpp:82 : Debug: Starting up +[17:15:58.140] src/core/core.cpp:236 : Debug: Loading user profile +[17:15:58.140] src/persistence/profile.cpp:249 : Debug: Loading tox save "/home/anoa/.config/tox/testing.tox" +[17:15:58.141] src/core/core.cpp:132 : Debug: Core starting with IPv6 enabled +[17:15:58.142] src/core/core.cpp:305 : Debug: Self avatar not found, will broadcast empty avatar to friends +[17:15:58.377] src/widget/systemtrayicon.cpp:65 : Debug: Using GTK backend +[17:15:59.637] src/core/core.cpp:407 : Debug: "Connecting to 198.46.138.44:33445 (nurupo)" +[17:15:59.637] src/core/core.cpp:407 : Debug: "Connecting to 178.62.250.138:33445 (Impyy)" +[17:16:04.138] src/core/core.cpp:407 : Debug: "Connecting to 130.133.110.14:33445 (Manolis)" +[17:16:04.139] src/core/core.cpp:407 : Debug: "Connecting to 104.167.101.29:33445 (noisykeyboard)" +[17:16:08.637] src/core/core.cpp:407 : Debug: "Connecting to 205.185.116.116:33445 (Busindre)" +[17:16:08.637] src/core/core.cpp:407 : Debug: "Connecting to 198.98.51.198:443 (Busindre)" +[17:16:10.387] src/core/core.cpp:374 : Debug: Connected to the DHT +[17:16:10.387] src/persistence/profile.cpp:314 : Debug: Saving tox save to "/home/anoa/.config/tox/testing.tox" +[17:16:30.904] src/core/core.cpp:585 : Debug: Requested friendship of 0 +[17:16:30.904] src/persistence/profile.cpp:314 : Debug: Saving tox save to "/home/anoa/.config/tox/testing.tox" +[17:17:04.033] src/persistence/profile.cpp:314 : Debug: Saving tox save to "/home/anoa/.config/tox/testing.tox" + +2016-01-20 17:17:47 qTox file logger starting +[17:17:47.795] src/main.cpp:169 : Debug: built on: 17:14:24 Jan 20 2016 ( 1453338437 ) +[17:17:47.795] src/main.cpp:170 : Debug: commit: 93991368c6202fc9dfe474ad1e9ba5668c8a1e7b + +[17:17:47.796] src/persistence/profile.cpp:86 : Debug: Loading tox save "/home/anoa/.config/tox/testing.tox" +[17:17:47.796] src/persistence/settings.cpp:350 : Debug: "Saving global settings at /home/anoa/.config/tox/qtox.ini" +[17:17:47.800] src/persistence/settings.cpp:291 : Debug: Loading personal settings from "/home/anoa/.config/tox/testing.ini" +[17:17:47.800] src/nexus.cpp:82 : Debug: Starting up +[17:17:48.818] src/core/core.cpp:236 : Debug: Loading user profile +[17:17:48.819] src/persistence/profile.cpp:249 : Debug: Loading tox save "/home/anoa/.config/tox/testing.tox" +[17:17:48.819] src/core/core.cpp:132 : Debug: Core starting with IPv6 enabled +[17:17:48.819] src/core/core.cpp:305 : Debug: Self avatar not found, will broadcast empty avatar to friends +[17:17:48.937] src/widget/systemtrayicon.cpp:65 : Debug: Using GTK backend +[17:17:50.287] src/core/core.cpp:407 : Debug: "Connecting to 205.185.116.116:33445 (Busindre)" +[17:17:50.288] src/core/core.cpp:407 : Debug: "Connecting to 198.98.51.198:443 (Busindre)" +[17:17:54.786] src/core/core.cpp:407 : Debug: "Connecting to 194.249.212.109:33445 (fluke571)" +[17:17:54.787] src/core/core.cpp:407 : Debug: "Connecting to 185.25.116.107:33445 (MAH69K)" +[17:17:58.437] src/core/core.cpp:374 : Debug: Connected to the DHT +[17:17:58.437] src/persistence/profile.cpp:314 : Debug: Saving tox save to "/home/anoa/.config/tox/testing.tox" diff --git a/src/main.cpp b/src/main.cpp index 9e2479876..e598adf83 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -139,11 +139,12 @@ int main(int argc, char *argv[]) QDir dir (logFileDir); // Check if log.1 already exists, and if so, delete it - if (dir.exists(logFileDir + "qtox.log.1")) { - dir.remove("qtox.log.1"); - } + if (dir.remove(logFileDir + "qtox.log.1")) + qDebug() << "Removed log successfully"; + else + qDebug() << "Unable to remove old log file"; - dir.rename("qtox.log", "qtox.log.1"); + dir.rename(logFileDir + "qtox.log", logFileDir + "qtox.log.1"); // Return to original log file path logFileFile->setFileName(logFileDir + "qtox.log"); From bfb866cfa2481870d59a836ff7c2e86583f32b5c Mon Sep 17 00:00:00 2001 From: anoadragon453 Date: Wed, 20 Jan 2016 17:34:03 -0800 Subject: [PATCH 129/210] Removed extraneous qtox.log :) --- qtox.log | 45 --------------------------------------------- 1 file changed, 45 deletions(-) delete mode 100644 qtox.log diff --git a/qtox.log b/qtox.log deleted file mode 100644 index bbd33499e..000000000 --- a/qtox.log +++ /dev/null @@ -1,45 +0,0 @@ - -2016-01-20 17:15:57 qTox file logger starting -[17:15:57.226] src/main.cpp:169 : Debug: built on: 17:14:24 Jan 20 2016 ( 1453338437 ) -[17:15:57.226] src/main.cpp:170 : Debug: commit: 93991368c6202fc9dfe474ad1e9ba5668c8a1e7b - -[17:15:57.226] src/persistence/profile.cpp:86 : Debug: Loading tox save "/home/anoa/.config/tox/testing.tox" -[17:15:57.226] src/persistence/settings.cpp:350 : Debug: "Saving global settings at /home/anoa/.config/tox/qtox.ini" -[17:15:57.232] src/persistence/settings.cpp:291 : Debug: Loading personal settings from "/home/anoa/.config/tox/testing.ini" -[17:15:57.233] src/nexus.cpp:82 : Debug: Starting up -[17:15:58.140] src/core/core.cpp:236 : Debug: Loading user profile -[17:15:58.140] src/persistence/profile.cpp:249 : Debug: Loading tox save "/home/anoa/.config/tox/testing.tox" -[17:15:58.141] src/core/core.cpp:132 : Debug: Core starting with IPv6 enabled -[17:15:58.142] src/core/core.cpp:305 : Debug: Self avatar not found, will broadcast empty avatar to friends -[17:15:58.377] src/widget/systemtrayicon.cpp:65 : Debug: Using GTK backend -[17:15:59.637] src/core/core.cpp:407 : Debug: "Connecting to 198.46.138.44:33445 (nurupo)" -[17:15:59.637] src/core/core.cpp:407 : Debug: "Connecting to 178.62.250.138:33445 (Impyy)" -[17:16:04.138] src/core/core.cpp:407 : Debug: "Connecting to 130.133.110.14:33445 (Manolis)" -[17:16:04.139] src/core/core.cpp:407 : Debug: "Connecting to 104.167.101.29:33445 (noisykeyboard)" -[17:16:08.637] src/core/core.cpp:407 : Debug: "Connecting to 205.185.116.116:33445 (Busindre)" -[17:16:08.637] src/core/core.cpp:407 : Debug: "Connecting to 198.98.51.198:443 (Busindre)" -[17:16:10.387] src/core/core.cpp:374 : Debug: Connected to the DHT -[17:16:10.387] src/persistence/profile.cpp:314 : Debug: Saving tox save to "/home/anoa/.config/tox/testing.tox" -[17:16:30.904] src/core/core.cpp:585 : Debug: Requested friendship of 0 -[17:16:30.904] src/persistence/profile.cpp:314 : Debug: Saving tox save to "/home/anoa/.config/tox/testing.tox" -[17:17:04.033] src/persistence/profile.cpp:314 : Debug: Saving tox save to "/home/anoa/.config/tox/testing.tox" - -2016-01-20 17:17:47 qTox file logger starting -[17:17:47.795] src/main.cpp:169 : Debug: built on: 17:14:24 Jan 20 2016 ( 1453338437 ) -[17:17:47.795] src/main.cpp:170 : Debug: commit: 93991368c6202fc9dfe474ad1e9ba5668c8a1e7b - -[17:17:47.796] src/persistence/profile.cpp:86 : Debug: Loading tox save "/home/anoa/.config/tox/testing.tox" -[17:17:47.796] src/persistence/settings.cpp:350 : Debug: "Saving global settings at /home/anoa/.config/tox/qtox.ini" -[17:17:47.800] src/persistence/settings.cpp:291 : Debug: Loading personal settings from "/home/anoa/.config/tox/testing.ini" -[17:17:47.800] src/nexus.cpp:82 : Debug: Starting up -[17:17:48.818] src/core/core.cpp:236 : Debug: Loading user profile -[17:17:48.819] src/persistence/profile.cpp:249 : Debug: Loading tox save "/home/anoa/.config/tox/testing.tox" -[17:17:48.819] src/core/core.cpp:132 : Debug: Core starting with IPv6 enabled -[17:17:48.819] src/core/core.cpp:305 : Debug: Self avatar not found, will broadcast empty avatar to friends -[17:17:48.937] src/widget/systemtrayicon.cpp:65 : Debug: Using GTK backend -[17:17:50.287] src/core/core.cpp:407 : Debug: "Connecting to 205.185.116.116:33445 (Busindre)" -[17:17:50.288] src/core/core.cpp:407 : Debug: "Connecting to 198.98.51.198:443 (Busindre)" -[17:17:54.786] src/core/core.cpp:407 : Debug: "Connecting to 194.249.212.109:33445 (fluke571)" -[17:17:54.787] src/core/core.cpp:407 : Debug: "Connecting to 185.25.116.107:33445 (MAH69K)" -[17:17:58.437] src/core/core.cpp:374 : Debug: Connected to the DHT -[17:17:58.437] src/persistence/profile.cpp:314 : Debug: Saving tox save to "/home/anoa/.config/tox/testing.tox" From d4b2038bbb33c9acdc36646f4174ff1ea843069a Mon Sep 17 00:00:00 2001 From: sudden6 Date: Thu, 21 Jan 2016 02:35:06 +0100 Subject: [PATCH 130/210] stop cpus from burning on slow networks --- src/net/toxme.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/net/toxme.cpp b/src/net/toxme.cpp index 9b384de6b..a615fd71b 100644 --- a/src/net/toxme.cpp +++ b/src/net/toxme.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,7 @@ QByteArray Toxme::makeJsonRequest(QString url, QString json, QNetworkReply::Netw while (!reply->isFinished()) { + QThread::msleep(1); qApp->processEvents(); } @@ -66,6 +68,7 @@ QByteArray Toxme::getServerPubkey(QString url, QNetworkReply::NetworkError &erro while (!reply->isFinished()) { + QThread::msleep(1); qApp->processEvents(); } From ff6725fe2a6effffa641b5d95488b745982ef821 Mon Sep 17 00:00:00 2001 From: tux3 Date: Thu, 21 Jan 2016 02:41:13 +0100 Subject: [PATCH 131/210] Fix #2194: Create QApplication before logging --- src/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index e598adf83..463f8f62f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -93,12 +93,13 @@ void logMessageHandler(QtMsgType type, const QMessageLogContext& ctxt, const QSt int main(int argc, char *argv[]) { - qInstallMessageHandler(logMessageHandler); // Enable log as early as possible QApplication a(argc, argv); a.setApplicationName("qTox"); a.setOrganizationName("Tox"); a.setApplicationVersion("\nGit commit: " + QString(GIT_VERSION)); + qInstallMessageHandler(logMessageHandler); // Enable log as early as possible (but not earlier!) + #if defined(Q_OS_OSX) //osx::moveToAppFolder(); TODO: Add setting to enable this feature. osx::migrateProfiles(); From 6cc36a969a7c3135388e4fe48d179721311525e2 Mon Sep 17 00:00:00 2001 From: tux3 Date: Thu, 21 Jan 2016 03:00:46 +0100 Subject: [PATCH 132/210] Fix capitalization of Settings::loadpersonal() My bad, thanks to @antis81 for noticing --- src/nexus.cpp | 2 +- src/persistence/settings.cpp | 6 +++--- src/persistence/settings.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/nexus.cpp b/src/nexus.cpp index 237dafbe9..a6e4fb715 100644 --- a/src/nexus.cpp +++ b/src/nexus.cpp @@ -275,7 +275,7 @@ void Nexus::setProfile(Profile* profile) { getInstance().profile = profile; if (profile) - Settings::getInstance().loadpersonal(profile); + Settings::getInstance().loadPersonal(profile); } AndroidGUI* Nexus::getAndroidGUI() diff --git a/src/persistence/settings.cpp b/src/persistence/settings.cpp index 0839e4303..4532f918c 100644 --- a/src/persistence/settings.cpp +++ b/src/persistence/settings.cpp @@ -265,7 +265,7 @@ void Settings::loadGlobal() loaded = true; } -void Settings::loadpersonal() +void Settings::loadPersonal() { Profile* profile = Nexus::getProfile(); if (!profile) @@ -273,10 +273,10 @@ void Settings::loadpersonal() qCritical() << "No active profile, couldn't load personal settings"; return; } - loadpersonal(profile); + loadPersonal(profile); } -void Settings::loadpersonal(Profile* profile) +void Settings::loadPersonal(Profile* profile) { QMutexLocker locker{&bigLock}; diff --git a/src/persistence/settings.h b/src/persistence/settings.h index 59b8cc87b..858c71beb 100644 --- a/src/persistence/settings.h +++ b/src/persistence/settings.h @@ -49,8 +49,8 @@ public: void savePersonal(Profile *profile); ///< Asynchronous void loadGlobal(); - void loadpersonal(); - void loadpersonal(Profile *profile); + void loadPersonal(); + void loadPersonal(Profile *profile); public slots: void saveGlobal(); ///< Asynchronous From 9e35a73daf233c840d19be0fa89b6235e60186f3 Mon Sep 17 00:00:00 2001 From: tux3 Date: Thu, 21 Jan 2016 04:26:17 +0100 Subject: [PATCH 133/210] Fix #864 visual issue --- src/widget/contentlayout.cpp | 14 ++++++++------ src/widget/contentlayout.h | 6 +++--- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/widget/contentlayout.cpp b/src/widget/contentlayout.cpp index 150444e5b..d65d40835 100644 --- a/src/widget/contentlayout.cpp +++ b/src/widget/contentlayout.cpp @@ -96,13 +96,12 @@ void ContentLayout::init() mainHead->layout()->setSpacing(0); mainHead->setMouseTracking(true); - mainHLine = new QFrame(); - mainHLine->setFrameShape(QFrame::HLine); - mainHLine->setFrameShadow(QFrame::Plain); - QPalette palette = mainHLine->palette(); + mainHLine.setFrameShape(QFrame::HLine); + mainHLine.setFrameShadow(QFrame::Plain); + QPalette palette = mainHLine.palette(); palette.setBrush(QPalette::WindowText, QBrush(QColor(193, 193, 193))); palette.setBrush(QPalette::WindowText, QBrush(QColor(193, 193, 193))); - mainHLine->setPalette(palette); + mainHLine.setPalette(palette); mainContent = new QWidget(); mainContent->setLayout(new QVBoxLayout); @@ -120,7 +119,10 @@ void ContentLayout::init() mainContent->setStyleSheet(Style::getStylesheet(":ui/settings/mainContent.css")); #endif + mainHLineLayout.addWidget(&mainHLine); + mainHLineLayout.addSpacing(5); + addWidget(mainHead); - addWidget(mainHLine); + addLayout(&mainHLineLayout); addWidget(mainContent); } diff --git a/src/widget/contentlayout.h b/src/widget/contentlayout.h index 6955ca63e..be69decc5 100644 --- a/src/widget/contentlayout.h +++ b/src/widget/contentlayout.h @@ -21,8 +21,7 @@ #define CONTENTLAYOUT_H #include - -class QFrame; +#include class ContentLayout : public QVBoxLayout { @@ -33,8 +32,9 @@ public: void clear(); + QFrame mainHLine; + QHBoxLayout mainHLineLayout; QWidget* mainContent; - QFrame* mainHLine; QWidget* mainHead; private: From e45172ea1b3a7c24af0025eb0b3882e4cb553014 Mon Sep 17 00:00:00 2001 From: tux3 Date: Thu, 21 Jan 2016 04:47:26 +0100 Subject: [PATCH 134/210] Fix #944: Allow transparent avatars --- src/widget/form/chatform.cpp | 4 +-- src/widget/form/groupchatform.cpp | 2 +- src/widget/friendwidget.cpp | 11 +++--- src/widget/groupwidget.cpp | 6 ++-- src/widget/maskablepixmapwidget.cpp | 54 ----------------------------- src/widget/maskablepixmapwidget.h | 4 +-- 6 files changed, 12 insertions(+), 69 deletions(-) diff --git a/src/widget/form/chatform.cpp b/src/widget/form/chatform.cpp index 50f9e8092..3fe1b468f 100644 --- a/src/widget/form/chatform.cpp +++ b/src/widget/form/chatform.cpp @@ -72,7 +72,7 @@ ChatForm::ChatForm(Friend* chatFriend) nameLabel->setText(f->getDisplayedName()); - avatar->setPixmap(QPixmap(":/img/contact_dark.svg"), Qt::transparent); + avatar->setPixmap(QPixmap(":/img/contact_dark.svg")); statusMessageLabel = new CroppingLabel(); statusMessageLabel->setObjectName("statusLabel"); @@ -673,7 +673,7 @@ void ChatForm::onAvatarRemoved(uint32_t FriendId) if (FriendId != f->getFriendID()) return; - avatar->setPixmap(QPixmap(":/img/contact_dark.svg"), Qt::transparent); + avatar->setPixmap(QPixmap(":/img/contact_dark.svg")); } void ChatForm::loadHistory(QDateTime since, bool processUndelivered) diff --git a/src/widget/form/groupchatform.cpp b/src/widget/form/groupchatform.cpp index e837d01ec..49eabf169 100644 --- a/src/widget/form/groupchatform.cpp +++ b/src/widget/form/groupchatform.cpp @@ -63,7 +63,7 @@ GroupChatForm::GroupChatForm(Group* chatGroup) nusersLabel->setObjectName("statusLabel"); retranslateUi(); - avatar->setPixmap(Style::scaleSvgImage(":/img/group_dark.svg", avatar->width(), avatar->height()), Qt::transparent); + avatar->setPixmap(Style::scaleSvgImage(":/img/group_dark.svg", avatar->width(), avatar->height())); msgEdit->setObjectName("group"); diff --git a/src/widget/friendwidget.cpp b/src/widget/friendwidget.cpp index 59cf07522..c8e5e06cb 100644 --- a/src/widget/friendwidget.cpp +++ b/src/widget/friendwidget.cpp @@ -49,7 +49,7 @@ FriendWidget::FriendWidget(int FriendId, QString id) , isDefaultAvatar{true} , historyLoaded{false} { - avatar->setPixmap(QPixmap(":/img/contact.svg"), Qt::transparent); + avatar->setPixmap(QPixmap(":/img/contact.svg")); statusPic.setPixmap(QPixmap(":/img/status/dot_offline.svg")); statusPic.setMargin(3); nameLabel->setText(id); @@ -261,7 +261,7 @@ void FriendWidget::setAsActiveChatroom() setActive(true); if (isDefaultAvatar) - avatar->setPixmap(QPixmap(":img/contact_dark.svg"), Qt::transparent); + avatar->setPixmap(QPixmap(":img/contact_dark.svg")); } void FriendWidget::setAsInactiveChatroom() @@ -269,7 +269,7 @@ void FriendWidget::setAsInactiveChatroom() setActive(false); if (isDefaultAvatar) - avatar->setPixmap(QPixmap(":img/contact.svg"), Qt::transparent); + avatar->setPixmap(QPixmap(":img/contact.svg")); } void FriendWidget::updateStatusLight() @@ -365,7 +365,6 @@ void FriendWidget::onAvatarChange(int FriendId, const QPixmap& pic) isDefaultAvatar = false; avatar->setPixmap(pic); - avatar->autopickBackground(); } void FriendWidget::onAvatarRemoved(int FriendId) @@ -376,9 +375,9 @@ void FriendWidget::onAvatarRemoved(int FriendId) isDefaultAvatar = true; if (isActive()) - avatar->setPixmap(QPixmap(":/img/contact_dark.svg"), Qt::transparent); + avatar->setPixmap(QPixmap(":/img/contact_dark.svg")); else - avatar->setPixmap(QPixmap(":/img/contact.svg"), Qt::transparent); + avatar->setPixmap(QPixmap(":/img/contact.svg")); } void FriendWidget::mousePressEvent(QMouseEvent *ev) diff --git a/src/widget/groupwidget.cpp b/src/widget/groupwidget.cpp index a4cbec9e6..3a2e8eb2a 100644 --- a/src/widget/groupwidget.cpp +++ b/src/widget/groupwidget.cpp @@ -39,7 +39,7 @@ GroupWidget::GroupWidget(int GroupId, QString Name) : groupId{GroupId} { - avatar->setPixmap(Style::scaleSvgImage(":img/group.svg", avatar->width(), avatar->height()), Qt::transparent); + avatar->setPixmap(Style::scaleSvgImage(":img/group.svg", avatar->width(), avatar->height())); statusPic.setPixmap(QPixmap(":img/status/dot_online.svg")); statusPic.setMargin(3); nameLabel->setText(Name); @@ -164,13 +164,13 @@ void GroupWidget::onUserListChanged() void GroupWidget::setAsActiveChatroom() { setActive(true); - avatar->setPixmap(Style::scaleSvgImage(":img/group_dark.svg", avatar->width(), avatar->height()), Qt::transparent); + avatar->setPixmap(Style::scaleSvgImage(":img/group_dark.svg", avatar->width(), avatar->height())); } void GroupWidget::setAsInactiveChatroom() { setActive(false); - avatar->setPixmap(Style::scaleSvgImage(":img/group.svg", avatar->width(), avatar->height()), Qt::transparent); + avatar->setPixmap(Style::scaleSvgImage(":img/group.svg", avatar->width(), avatar->height())); } void GroupWidget::updateStatusLight() diff --git a/src/widget/maskablepixmapwidget.cpp b/src/widget/maskablepixmapwidget.cpp index bb2bf8fa9..3791c8a5d 100644 --- a/src/widget/maskablepixmapwidget.cpp +++ b/src/widget/maskablepixmapwidget.cpp @@ -23,7 +23,6 @@ MaskablePixmapWidget::MaskablePixmapWidget(QWidget *parent, QSize size, QString maskName) : QWidget(parent) , maskName(maskName) - , backgroundColor(Qt::white) , clickable(false) { setSize(size); @@ -34,43 +33,6 @@ MaskablePixmapWidget::~MaskablePixmapWidget() delete renderTarget; } -void MaskablePixmapWidget::autopickBackground() -{ - QImage pic = pixmap.toImage(); - - if (pic.isNull()) - return; - - int r = 0; - int g = 0; - int b = 0; - int weight = 0; - - for (int x=0;xclickable = clickable; @@ -81,25 +43,12 @@ void MaskablePixmapWidget::setClickable(bool clickable) unsetCursor(); } -void MaskablePixmapWidget::setPixmap(const QPixmap &pmap, const QColor &background) -{ - if (!pmap.isNull()) - { - unscaled = pmap; - pixmap = pmap.scaled(width() - 2, height() - 2, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); - backgroundColor = background; - manualColor = true; - update(); - } -} - void MaskablePixmapWidget::setPixmap(const QPixmap &pmap) { if (!pmap.isNull()) { unscaled = pmap; pixmap = pmap.scaled(width() - 2, height() - 2, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); - autopickBackground(); update(); } } @@ -122,8 +71,6 @@ void MaskablePixmapWidget::setSize(QSize size) if (!unscaled.isNull()) { pixmap = unscaled.scaled(width() - 2, height() - 2, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); - if (!manualColor) - autopickBackground(); update(); } } @@ -136,7 +83,6 @@ void MaskablePixmapWidget::paintEvent(QPaintEvent *) QPainter painter(renderTarget); painter.setCompositionMode(QPainter::CompositionMode_SourceOver); - painter.fillRect(0,0,width(),height(),backgroundColor); painter.drawPixmap(offset,pixmap); painter.setCompositionMode(QPainter::CompositionMode_DestinationIn); painter.drawPixmap(0,0,mask); diff --git a/src/widget/maskablepixmapwidget.h b/src/widget/maskablepixmapwidget.h index 9cfad272e..f709b6c5b 100644 --- a/src/widget/maskablepixmapwidget.h +++ b/src/widget/maskablepixmapwidget.h @@ -30,7 +30,6 @@ public: ~MaskablePixmapWidget(); void autopickBackground(); void setClickable(bool clickable); - void setPixmap(const QPixmap &pmap, const QColor &background); void setPixmap(const QPixmap &pmap); QPixmap getPixmap() const; void setSize(QSize size); @@ -47,8 +46,7 @@ private: QPixmap* renderTarget = nullptr; // pointer to dynamically call the constructor QSize size; QString maskName; - QColor backgroundColor; - bool clickable, manualColor = false; + bool clickable; }; #endif // MASKABLEPIXMAPWIDGET_H From 963e8996fb38ad6501761ce3c33a87a546229de4 Mon Sep 17 00:00:00 2001 From: tux3 Date: Thu, 21 Jan 2016 04:59:20 +0100 Subject: [PATCH 135/210] Fix #1016: QSettings UTF-8 issues --- src/persistence/settings.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/persistence/settings.cpp b/src/persistence/settings.cpp index 4532f918c..f3ce17924 100644 --- a/src/persistence/settings.cpp +++ b/src/persistence/settings.cpp @@ -97,6 +97,7 @@ void Settings::loadGlobal() if (QFile(globalSettingsFile).exists()) { QSettings ps(globalSettingsFile, QSettings::IniFormat); + ps.setIniCodec("UTF-8"); ps.beginGroup("General"); makeToxPortable = ps.value("makeToxPortable", false).toBool(); ps.endGroup(); @@ -119,6 +120,7 @@ void Settings::loadGlobal() qDebug() << "Loading settings from " + filePath; QSettings s(filePath, QSettings::IniFormat); + s.setIniCodec("UTF-8"); s.beginGroup("Login"); autoLogin = s.value("autoLogin", false).toBool(); s.endGroup(); @@ -246,6 +248,7 @@ void Settings::loadGlobal() if (dhtServerList.isEmpty()) { QSettings rcs(":/conf/settings.ini", QSettings::IniFormat); + rcs.setIniCodec("UTF-8"); rcs.beginGroup("DHT Server"); int serverListSize = rcs.beginReadArray("dhtServerList"); for (int i = 0; i < serverListSize; i ++) @@ -350,6 +353,7 @@ void Settings::saveGlobal() qDebug() << "Saving global settings at " + path; QSettings s(path, QSettings::IniFormat); + s.setIniCodec("UTF-8"); s.clear(); @@ -1515,6 +1519,7 @@ void Settings::createPersonal(QString basename) qDebug() << "Creating new profile settings in " << path; QSettings ps(path, QSettings::IniFormat); + ps.setIniCodec("UTF-8"); ps.beginGroup("Friends"); ps.beginWriteArray("Friend", 0); ps.endArray(); From f0e29a1d465796d27c90a9a4538313288122951d Mon Sep 17 00:00:00 2001 From: tux3 Date: Thu, 21 Jan 2016 05:19:30 +0100 Subject: [PATCH 136/210] Fix #1180: Oversized file transfer bubbles --- src/chatlog/content/filetransferwidget.cpp | 2 +- src/chatlog/content/filetransferwidget.ui | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chatlog/content/filetransferwidget.cpp b/src/chatlog/content/filetransferwidget.cpp index d0b44c06c..84d4f902c 100644 --- a/src/chatlog/content/filetransferwidget.cpp +++ b/src/chatlog/content/filetransferwidget.cpp @@ -100,7 +100,7 @@ FileTransferWidget::FileTransferWidget(QWidget *parent, ToxFile file) ui->progressLabel->setText(tr("Accept to receive this file", "file transfer widget")); } - setFixedHeight(78); + setFixedHeight(64); } FileTransferWidget::~FileTransferWidget() diff --git a/src/chatlog/content/filetransferwidget.ui b/src/chatlog/content/filetransferwidget.ui index 43a16adc5..28d6a8a0b 100644 --- a/src/chatlog/content/filetransferwidget.ui +++ b/src/chatlog/content/filetransferwidget.ui @@ -116,7 +116,7 @@ 6 - 3 + 2 From 70809e877ec0bc05f240bd65950222e416727f90 Mon Sep 17 00:00:00 2001 From: tux3 Date: Thu, 21 Jan 2016 05:28:47 +0100 Subject: [PATCH 137/210] Fix #1434: Groupchat call button color glitch Thanks to @forteGIT for finding the bug --- src/widget/form/groupchatform.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widget/form/groupchatform.cpp b/src/widget/form/groupchatform.cpp index 49eabf169..da7c70a37 100644 --- a/src/widget/form/groupchatform.cpp +++ b/src/widget/form/groupchatform.cpp @@ -216,7 +216,7 @@ void GroupChatForm::onUserListChanged() } // Enable or disable call button - if (peersCount != 1) + if (peersCount != 1 && !callButton->isEnabled()) { callButton->setEnabled(true); callButton->setObjectName("green"); From 217716184b3f12a4537e5e1a18611e2d0e60d744 Mon Sep 17 00:00:00 2001 From: tux3 Date: Thu, 21 Jan 2016 06:19:30 +0100 Subject: [PATCH 138/210] Speedup loading history By not marking everything as not sent then doing a second pass that marks sent things as sent, redoing the layout for every item... --- src/widget/form/chatform.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/widget/form/chatform.cpp b/src/widget/form/chatform.cpp index 3fe1b468f..31ae9cf9b 100644 --- a/src/widget/form/chatform.cpp +++ b/src/widget/form/chatform.cpp @@ -719,12 +719,13 @@ void ChatForm::loadHistory(QDateTime since, bool processUndelivered) ToxId authorId = ToxId(it.sender); QString authorStr = !it.dispName.isEmpty() ? it.dispName : (authorId.isSelf() ? Core::getInstance()->getUsername() : resolveToxId(authorId)); bool isAction = it.message.startsWith("/me ", Qt::CaseInsensitive); + bool needSending = !it.isSent && authorId.isSelf(); ChatMessage::Ptr msg = ChatMessage::createChatMessage(authorStr, isAction ? it.message.mid(4) : it.message, isAction ? ChatMessage::ACTION : ChatMessage::NORMAL, authorId.isSelf(), - QDateTime()); + needSending ? QDateTime() : msgDateTime); if (!isAction && (prevId == authorId) && (prevMsgDateTime.secsTo(msgDateTime) < getChatLog()->repNameAfter) ) msg->hideSender(); @@ -732,11 +733,7 @@ void ChatForm::loadHistory(QDateTime since, bool processUndelivered) prevId = authorId; prevMsgDateTime = msgDateTime; - if (it.isSent || !authorId.isSelf()) - { - msg->markAsSent(msgDateTime); - } - else + if (needSending) { if (processUndelivered) { From 24bccb7bdd9572ba71055683df68f07121f4a177 Mon Sep 17 00:00:00 2001 From: tux3 Date: Thu, 21 Jan 2016 07:13:10 +0100 Subject: [PATCH 139/210] 2x faster Text::regenerate Hopefully without breaking anything substantial --- src/chatlog/content/text.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/chatlog/content/text.cpp b/src/chatlog/content/text.cpp index 4e4adfc8c..14afe8969 100644 --- a/src/chatlog/content/text.cpp +++ b/src/chatlog/content/text.cpp @@ -246,18 +246,23 @@ void Text::regenerate() { doc->setDefaultFont(defFont); + // wrap mode + if (elide) + { + QTextOption opt; + opt.setWrapMode(QTextOption::NoWrap); + doc->setDefaultTextOption(opt); + } + + // width + if (width != 0) + doc->setTextWidth(width); + if (!elide) doc->setHtml(text); else doc->setPlainText(elidedText); - // wrap mode - QTextOption opt; - opt.setWrapMode(elide ? QTextOption::NoWrap : QTextOption::WrapAtWordBoundaryOrAnywhere); - doc->setDefaultTextOption(opt); - - // width - doc->setTextWidth(width); doc->documentLayout()->update(); // update ascent From 94f3e6d6e4d04c2029fb4f54a44b0d7b84d53029 Mon Sep 17 00:00:00 2001 From: tux3 Date: Thu, 21 Jan 2016 07:47:15 +0100 Subject: [PATCH 140/210] Async smiley loading for fast start This can be a ~1s win on startup time with a HDD, now we load and cache the smileys in the background, blocking only if we try to use them while they are still loading --- src/persistence/smileypack.cpp | 15 +++++++++++++-- src/persistence/smileypack.h | 4 +++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/persistence/smileypack.cpp b/src/persistence/smileypack.cpp index e3d80a735..b56facea5 100644 --- a/src/persistence/smileypack.cpp +++ b/src/persistence/smileypack.cpp @@ -33,10 +33,12 @@ #include #include #include +#include SmileyPack::SmileyPack() { - load(Settings::getInstance().getSmileyPack()); + loadingMutex.lock(); + QtConcurrent::run(this, &SmileyPack::load, Settings::getInstance().getSmileyPack()); connect(&Settings::getInstance(), &Settings::smileyPackChanged, this, &SmileyPack::onSmileyPackChanged); } @@ -101,7 +103,10 @@ bool SmileyPack::load(const QString& filename) // open emoticons.xml QFile xmlFile(filename); if (!xmlFile.open(QIODevice::ReadOnly)) + { + loadingMutex.unlock(); return false; // cannot open file + } /* parse the cfg file * sample: @@ -151,11 +156,14 @@ bool SmileyPack::load(const QString& filename) } // success! + loadingMutex.unlock(); return true; } QString SmileyPack::smileyfied(QString msg) { + QMutexLocker locker(&loadingMutex); + QRegExp exp("\\S+"); // matches words int index = msg.indexOf(exp); @@ -179,6 +187,7 @@ QString SmileyPack::smileyfied(QString msg) QList SmileyPack::getEmoticons() const { + QMutexLocker locker(&loadingMutex); return emoticons; } @@ -189,6 +198,7 @@ QString SmileyPack::getAsRichText(const QString &key) QIcon SmileyPack::getAsIcon(const QString &key) { + QMutexLocker locker(&loadingMutex); return getCachedSmiley(key); } @@ -217,5 +227,6 @@ QIcon SmileyPack::getCachedSmiley(const QString &key) void SmileyPack::onSmileyPackChanged() { - load(Settings::getInstance().getSmileyPack()); + loadingMutex.lock(); + QtConcurrent::run(this, &SmileyPack::load, Settings::getInstance().getSmileyPack()); } diff --git a/src/persistence/smileypack.h b/src/persistence/smileypack.h index 262be026a..9281dca3c 100644 --- a/src/persistence/smileypack.h +++ b/src/persistence/smileypack.h @@ -25,6 +25,7 @@ #include #include #include +#include #define SMILEYPACK_SEARCH_PATHS \ { \ @@ -40,7 +41,6 @@ public: static QList > listSmileyPacks(const QStringList& paths = SMILEYPACK_SEARCH_PATHS); static bool isValid(const QString& filename); - bool load(const QString& filename); QString smileyfied(QString msg); QList getEmoticons() const; QString getAsRichText(const QString& key); @@ -54,6 +54,7 @@ private: SmileyPack(SmileyPack&) = delete; SmileyPack& operator=(const SmileyPack&) = delete; + bool load(const QString& filename); ///< The caller must lock loadingMutex and should run it in a thread void cacheSmiley(const QString& name); QIcon getCachedSmiley(const QString& key); @@ -61,6 +62,7 @@ private: QHash iconCache; // representation of a smiley ie. "happy.png" -> data QList emoticons; // {{ ":)", ":-)" }, {":(", ...}, ... } QString path; // directory containing the cfg and image files + mutable QMutex loadingMutex; }; #endif // SMILEYPACK_H From 8253e1e395482e1c4717207fe3396b8bf02493ed Mon Sep 17 00:00:00 2001 From: tux3 Date: Thu, 21 Jan 2016 08:04:46 +0100 Subject: [PATCH 141/210] Fix #1409: Don't save core if nothing really changed --- src/core/core.cpp | 6 ++++++ src/widget/androidgui.cpp | 11 ----------- src/widget/androidgui.h | 4 ---- src/widget/widget.cpp | 6 ------ src/widget/widget.h | 1 - 5 files changed, 6 insertions(+), 22 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index 94393c9dc..220595a9d 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -740,6 +740,9 @@ QString Core::getUsername() const void Core::setUsername(const QString& username) { + if (username == getUsername()) + return; + CString cUsername(username); if (tox_self_set_name(tox, cUsername.data(), cUsername.size(), nullptr) == false) @@ -813,6 +816,9 @@ Status Core::getStatus() const void Core::setStatusMessage(const QString& message) { + if (message == getStatusMessage()) + return; + CString cMessage(message); if (tox_self_set_status_message(tox, cMessage.data(), cMessage.size(), nullptr) == false) diff --git a/src/widget/androidgui.cpp b/src/widget/androidgui.cpp index 500dc0964..507c92dae 100644 --- a/src/widget/androidgui.cpp +++ b/src/widget/androidgui.cpp @@ -81,12 +81,6 @@ void AndroidGUI::onDisconnected() emit statusSet(Status::Offline); } -void AndroidGUI::onUsernameChanged(const QString& newUsername, const QString& oldUsername) -{ - setUsername(oldUsername); // restore old username until Core tells us to set it - Nexus::getCore()->setUsername(newUsername); -} - void AndroidGUI::setUsername(const QString& username) { QString sanename = username; @@ -95,11 +89,6 @@ void AndroidGUI::setUsername(const QString& username) sanitizedNameMention = QRegExp("\\b" + QRegExp::escape(sanename) + "\\b", Qt::CaseInsensitive); } -void AndroidGUI::onStatusMessageChanged(const QString& newStatusMessage, const QString& oldStatusMessage) -{ - Nexus::getCore()->setStatusMessage(newStatusMessage); -} - void AndroidGUI::setStatusMessage(const QString &statusMessage) { diff --git a/src/widget/androidgui.h b/src/widget/androidgui.h index 526697a2c..2c1c27700 100644 --- a/src/widget/androidgui.h +++ b/src/widget/androidgui.h @@ -59,10 +59,6 @@ private: void reloadTheme(); virtual void keyPressEvent(QKeyEvent* event) final override; -private slots: - void onUsernameChanged(const QString& newUsername, const QString& oldUsername); - void onStatusMessageChanged(const QString& newStatusMessage, const QString& oldStatusMessage); - private: Ui::Android* ui; MaskablePixmapWidget* profilePicture; diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index 7501ab776..d2677077e 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -828,12 +828,6 @@ void Widget::hideMainForms(GenericChatroomWidget* chatroomWidget) activeChatroomWidget = chatroomWidget; } -void Widget::onUsernameChanged(const QString& newUsername, const QString& oldUsername) -{ - setUsername(oldUsername); // restore old username until Core tells us to set it - Nexus::getCore()->setUsername(newUsername); -} - void Widget::setUsername(const QString& username) { if (username.isEmpty()) diff --git a/src/widget/widget.h b/src/widget/widget.h index 7ca4f18e2..07327feda 100644 --- a/src/widget/widget.h +++ b/src/widget/widget.h @@ -164,7 +164,6 @@ private slots: void onGroupClicked(); void onTransferClicked(); void showProfile(); - void onUsernameChanged(const QString& newUsername, const QString& oldUsername); void onChatroomWidgetClicked(GenericChatroomWidget *, bool group); void onStatusMessageChanged(const QString& newStatusMessage); void removeFriend(int friendId); From 12763ab54e08ada43197ca0bc70da83806ef445d Mon Sep 17 00:00:00 2001 From: tux3 Date: Thu, 21 Jan 2016 14:56:14 +0100 Subject: [PATCH 142/210] Some english fixes in followup to #2825 --- src/net/toxme.cpp | 12 ++++++------ src/net/toxme.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/net/toxme.cpp b/src/net/toxme.cpp index a615fd71b..8e4fa80aa 100644 --- a/src/net/toxme.cpp +++ b/src/net/toxme.cpp @@ -193,14 +193,14 @@ Toxme::ExecCode Toxme::extractError(QString json) { end = json.indexOf("}"); if (end == -1) - return IncorrectResponce; + return IncorrectResponse; } json.truncate(end); bool ok; int r = json.toInt(&ok); if (!ok) - return IncorrectResponce; + return IncorrectResponse; return ExecCode(r); } @@ -264,7 +264,7 @@ QString Toxme::getPass(QString json, ExecCode &code) { int end = json.indexOf("\""); if (end == -1) { - code = IncorrectResponce; + code = IncorrectResponse; return QString(); } @@ -293,8 +293,8 @@ int Toxme::deleteAddress(QString server, ToxId id) QString Toxme::getErrorMessage(int errorCode) { switch (errorCode) { - case IncorrectResponce: - return QObject::tr("Incorrect responce"); + case IncorrectResponse: + return QObject::tr("Incorrect response"); case NoPassword: return QObject::tr("No password in response"); case ServerError: @@ -322,7 +322,7 @@ QString Toxme::getErrorMessage(int errorCode) case -31: return QObject::tr("Tox ID not sent"); case -41: - return QObject::tr("Lookup failed because the other server replied with invalid data"); + return QObject::tr("Lookup failed because the server replied with invalid data"); case -42: return QObject::tr("That user does not exist"); case -43: diff --git a/src/net/toxme.h b/src/net/toxme.h index 4f36806e1..9d5a2e709 100644 --- a/src/net/toxme.h +++ b/src/net/toxme.h @@ -41,7 +41,7 @@ public: Registered = 0, Updated = 1, ServerError = 2, - IncorrectResponce = 3, + IncorrectResponse = 3, NoPassword = 4 }; From 5693d3ee8651ce200984bb419fa54679e5b3947b Mon Sep 17 00:00:00 2001 From: tux3 Date: Thu, 21 Jan 2016 15:44:38 +0100 Subject: [PATCH 143/210] Revert "2x faster Text::regenerate" This reverts commit 24bccb7bdd9572ba71055683df68f07121f4a177. --- src/chatlog/content/text.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/chatlog/content/text.cpp b/src/chatlog/content/text.cpp index 14afe8969..4e4adfc8c 100644 --- a/src/chatlog/content/text.cpp +++ b/src/chatlog/content/text.cpp @@ -246,23 +246,18 @@ void Text::regenerate() { doc->setDefaultFont(defFont); - // wrap mode - if (elide) - { - QTextOption opt; - opt.setWrapMode(QTextOption::NoWrap); - doc->setDefaultTextOption(opt); - } - - // width - if (width != 0) - doc->setTextWidth(width); - if (!elide) doc->setHtml(text); else doc->setPlainText(elidedText); + // wrap mode + QTextOption opt; + opt.setWrapMode(elide ? QTextOption::NoWrap : QTextOption::WrapAtWordBoundaryOrAnywhere); + doc->setDefaultTextOption(opt); + + // width + doc->setTextWidth(width); doc->documentLayout()->update(); // update ascent From d02348c1f81893c3f30b076e46196ce2cdc3b86d Mon Sep 17 00:00:00 2001 From: apprb Date: Thu, 21 Jan 2016 20:52:57 +0600 Subject: [PATCH 144/210] Fix #2774: Client freezes after attempt to start group audio --- src/audio/audio.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 8f1520f00..eaeb0b7f7 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -563,6 +563,8 @@ void Audio::playGroupAudio(int group, int peer, const int16_t* data, emit groupAudioPlayed(group, peer, volume / bufsize); + locker.unlock(); + playAudioBuffer(call.alSource, data, samples, channels, sample_rate); } From 2654b6cbcda0f5939665ac06ecbf9b77f3edb475 Mon Sep 17 00:00:00 2001 From: tux3 Date: Thu, 21 Jan 2016 16:51:25 +0100 Subject: [PATCH 145/210] Safer casts in Core::getGroupPeerNames --- src/core/core.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index 220595a9d..5effc718e 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -978,21 +978,23 @@ ToxId Core::getGroupPeerToxId(int groupId, int peerId) const QList Core::getGroupPeerNames(int groupId) const { QList names; - int nPeers = getGroupNumberPeers(groupId); - if (nPeers < 0) + int result = getGroupNumberPeers(groupId); + if (result < 0) { qWarning() << "getGroupPeerNames: Unable to get number of peers"; return names; } + uint16_t nPeers = static_cast(result); + std::unique_ptr namesArray{new uint8_t[nPeers][TOX_MAX_NAME_LENGTH]}; std::unique_ptr lengths{new uint16_t[nPeers]}; - int result = tox_group_get_names(tox, groupId, namesArray.get(), lengths.get(), nPeers); + result = tox_group_get_names(tox, groupId, namesArray.get(), lengths.get(), nPeers); if (result != nPeers) { - qWarning() << "getGroupPeerNames: Unexpected result"; + qWarning() << "getGroupPeerNames: Unexpected tox_group_get_names result"; return names; } - for (size_t i=0; i Date: Thu, 21 Jan 2016 17:11:37 +0100 Subject: [PATCH 146/210] Fix margins of file transfer widget Fixes #1180 --- src/chatlog/content/filetransferwidget.ui | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/chatlog/content/filetransferwidget.ui b/src/chatlog/content/filetransferwidget.ui index 28d6a8a0b..290d79035 100644 --- a/src/chatlog/content/filetransferwidget.ui +++ b/src/chatlog/content/filetransferwidget.ui @@ -6,7 +6,7 @@ 0 0 - 625 + 615 243 @@ -68,10 +68,10 @@ - 10 + 4 - 6 + 2 0 @@ -101,22 +101,22 @@ QLayout::SetDefaultConstraint - 6 + 4 - 0 + 2 - 6 + 4 - 0 + 2 6 - 2 + 0 From c415e063e100f7a5c9e2d38359d5436814090c1e Mon Sep 17 00:00:00 2001 From: agilob Date: Thu, 21 Jan 2016 19:47:34 +0000 Subject: [PATCH 147/210] Fix label text colour in login profile Before labels password and username were not visible for me because colour (dark grey) for those label was inherited from OS which has dark theme, and background of the label was light grey. --- src/loginscreen.ui | 2 +- src/nexus.cpp | 2 -- src/widget/loginscreen.cpp | 3 +++ ui/loginScreen/loginScreen.css | 4 ++++ 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/loginscreen.ui b/src/loginscreen.ui index 0b9098730..17fd1c085 100644 --- a/src/loginscreen.ui +++ b/src/loginscreen.ui @@ -279,7 +279,7 @@ - + Username: diff --git a/src/nexus.cpp b/src/nexus.cpp index a6e4fb715..bcbb2f30f 100644 --- a/src/nexus.cpp +++ b/src/nexus.cpp @@ -25,7 +25,6 @@ #include "persistence/settings.h" #include "video/camerasource.h" #include "widget/gui.h" -#include "widget/style.h" #include "widget/loginscreen.h" #include #include @@ -98,7 +97,6 @@ void Nexus::start() qRegisterMetaType>("std::shared_ptr"); loginScreen = new LoginScreen(); - loginScreen->setStyleSheet(Style::getStylesheet(":/ui/loginScreen/loginScreen.css")); #ifdef Q_OS_MAC globalMenuBar = new QMenuBar(0); diff --git a/src/widget/loginscreen.cpp b/src/widget/loginscreen.cpp index d3ba80921..2649ed782 100644 --- a/src/widget/loginscreen.cpp +++ b/src/widget/loginscreen.cpp @@ -26,6 +26,7 @@ #include "src/persistence/settings.h" #include "src/widget/form/setpassworddialog.h" #include "src/widget/translator.h" +#include "src/widget/style.h" #include #include @@ -55,6 +56,8 @@ LoginScreen::LoginScreen(QWidget *parent) : connect(ui->autoLoginCB, &QCheckBox::stateChanged, this, &LoginScreen::onAutoLoginToggled); reset(); + this->setStyleSheet(Style::getStylesheet(":/ui/loginScreen/loginScreen.css")); + retranslateUi(); Translator::registerHandler(std::bind(&LoginScreen::retranslateUi, this), this); } diff --git a/ui/loginScreen/loginScreen.css b/ui/loginScreen/loginScreen.css index 15baa3279..db43b9eb8 100644 --- a/ui/loginScreen/loginScreen.css +++ b/ui/loginScreen/loginScreen.css @@ -46,3 +46,7 @@ QStackedWidget QPushButton #createAccountButton:hover { background: #0c530d; } + +QLabel { + color: black; +} From 14b2e480ae21e1d74da22d5f9b242c6d64b50573 Mon Sep 17 00:00:00 2001 From: agilob Date: Thu, 21 Jan 2016 19:51:54 +0000 Subject: [PATCH 148/210] Loginpage: Apply black colour to qcheckbox as well --- ui/loginScreen/loginScreen.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/loginScreen/loginScreen.css b/ui/loginScreen/loginScreen.css index db43b9eb8..fde684382 100644 --- a/ui/loginScreen/loginScreen.css +++ b/ui/loginScreen/loginScreen.css @@ -47,6 +47,6 @@ QStackedWidget QPushButton background: #0c530d; } -QLabel { +QLabel, QCheckBox { color: black; } From 9cb71aff68538465595a16553524e68e4394a95e Mon Sep 17 00:00:00 2001 From: agilob Date: Thu, 21 Jan 2016 19:53:33 +0000 Subject: [PATCH 149/210] Loginpage: Apply black colour to progressbar --- src/loginscreen.ui | 2 +- ui/loginScreen/loginScreen.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/loginscreen.ui b/src/loginscreen.ui index 17fd1c085..722e6d387 100644 --- a/src/loginscreen.ui +++ b/src/loginscreen.ui @@ -42,7 +42,7 @@ true - 1 + 0 diff --git a/ui/loginScreen/loginScreen.css b/ui/loginScreen/loginScreen.css index fde684382..db2c84889 100644 --- a/ui/loginScreen/loginScreen.css +++ b/ui/loginScreen/loginScreen.css @@ -47,6 +47,6 @@ QStackedWidget QPushButton background: #0c530d; } -QLabel, QCheckBox { +QLabel, QCheckBox, QProgressBar { color: black; } From 67620f96617312ccbb27c721c2c3090f036d52e3 Mon Sep 17 00:00:00 2001 From: tux3 Date: Fri, 22 Jan 2016 02:46:06 +0100 Subject: [PATCH 150/210] Fix #2796 --- src/net/autoupdate.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/net/autoupdate.cpp b/src/net/autoupdate.cpp index 0088b7b81..e91a41ec5 100644 --- a/src/net/autoupdate.cpp +++ b/src/net/autoupdate.cpp @@ -86,7 +86,8 @@ bool AutoUpdater::isUpdateAvailable() if (isDownloadingUpdate) return false; - if (!QFile::exists(updaterBin)) + QString updaterPath = updaterBin.startsWith('/') ? updaterBin : qApp->applicationDirPath()+'/'+updaterBin; + if (!QFile::exists(updaterPath)) return false; QByteArray updateFlist = getUpdateFlist(); From 26918270dee03694e0325fd6c649038be08260bc Mon Sep 17 00:00:00 2001 From: agilob Date: Sat, 23 Jan 2016 15:37:28 +0000 Subject: [PATCH 151/210] Make disabled checkbox gray --- ui/loginScreen/loginScreen.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ui/loginScreen/loginScreen.css b/ui/loginScreen/loginScreen.css index db2c84889..d742cbdd1 100644 --- a/ui/loginScreen/loginScreen.css +++ b/ui/loginScreen/loginScreen.css @@ -50,3 +50,7 @@ QStackedWidget QPushButton QLabel, QCheckBox, QProgressBar { color: black; } + +QCheckBox::disabled { + color: gray; +} From b3926c8904f64b655f79216db0c6091489a95439 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sat, 16 Jan 2016 23:59:28 +0100 Subject: [PATCH 152/210] change method description of Audio::setOutputVolume to what it should do --- src/audio/audio.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index eaeb0b7f7..2ba01dfb2 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -307,7 +307,9 @@ qreal Audio::outputVolume() } /** -The volume must be between 0 and 1 +Set the master output volume. + +@param[in] volume the master volume (between 0 and 1) */ void Audio::setOutputVolume(qreal volume) { From a6024b85eaed861ca12f45c4ee698fe16bfaee89 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sun, 3 Jan 2016 13:12:29 +0100 Subject: [PATCH 153/210] initialize a subscribed audio source with "master" volume instead of "max." --- src/audio/audio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 2ba01dfb2..dd4be5432 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -710,7 +710,7 @@ void Audio::subscribeOutput(SID& sid) alGenSources(1, &sid); assert(sid); - alSourcef(sid, AL_GAIN, 1.f); + alSourcef(sid, AL_GAIN, d->outputVolume); d->outSources << sid; qDebug() << "Audio source" << sid << "created. Sources active:" << d->outSources.size(); From 1fb4d0d9f3f43d7f7e0b5584ab78c90b860f7bd7 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sun, 3 Jan 2016 13:13:04 +0100 Subject: [PATCH 154/210] clean up audio settings ui --- src/widget/form/settings/avform.cpp | 4 --- src/widget/form/settings/avsettings.ui | 38 ++++---------------------- 2 files changed, 5 insertions(+), 37 deletions(-) diff --git a/src/widget/form/settings/avform.cpp b/src/widget/form/settings/avform.cpp index d6d1f4776..bd98ddc46 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -363,14 +363,12 @@ void AVForm::onPlaybackValueChanged(int value) { Audio::getInstance().setOutputVolume(value / 100.0); Settings::getInstance().setOutVolume(bodyUI->playbackSlider->value()); - bodyUI->playbackMax->setText(QString::number(value)); } void AVForm::onMicrophoneValueChanged(int value) { Audio::getInstance().setInputVolume(value / 100.0); Settings::getInstance().setInVolume(bodyUI->microphoneSlider->value()); - bodyUI->microphoneMax->setText(QString::number(value)); } void AVForm::createVideoSurface() @@ -411,6 +409,4 @@ bool AVForm::eventFilter(QObject *o, QEvent *e) void AVForm::retranslateUi() { bodyUI->retranslateUi(this); - bodyUI->playbackMax->setText(QString::number(bodyUI->playbackSlider->value())); - bodyUI->microphoneMax->setText(QString::number(bodyUI->microphoneSlider->value())); } diff --git a/src/widget/form/settings/avsettings.ui b/src/widget/form/settings/avsettings.ui index f197788b6..a09c3d939 100644 --- a/src/widget/form/settings/avsettings.ui +++ b/src/widget/form/settings/avsettings.ui @@ -41,13 +41,6 @@ Audio Settings - - - - 0 - - - @@ -58,10 +51,10 @@ - + - + Use slider to set volume of your speakers. @@ -77,21 +70,7 @@ - Microphone - - - - - - - 100 - - - - - - - 100 + Gain @@ -102,14 +81,7 @@ - - - - 0 - - - - + @@ -128,7 +100,7 @@ - Playback + Volume From 7d547b10eb3c8c89d64e4907ad95be3fba7621d1 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Mon, 11 Jan 2016 00:45:55 +0100 Subject: [PATCH 155/210] major changes to audio volume control * use the ALListener object for master volume control * initialize audio sources * audio volumes are now expressed as percentage values between 0 and 1 to the public API * removed artificial amplification of input samples * removed invalid audio source generation in group calls * minor: fixed gain slider max. value to 100 percent --- src/audio/audio.cpp | 217 ++++++++++++++++--------- src/widget/form/settings/avsettings.ui | 2 +- 2 files changed, 137 insertions(+), 82 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index dd4be5432..c0089d319 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -28,8 +28,8 @@ #include "audio.h" #include "src/core/core.h" -#include "src/persistence/settings.h" #include "src/core/coreav.h" +#include "src/persistence/settings.h" #include #include @@ -56,6 +56,22 @@ #include "audiofilterer.h" #endif +#ifndef CHECK_AL_ERROR +#define CHECK_AL_ERROR \ + do { \ + const ALenum al_err = alGetError(); \ + if (al_err) { qWarning("OpenAL error: %d", al_err); } \ + } while (0) +#endif + +#ifndef CHECK_ALC_ERROR +#define CHECK_ALC_ERROR(device) \ + do { \ + const ALCenum alc_err = alcGetError(device); \ + if (alc_err) { qWarning("OpenAL error: %d", alc_err); } \ + } while (0) +#endif + /** @class AudioPlayer @@ -156,13 +172,12 @@ public: AudioPrivate() : audioThread(new QThread) , alInDev(nullptr) - , alOutDev(nullptr) - , alContext(nullptr) - , inputVolume(1.f) - , outputVolume(1.f) , inputInitialized(false) - , outputInitialized(false) , inSubscriptions(0) + , alOutDev(nullptr) + , alOutContext(nullptr) + , alMainSource(0) + , outputInitialized(false) { audioThread->setObjectName("qTox Audio"); QObject::connect(audioThread, &QThread::finished, audioThread, &QThread::deleteLater); @@ -179,6 +194,8 @@ public: cleanupOutput(); } + bool autoInitInput(); + bool autoInitOutput(); bool initInput(QString inDevDescr); bool initOutput(QString outDevDescr); void cleanupInput(); @@ -189,15 +206,15 @@ public: QMutex audioLock; ALCdevice* alInDev; - ALCdevice* alOutDev; - ALCcontext* alContext; - ALuint alMainSource; - qreal inputVolume; - qreal outputVolume; + ALfloat gain; bool inputInitialized; + quint32 inSubscriptions; + + ALCdevice* alOutDev; + ALCcontext* alOutContext; + ALuint alMainSource; bool outputInitialized; - quint32 inSubscriptions; ALSources outSources; QPointer audioMeter; @@ -298,12 +315,21 @@ Audio::~Audio() } /** -Returns the current output volume, between 0 and 1 +Returns the current output volume (between 0 and 1) */ qreal Audio::outputVolume() { QMutexLocker locker(&d->audioLock); - return d->outputVolume; + + if (!d->alMainSource) { + qWarning("Audio output source not initialized."); + return 0.0; + } + + ALfloat volume; + alGetSourcef(d->alMainSource, AL_GAIN, &volume); + + return volume; } /** @@ -315,31 +341,34 @@ void Audio::setOutputVolume(qreal volume) { QMutexLocker locker(&d->audioLock); - d->outputVolume = volume; - alSourcef(d->alMainSource, AL_GAIN, volume); - - for (const ToxGroupCall& call : CoreAV::groupCalls) - { - alSourcef(call.alSource, AL_GAIN, volume); + if (volume < 0.0) { + volume = 0.0; + } else if (volume > 1.0) { + volume = 1.0; } - for (const ToxFriendCall& call : CoreAV::calls) - { - alSourcef(call.alSource, AL_GAIN, volume); - } + alListenerf(AL_GAIN, volume); + CHECK_AL_ERROR; } qreal Audio::inputVolume() { QMutexLocker locker(&d->audioLock); - return d->inputVolume; + return d->gain; } void Audio::setInputVolume(qreal volume) { QMutexLocker locker(&d->audioLock); - d->inputVolume = volume; + + if (volume < 0.0) { + volume = 0.0; + } else if (volume > 1.0) { + volume = 1.0; + } + + d->gain = volume; } void Audio::reinitInput(const QString& inDevDesc) @@ -365,11 +394,9 @@ void Audio::subscribeInput() { QMutexLocker locker(&d->audioLock); - if (!d->alInDev) { - if (!d->initInput(Settings::getInstance().getInDev())) { - qWarning("Failed to subscribe to audio input device."); - return; - } + if (!d->autoInitInput()) { + qWarning("Failed to subscribe to audio input device."); + return; } d->inSubscriptions++; @@ -394,6 +421,26 @@ void Audio::unsubscribeInput() d->cleanupInput(); } +/** +Initialize audio input device, if not initialized. + +@return true, if device was initialized; false otherwise +*/ +bool AudioPrivate::autoInitInput() +{ + return alInDev ? true : initInput(Settings::getInstance().getInDev()); +} + +/** +Initialize audio output device, if not initialized. + +@return true, if device was initialized; false otherwise +*/ +bool AudioPrivate::autoInitOutput() +{ + return alOutDev ? true : initOutput(Settings::getInstance().getOutDev()); +} + bool AudioPrivate::initInput(QString inDevDescr) { qDebug() << "Opening audio input" << inDevDescr; @@ -421,14 +468,14 @@ bool AudioPrivate::initInput(QString inDevDescr) sampleRate, stereoFlag, bufSize); // Restart the capture if necessary - if (alInDev) { - qDebug() << "Opened audio input" << inDevDescr; - alcCaptureStart(alInDev); - } else { - qCritical() << "Failed to initialize audio input device:" << inDevDescr; + if (!alInDev) { + qWarning() << "Failed to initialize audio input device:" << inDevDescr; return false; } + qDebug() << "Opened audio input" << inDevDescr; + alcCaptureStart(alInDev); + inputInitialized = true; return true; } @@ -445,7 +492,7 @@ bool AudioPrivate::initOutput(QString outDevDescr) outputInitialized = false; if (outDevDescr == "none") - return true; + return false; assert(!alOutDev); @@ -459,31 +506,39 @@ bool AudioPrivate::initOutput(QString outDevDescr) if (!outDevDescr.isEmpty()) alOutDev = alcOpenDevice(outDevDescr.toUtf8().constData()); - if (alOutDev) + if (!alOutDev) { - alContext = alcCreateContext(alOutDev, nullptr); - if (alcMakeContextCurrent(alContext)) - { - alGenSources(1, &alMainSource); - alSourcef(alMainSource, AL_GAIN, outputVolume); - } - else - { - qWarning() << "Cannot create output audio context"; - cleanupOutput(); - return false; - } - - Core* core = Core::getInstance(); - if (core) - core->getAv()->invalidateCallSources(); // Force to regen each group call's sources - - outputInitialized = true; - return true; + qWarning() << "Cannot open output audio device" << outDevDescr; + return false; } - qWarning() << "Cannot open output audio device" << outDevDescr; - return false; + qDebug() << "Opened audio output" << outDevDescr; + alOutContext = alcCreateContext(alOutDev, nullptr); + CHECK_ALC_ERROR(alOutDev); + + if (!alcMakeContextCurrent(alOutContext)) { + qWarning() << "Cannot create output audio context"; + return false; + } + + alGenSources(1, &alMainSource); CHECK_AL_ERROR; + alSourcef(alMainSource, AL_GAIN, 1.f); CHECK_AL_ERROR; + alSourcef(alMainSource, AL_PITCH, 1.f); CHECK_AL_ERROR; + alSource3f(alMainSource, AL_VELOCITY, 0.f, 0.f, 0.f); CHECK_AL_ERROR; + alSource3f(alMainSource, AL_POSITION, 0.f, 0.f, 0.f); CHECK_AL_ERROR; + + // init master volume + alListenerf(AL_GAIN, Settings::getInstance().getOutVolume() * 0.01f); + CHECK_AL_ERROR; + + Core* core = Core::getInstance(); + if (core) { + // reset each call's audio source + core->getAv()->invalidateCallSources(); + } + + outputInitialized = true; + return true; } /** @@ -493,10 +548,8 @@ void Audio::playMono16Sound(const QByteArray& data) { QMutexLocker locker(&d->audioLock); - if (!d->alOutDev) - d->initOutput(Settings::getInstance().getOutDev()); - - alSourcef(d->alMainSource, AL_GAIN, d->outputVolume); + if (!d->autoInitOutput()) + return; AudioPlayer *player = new AudioPlayer(d->alMainSource, data); connect(player, &AudioPlayer::finished, [=]() { @@ -552,12 +605,6 @@ void Audio::playGroupAudio(int group, int peer, const int16_t* data, if (call.inactive || call.muteVol) return; - if (!call.alSource) - { - alGenSources(1, &call.alSource); - alSourcef(call.alSource, AL_GAIN, d->outputVolume); - } - qreal volume = 0.; int bufsize = samples * 2 * channels; for (int i = 0; i < bufsize; ++i) @@ -606,7 +653,6 @@ void Audio::playAudioBuffer(quint32 alSource, const int16_t *data, int samples, ALint state; alGetSourcei(alSource, AL_SOURCE_STATE, &state); - alSourcef(alSource, AL_GAIN, d->outputVolume); if (state != AL_PLAYING) alSourcePlay(alSource); } @@ -645,17 +691,17 @@ void AudioPrivate::cleanupOutput() outputInitialized = false; if (alOutDev) { - qDebug() << "Closing audio output"; alSourcei(alMainSource, AL_LOOPING, AL_FALSE); alSourceStop(alMainSource); alDeleteSources(1, &alMainSource); if (!alcMakeContextCurrent(nullptr)) - qWarning("Failed to clear current audio context."); + qWarning("Failed to clear audio context."); - alcDestroyContext(alContext); - alContext = nullptr; + alcDestroyContext(alOutContext); + alOutContext = nullptr; + qDebug() << "Closing audio output"; if (alcCloseDevice(alOutDev)) alOutDev = nullptr; else @@ -701,17 +747,26 @@ void Audio::subscribeOutput(SID& sid) { QMutexLocker locker(&d->audioLock); - if (!d->alOutDev) { - if (!d->initOutput(Settings::getInstance().getOutDev())) { - qWarning("Failed to subscribe to audio output device."); - return; - } + if (!d->autoInitOutput()) { + qWarning("Failed to subscribe to audio output device."); + return; + } + + if (!alcMakeContextCurrent(d->alOutContext)) { + qWarning("Failed to activate output context."); + return; } alGenSources(1, &sid); assert(sid); - alSourcef(sid, AL_GAIN, d->outputVolume); d->outSources << sid; + + // initialize source + alSourcef(sid, AL_GAIN, 1.f); CHECK_AL_ERROR; + alSourcef(sid, AL_PITCH, 1.f); CHECK_AL_ERROR; + alSource3f(sid, AL_VELOCITY, 0.f, 0.f, 0.f); CHECK_AL_ERROR; + alSource3f(sid, AL_POSITION, 0.f, 0.f, 0.f); CHECK_AL_ERROR; + qDebug() << "Audio source" << sid << "created. Sources active:" << d->outSources.size(); } @@ -770,7 +825,7 @@ bool Audio::tryCaptureSamples(int16_t* buf, int samples) for (size_t i = 0; i < samples * AUDIO_CHANNELS; ++i) { - int sample = buf[i] * pow(d->inputVolume, 2); + int sample = buf[i]; if (sample < std::numeric_limits::min()) sample = std::numeric_limits::min(); diff --git a/src/widget/form/settings/avsettings.ui b/src/widget/form/settings/avsettings.ui index a09c3d939..f8bf1998e 100644 --- a/src/widget/form/settings/avsettings.ui +++ b/src/widget/form/settings/avsettings.ui @@ -90,7 +90,7 @@ Use slider to set volume of your microphone. - 400 + 100 Qt::Horizontal From e1f7e553ab2b312fd8556dbbc849bd0c915ad80d Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Mon, 11 Jan 2016 00:47:14 +0100 Subject: [PATCH 156/210] initialize volume sliders in av-settings ui at the right place --- src/widget/form/settings/avform.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/widget/form/settings/avform.cpp b/src/widget/form/settings/avform.cpp index bd98ddc46..2edeb2680 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -64,10 +64,10 @@ AVForm::AVForm() : getAudioOutDevices(); getVideoDevices(); }); - connect(bodyUI->playbackSlider, &QSlider::valueChanged, this, &AVForm::onPlaybackValueChanged); - connect(bodyUI->microphoneSlider, &QSlider::valueChanged, this, &AVForm::onMicrophoneValueChanged); bodyUI->playbackSlider->setValue(Settings::getInstance().getOutVolume()); bodyUI->microphoneSlider->setValue(Settings::getInstance().getInVolume()); + connect(bodyUI->playbackSlider, &QSlider::valueChanged, this, &AVForm::onPlaybackValueChanged); + connect(bodyUI->microphoneSlider, &QSlider::valueChanged, this, &AVForm::onMicrophoneValueChanged); bodyUI->playbackSlider->installEventFilter(this); bodyUI->microphoneSlider->installEventFilter(this); From 086e35d106ee9e6030c68d63b36a4626502cf604 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Mon, 11 Jan 2016 00:47:59 +0100 Subject: [PATCH 157/210] use utf-8 strings for audio device specifiers --- src/widget/form/settings/avform.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/widget/form/settings/avform.cpp b/src/widget/form/settings/avform.cpp index 2edeb2680..9ebbe880d 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -286,11 +286,7 @@ void AVForm::getAudioInDevices() while (*pDeviceList) { int len = strlen(pDeviceList); -#ifdef Q_OS_WIN QString inDev = QString::fromUtf8(pDeviceList, len); -#else - QString inDev = QString::fromLocal8Bit(pDeviceList, len); -#endif bodyUI->inDevCombobox->addItem(inDev); if (settingsInDev == inDev) inDevIndex = bodyUI->inDevCombobox->count()-1; @@ -317,11 +313,7 @@ void AVForm::getAudioOutDevices() while (*pDeviceList) { int len = strlen(pDeviceList); -#ifdef Q_OS_WIN QString outDev = QString::fromUtf8(pDeviceList, len); -#else - QString outDev = QString::fromLocal8Bit(pDeviceList, len); -#endif bodyUI->outDevCombobox->addItem(outDev); if (settingsOutDev == outDev) { From 9b5c799742563d72a2d823dee6871eba155c756d Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sat, 16 Jan 2016 22:21:15 +0100 Subject: [PATCH 158/210] fix getter for audio master output volume Return the ALListener's gain as "master" volume. --- src/audio/audio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index c0089d319..82a274f79 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -327,7 +327,7 @@ qreal Audio::outputVolume() } ALfloat volume; - alGetSourcef(d->alMainSource, AL_GAIN, &volume); + alGetListenerf(AL_GAIN, &volume); return volume; } From 719def932b6121beb11760f0f7e5566ab646f596 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sat, 16 Jan 2016 22:27:14 +0100 Subject: [PATCH 159/210] remove unneeded "setCurrentIndex(-1)", when reading audio in/out device lists The combo boxes current index is set to the correct value at end of initialization loop. --- src/widget/form/settings/avform.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/widget/form/settings/avform.cpp b/src/widget/form/settings/avform.cpp index 9ebbe880d..1c7fa995b 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -282,7 +282,6 @@ void AVForm::getAudioInDevices() const char* pDeviceList = Audio::inDeviceNames(); if (pDeviceList) { - //prevent currentIndexChanged to be fired while adding items while (*pDeviceList) { int len = strlen(pDeviceList); @@ -292,8 +291,6 @@ void AVForm::getAudioInDevices() inDevIndex = bodyUI->inDevCombobox->count()-1; pDeviceList += len+1; } - //addItem changes currentIndex -> reset - bodyUI->inDevCombobox->setCurrentIndex(-1); } bodyUI->inDevCombobox->blockSignals(false); bodyUI->inDevCombobox->setCurrentIndex(inDevIndex); @@ -309,7 +306,6 @@ void AVForm::getAudioOutDevices() const char* pDeviceList = Audio::outDeviceNames(); if (pDeviceList) { - //prevent currentIndexChanged to be fired while adding items while (*pDeviceList) { int len = strlen(pDeviceList); @@ -321,8 +317,6 @@ void AVForm::getAudioOutDevices() } pDeviceList += len+1; } - //addItem changes currentIndex -> reset - bodyUI->outDevCombobox->setCurrentIndex(-1); } bodyUI->outDevCombobox->blockSignals(false); bodyUI->outDevCombobox->setCurrentIndex(outDevIndex); From 6f7df25f4adcdb77cee65c3c9f53c6ca3b6d96f7 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sat, 16 Jan 2016 22:31:33 +0100 Subject: [PATCH 160/210] initialize gain/volume after initialization of audio in/out device The gain/volume values are now applied to the settings once, when releasing the slider instead of continuously. --- src/widget/form/settings/avform.cpp | 43 ++++++++++++++++++++++------- src/widget/form/settings/avform.h | 2 ++ 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/widget/form/settings/avform.cpp b/src/widget/form/settings/avform.cpp index 1c7fa995b..bd59cafbc 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -64,13 +64,19 @@ AVForm::AVForm() : getAudioOutDevices(); getVideoDevices(); }); - bodyUI->playbackSlider->setValue(Settings::getInstance().getOutVolume()); - bodyUI->microphoneSlider->setValue(Settings::getInstance().getInVolume()); - connect(bodyUI->playbackSlider, &QSlider::valueChanged, this, &AVForm::onPlaybackValueChanged); - connect(bodyUI->microphoneSlider, &QSlider::valueChanged, this, &AVForm::onMicrophoneValueChanged); + bodyUI->playbackSlider->setTracking(false); bodyUI->playbackSlider->installEventFilter(this); + connect(bodyUI->playbackSlider, &QSlider::sliderMoved, + this, &AVForm::onPlaybackSliderMoved); + connect(bodyUI->playbackSlider, &QSlider::valueChanged, + this, &AVForm::onPlaybackValueChanged); + bodyUI->microphoneSlider->setTracking(false); bodyUI->microphoneSlider->installEventFilter(this); + connect(bodyUI->microphoneSlider, &QSlider::sliderMoved, + this, &AVForm::onMicrophoneSliderMoved); + connect(bodyUI->microphoneSlider, &QSlider::valueChanged, + this, &AVForm::onMicrophoneValueChanged); for (QComboBox* cb : findChildren()) { @@ -328,7 +334,9 @@ void AVForm::onInDevChanged(QString deviceDescriptor) deviceDescriptor = "none"; Settings::getInstance().setInDev(deviceDescriptor); - Audio::getInstance().reinitInput(deviceDescriptor); + Audio& audio = Audio::getInstance(); + audio.reinitInput(deviceDescriptor); + bodyUI->microphoneSlider->setSliderPosition(audio.inputVolume() * 100.f); } void AVForm::onOutDevChanged(QString deviceDescriptor) @@ -337,7 +345,9 @@ void AVForm::onOutDevChanged(QString deviceDescriptor) deviceDescriptor = "none"; Settings::getInstance().setOutDev(deviceDescriptor); - Audio::getInstance().reinitOutput(deviceDescriptor); + Audio& audio = Audio::getInstance(); + audio.reinitOutput(deviceDescriptor); + bodyUI->playbackSlider->setSliderPosition(audio.outputVolume() * 100.f); } void AVForm::onFilterAudioToggled(bool filterAudio) @@ -345,16 +355,29 @@ void AVForm::onFilterAudioToggled(bool filterAudio) Settings::getInstance().setFilterAudio(filterAudio); } +void AVForm::onPlaybackSliderMoved(int value) +{ + Audio& audio = Audio::getInstance(); + if (audio.isOutputReady()) { + const qreal percentage = value / 100.0; + audio.setOutputVolume(percentage); + } +} + void AVForm::onPlaybackValueChanged(int value) { - Audio::getInstance().setOutputVolume(value / 100.0); - Settings::getInstance().setOutVolume(bodyUI->playbackSlider->value()); + Settings::getInstance().setOutVolume(value); +} + +void AVForm::onMicrophoneSliderMoved(int value) +{ + const qreal percentage = value / 100.0; + Audio::getInstance().setInputVolume(percentage); } void AVForm::onMicrophoneValueChanged(int value) { - Audio::getInstance().setInputVolume(value / 100.0); - Settings::getInstance().setInVolume(bodyUI->microphoneSlider->value()); + Settings::getInstance().setInVolume(value); } void AVForm::createVideoSurface() diff --git a/src/widget/form/settings/avform.h b/src/widget/form/settings/avform.h index 42c1b40fd..304ce87db 100644 --- a/src/widget/form/settings/avform.h +++ b/src/widget/form/settings/avform.h @@ -57,7 +57,9 @@ private slots: void onInDevChanged(QString deviceDescriptor); void onOutDevChanged(QString deviceDescriptor); void onFilterAudioToggled(bool filterAudio); + void onPlaybackSliderMoved(int value); void onPlaybackValueChanged(int value); + void onMicrophoneSliderMoved(int value); void onMicrophoneValueChanged(int value); // camera From f4f77af071c2868320ebffac014081807e636b95 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sun, 17 Jan 2016 11:34:50 +0100 Subject: [PATCH 161/210] add "play test sound" button, while changing volume --- src/widget/form/settings/avform.cpp | 11 +++++ src/widget/form/settings/avform.h | 3 ++ src/widget/form/settings/avsettings.ui | 66 ++++++++++++++++---------- 3 files changed, 55 insertions(+), 25 deletions(-) diff --git a/src/widget/form/settings/avform.cpp b/src/widget/form/settings/avform.cpp index bd59cafbc..01ce0773a 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -44,6 +44,9 @@ AVForm::AVForm() : bodyUI = new Ui::AVSettings; bodyUI->setupUi(this); + bodyUI->btnPlayTestSound->setToolTip( + tr("Play a test sound while changing the output volume.")); + #ifdef QTOX_FILTER_AUDIO bodyUI->filterAudio->setChecked(Settings::getInstance().getFilterAudio()); #else @@ -361,6 +364,9 @@ void AVForm::onPlaybackSliderMoved(int value) if (audio.isOutputReady()) { const qreal percentage = value / 100.0; audio.setOutputVolume(percentage); + + if (mPlayTestSound) + audio.playMono16Sound(QStringLiteral(":/audio/notification.pcm")); } } @@ -419,3 +425,8 @@ void AVForm::retranslateUi() { bodyUI->retranslateUi(this); } + +void AVForm::on_btnPlayTestSound_clicked(bool checked) +{ + mPlayTestSound = checked; +} diff --git a/src/widget/form/settings/avform.h b/src/widget/form/settings/avform.h index 304ce87db..56e627f38 100644 --- a/src/widget/form/settings/avform.h +++ b/src/widget/form/settings/avform.h @@ -66,6 +66,8 @@ private slots: void onVideoDevChanged(int index); void onVideoModesIndexChanged(int index); + void on_btnPlayTestSound_clicked(bool checked); + protected: void updateVideoModes(int curIndex); @@ -78,6 +80,7 @@ private: private: Ui::AVSettings *bodyUI; bool subscribedToAudioIn; + bool mPlayTestSound; VideoSurface *camVideoSurface; CameraSource &camera; QVector> videoDeviceList; diff --git a/src/widget/form/settings/avsettings.ui b/src/widget/form/settings/avsettings.ui index f8bf1998e..ee2cada0a 100644 --- a/src/widget/form/settings/avsettings.ui +++ b/src/widget/form/settings/avsettings.ui @@ -41,20 +41,24 @@ Audio Settings - - - - Filter sound from your microphone, so that people hearing you would get better sound. - + + - Filter audio + Playback device + + + + + + + + + + Volume - - - Use slider to set volume of your speakers. @@ -67,24 +71,38 @@ - - + + - Gain + ... + + + + :/ui/volButton/volButton.png:/ui/volButton/volButton.png + + + true - + Capture device - + - + + + + Gain + + + + Use slider to set volume of your microphone. @@ -97,17 +115,13 @@ - - - - Volume + + + + Filter sound from your microphone, so that people hearing you would get better sound. - - - - - Playback device + Filter audio @@ -206,6 +220,8 @@ which may lead to problems with video calls. 1 - + + + From da6bed19b227e956d19c0f6c0346fd597bde12d2 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sun, 17 Jan 2016 11:37:05 +0100 Subject: [PATCH 162/210] enable volume sliders only, if a valid audio device is selected --- src/widget/form/settings/avform.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/widget/form/settings/avform.cpp b/src/widget/form/settings/avform.cpp index 01ce0773a..82efacbb0 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -339,6 +339,7 @@ void AVForm::onInDevChanged(QString deviceDescriptor) Settings::getInstance().setInDev(deviceDescriptor); Audio& audio = Audio::getInstance(); audio.reinitInput(deviceDescriptor); + bodyUI->microphoneSlider->setEnabled(audio.isInputReady()); bodyUI->microphoneSlider->setSliderPosition(audio.inputVolume() * 100.f); } @@ -350,6 +351,7 @@ void AVForm::onOutDevChanged(QString deviceDescriptor) Settings::getInstance().setOutDev(deviceDescriptor); Audio& audio = Audio::getInstance(); audio.reinitOutput(deviceDescriptor); + bodyUI->playbackSlider->setEnabled(audio.isOutputReady()); bodyUI->playbackSlider->setSliderPosition(audio.outputVolume() * 100.f); } From ffbd8fba91cf10a7941b4285c2555b2bd4a8a272 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sun, 17 Jan 2016 11:39:23 +0100 Subject: [PATCH 163/210] do not warn, when requesting the volume from an invalid audio device Instead, we return a defined value (0.0) and keep quiet otherwise. --- src/audio/audio.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 82a274f79..84228cb7b 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -321,13 +321,12 @@ qreal Audio::outputVolume() { QMutexLocker locker(&d->audioLock); - if (!d->alMainSource) { - qWarning("Audio output source not initialized."); - return 0.0; - } + ALfloat volume = 0.0; - ALfloat volume; - alGetListenerf(AL_GAIN, &volume); + if (d->alOutDev) { + alGetListenerf(AL_GAIN, &volume); + CHECK_AL_ERROR; + } return volume; } From fb68d3750ce573942d4051d035a34996614c560a Mon Sep 17 00:00:00 2001 From: tux3 Date: Thu, 21 Jan 2016 16:25:25 +0100 Subject: [PATCH 164/210] Cleanup mic feedback related code It simply doesn't work, so let's do it right later --- src/audio/audio.cpp | 120 -------------------------- src/audio/audio.h | 28 ------ src/widget/tool/micfeedbackwidget.cpp | 6 ++ 3 files changed, 6 insertions(+), 148 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 84228cb7b..552d15273 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -118,52 +118,6 @@ private: ALuint mSource; }; -class AudioMeter : public QThread -{ -public: - AudioMeter() - { - connect(this, &AudioMeter::finished, this, &AudioMeter::deleteLater); - } - - inline void stop() - { - requestInterruption(); - } - -private: - void run() override final - { - static const int framesize = AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS; - - Audio& audio = Audio::getInstance(); - - mNewMaxGain = 0.f; - - QMutexLocker locker(&mMeterLock); - while (!isInterruptionRequested()) { - mListenerReady.wait(locker.mutex()); - locker.relock(); - - int16_t buff[framesize] = {0}; - if (audio.tryCaptureSamples(buff, AUDIO_FRAME_SAMPLE_COUNT)) { - mNewMaxGain = 0.f; - for (int i = 0; i < framesize; ++i) { - mNewMaxGain = qMax(mNewMaxGain, qAbs(buff[i]) / 32767.0); - } - } - - mGainMeasured.wakeAll(); - } - } - -public: - QMutex mMeterLock; - QWaitCondition mListenerReady; - QWaitCondition mGainMeasured; - qreal mNewMaxGain; -}; - class AudioPrivate { typedef QList ALSources; @@ -185,9 +139,6 @@ public: ~AudioPrivate() { - if (audioMeter) - audioMeter->stop(); - audioThread->exit(); audioThread->wait(); cleanupInput(); @@ -216,71 +167,8 @@ public: bool outputInitialized; ALSources outSources; - - QPointer audioMeter; }; -AudioMeterListener::AudioMeterListener(AudioMeter* measureThread) - : mActive(false) - , mAudioMeter(measureThread) -{ - assert(mAudioMeter); -} - -void AudioMeterListener::start() -{ - if (!mAudioMeter->isRunning()) { - mAudioMeter->start(); - // TODO: ensure that audiometer is running - // -> Start listeners from AudioMeter::started signal - while (!mAudioMeter->isRunning()) - QThread::msleep(10); - } - - QThread* listener = new QThread; - connect(listener, &QThread::started, this, &AudioMeterListener::doListen); - connect(listener, &QThread::finished, listener, &QThread::deleteLater); - moveToThread(listener); - - listener->start(); -} - -void AudioMeterListener::stop() -{ - mActive = false; -} - -void AudioMeterListener::processed() -{ - mGainProcessed.wakeAll(); -} - -void AudioMeterListener::doListen() -{ - mMaxGain = 0.f; - mActive = true; - - QMutexLocker locker(&mAudioMeter->mMeterLock); - while (mActive) { - mAudioMeter->mListenerReady.wakeAll(); - mAudioMeter->mGainMeasured.wait(&mAudioMeter->mMeterLock); - locker.relock(); - - if (mAudioMeter->mNewMaxGain > mMaxGain) { - mMaxGain = mAudioMeter->mNewMaxGain; - emit gainChanged(mMaxGain); - } else if (mMaxGain > 0.02f) { - mMaxGain -= 0.008f; - emit gainChanged(mMaxGain); - } - - mGainProcessed.wait(locker.mutex(), 10); - locker.relock(); - } - - mAudioMeter->requestInterruption(); -} - /** Returns the singleton instance. */ @@ -290,14 +178,6 @@ Audio& Audio::getInstance() return instance; } -AudioMeterListener* Audio::createAudioMeterListener() const -{ - if (!d->audioMeter) - d->audioMeter = new AudioMeter; - - return new AudioMeterListener(d->audioMeter); -} - Audio::Audio() : d(new AudioPrivate) { diff --git a/src/audio/audio.h b/src/audio/audio.h index 7436ff55e..f9fa32a49 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -29,8 +29,6 @@ struct Tox; class AudioFilterer; -class AudioMeter; -class AudioMeterListener; class AudioPrivate; // Public default audio settings @@ -50,8 +48,6 @@ public: static Audio& getInstance(); public: - AudioMeterListener* createAudioMeterListener() const; - qreal outputVolume(); void setOutputVolume(qreal volume); @@ -102,28 +98,4 @@ private: AudioPrivate* d; }; -class AudioMeterListener : public QObject -{ - Q_OBJECT -public: - explicit AudioMeterListener(AudioMeter* measureThread); - - void start(); - void stop(); - - void processed(); - -signals: - void gainChanged(qreal newMaxGain); - -private slots: - void doListen(); - -private: - bool mActive; - AudioMeter* mAudioMeter; - qreal mMaxGain; - QWaitCondition mGainProcessed; -}; - #endif // AUDIO_H diff --git a/src/widget/tool/micfeedbackwidget.cpp b/src/widget/tool/micfeedbackwidget.cpp index 60766653e..64457277c 100644 --- a/src/widget/tool/micfeedbackwidget.cpp +++ b/src/widget/tool/micfeedbackwidget.cpp @@ -60,20 +60,26 @@ void MicFeedbackWidget::paintEvent(QPaintEvent*) void MicFeedbackWidget::showEvent(QShowEvent*) { +#if 0 mMeterListener = Audio::getInstance().createAudioMeterListener(); connect(mMeterListener, &AudioMeterListener::gainChanged, this, &MicFeedbackWidget::onGainMetered); mMeterListener->start(); +#endif } void MicFeedbackWidget::hideEvent(QHideEvent*) { +#if 0 mMeterListener->stop(); +#endif } void MicFeedbackWidget::onGainMetered(qreal value) { +#if 0 current = value; update(); mMeterListener->processed(); +#endif } From 0a1833a74bbe2c669cf598b50509a5f84fea5026 Mon Sep 17 00:00:00 2001 From: tux3 Date: Thu, 21 Jan 2016 16:43:13 +0100 Subject: [PATCH 165/210] Un-pimpl This makes the code much shorter and easier to follow, especially since AudioPrivate was right in the middle of audio.cpp, awkwardly splitting things in two Compile times should not be substantially affected since we just need to include the OpenAL C headers --- src/audio/audio.cpp | 223 +++++++++++++++++--------------------------- src/audio/audio.h | 49 ++++++++-- 2 files changed, 126 insertions(+), 146 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 552d15273..dfa4cda15 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -17,7 +17,6 @@ along with qTox. If not, see . */ - // Output some extra debug info #define AUDIO_DEBUG 1 @@ -36,22 +35,10 @@ #include #include #include +#include #include -#if defined(__APPLE__) && defined(__MACH__) - #include - #include -#else - #include - #include -#endif - -#ifndef ALC_ALL_DEVICES_SPECIFIER -// compatibility with older versions of OpenAL -#include -#endif - #ifdef QTOX_FILTER_AUDIO #include "audiofilterer.h" #endif @@ -118,57 +105,6 @@ private: ALuint mSource; }; -class AudioPrivate -{ - typedef QList ALSources; - -public: - AudioPrivate() - : audioThread(new QThread) - , alInDev(nullptr) - , inputInitialized(false) - , inSubscriptions(0) - , alOutDev(nullptr) - , alOutContext(nullptr) - , alMainSource(0) - , outputInitialized(false) - { - audioThread->setObjectName("qTox Audio"); - QObject::connect(audioThread, &QThread::finished, audioThread, &QThread::deleteLater); - } - - ~AudioPrivate() - { - audioThread->exit(); - audioThread->wait(); - cleanupInput(); - cleanupOutput(); - } - - bool autoInitInput(); - bool autoInitOutput(); - bool initInput(QString inDevDescr); - bool initOutput(QString outDevDescr); - void cleanupInput(); - void cleanupOutput(); - -public: - QThread* audioThread; - QMutex audioLock; - - ALCdevice* alInDev; - ALfloat gain; - bool inputInitialized; - quint32 inSubscriptions; - - ALCdevice* alOutDev; - ALCcontext* alOutContext; - ALuint alMainSource; - bool outputInitialized; - - ALSources outSources; -}; - /** Returns the singleton instance. */ @@ -179,19 +115,32 @@ Audio& Audio::getInstance() } Audio::Audio() - : d(new AudioPrivate) + : audioThread(new QThread) + , alInDev(nullptr) + , inputInitialized(false) + , inSubscriptions(0) + , alOutDev(nullptr) + , alOutContext(nullptr) + , alMainSource(0) + , outputInitialized(false) { - moveToThread(d->audioThread); + audioThread->setObjectName("qTox Audio"); + QObject::connect(audioThread, &QThread::finished, audioThread, &QThread::deleteLater); - if (!d->audioThread->isRunning()) - d->audioThread->start(); + moveToThread(audioThread); + + if (!audioThread->isRunning()) + audioThread->start(); else qWarning("Audio thread already started -> ignored."); } Audio::~Audio() { - delete d; + audioThread->exit(); + audioThread->wait(); + cleanupInput(); + cleanupOutput(); } /** @@ -199,11 +148,11 @@ Returns the current output volume (between 0 and 1) */ qreal Audio::outputVolume() { - QMutexLocker locker(&d->audioLock); + QMutexLocker locker(&audioLock); ALfloat volume = 0.0; - if (d->alOutDev) { + if (alOutDev) { alGetListenerf(AL_GAIN, &volume); CHECK_AL_ERROR; } @@ -218,7 +167,7 @@ Set the master output volume. */ void Audio::setOutputVolume(qreal volume) { - QMutexLocker locker(&d->audioLock); + QMutexLocker locker(&audioLock); if (volume < 0.0) { volume = 0.0; @@ -232,14 +181,14 @@ void Audio::setOutputVolume(qreal volume) qreal Audio::inputVolume() { - QMutexLocker locker(&d->audioLock); + QMutexLocker locker(&audioLock); - return d->gain; + return gain; } void Audio::setInputVolume(qreal volume) { - QMutexLocker locker(&d->audioLock); + QMutexLocker locker(&audioLock); if (volume < 0.0) { volume = 0.0; @@ -247,21 +196,21 @@ void Audio::setInputVolume(qreal volume) volume = 1.0; } - d->gain = volume; + gain = volume; } void Audio::reinitInput(const QString& inDevDesc) { - QMutexLocker locker(&d->audioLock); - d->cleanupInput(); - d->initInput(inDevDesc); + QMutexLocker locker(&audioLock); + cleanupInput(); + initInput(inDevDesc); } bool Audio::reinitOutput(const QString& outDevDesc) { - QMutexLocker locker(&d->audioLock); - d->cleanupOutput(); - return d->initOutput(outDevDesc); + QMutexLocker locker(&audioLock); + cleanupOutput(); + return initOutput(outDevDesc); } /** @@ -271,15 +220,15 @@ If the input device is not open, it will be opened before capturing. */ void Audio::subscribeInput() { - QMutexLocker locker(&d->audioLock); + QMutexLocker locker(&audioLock); - if (!d->autoInitInput()) { + if (!autoInitInput()) { qWarning("Failed to subscribe to audio input device."); return; } - d->inSubscriptions++; - qDebug() << "Subscribed to audio input device [" << d->inSubscriptions << "subscriptions ]"; + inSubscriptions++; + qDebug() << "Subscribed to audio input device [" << inSubscriptions << "subscriptions ]"; } /** @@ -289,15 +238,15 @@ If the input device has no more subscriptions, it will be closed. */ void Audio::unsubscribeInput() { - QMutexLocker locker(&d->audioLock); + QMutexLocker locker(&audioLock); - if (d->inSubscriptions > 0) { - d->inSubscriptions--; - qDebug() << "Unsubscribed from audio input device [" << d->inSubscriptions << "subscriptions left ]"; + if (inSubscriptions > 0) { + inSubscriptions--; + qDebug() << "Unsubscribed from audio input device [" << inSubscriptions << "subscriptions left ]"; } - if (!d->inSubscriptions) - d->cleanupInput(); + if (!inSubscriptions) + cleanupInput(); } /** @@ -305,7 +254,7 @@ Initialize audio input device, if not initialized. @return true, if device was initialized; false otherwise */ -bool AudioPrivate::autoInitInput() +bool Audio::autoInitInput() { return alInDev ? true : initInput(Settings::getInstance().getInDev()); } @@ -315,12 +264,12 @@ Initialize audio output device, if not initialized. @return true, if device was initialized; false otherwise */ -bool AudioPrivate::autoInitOutput() +bool Audio::autoInitOutput() { return alOutDev ? true : initOutput(Settings::getInstance().getOutDev()); } -bool AudioPrivate::initInput(QString inDevDescr) +bool Audio::initInput(QString inDevDescr) { qDebug() << "Opening audio input" << inDevDescr; @@ -364,7 +313,7 @@ bool AudioPrivate::initInput(QString inDevDescr) Open an audio output device */ -bool AudioPrivate::initOutput(QString outDevDescr) +bool Audio::initOutput(QString outDevDescr) { qDebug() << "Opening audio output" << outDevDescr; outSources.clear(); @@ -425,17 +374,17 @@ Play a 44100Hz mono 16bit PCM sound */ void Audio::playMono16Sound(const QByteArray& data) { - QMutexLocker locker(&d->audioLock); + QMutexLocker locker(&audioLock); - if (!d->autoInitOutput()) + if (!autoInitOutput()) return; - AudioPlayer *player = new AudioPlayer(d->alMainSource, data); + AudioPlayer *player = new AudioPlayer(alMainSource, data); connect(player, &AudioPlayer::finished, [=]() { - QMutexLocker locker(&d->audioLock); + QMutexLocker locker(&audioLock); - if (d->outSources.isEmpty()) - d->cleanupOutput(); + if (outSources.isEmpty()) + cleanupOutput(); else qDebug("Audio output not closed -> there are pending subscriptions."); }); @@ -473,8 +422,8 @@ Must be called from the audio thread, plays a group call's received audio void Audio::playGroupAudio(int group, int peer, const int16_t* data, unsigned samples, uint8_t channels, unsigned sample_rate) { - assert(QThread::currentThread() == d->audioThread); - QMutexLocker locker(&d->audioLock); + assert(QThread::currentThread() == audioThread); + QMutexLocker locker(&audioLock); if (!CoreAV::groupCalls.contains(group)) return; @@ -499,9 +448,9 @@ void Audio::playGroupAudio(int group, int peer, const int16_t* data, void Audio::playAudioBuffer(quint32 alSource, const int16_t *data, int samples, unsigned channels, int sampleRate) { assert(channels == 1 || channels == 2); - QMutexLocker locker(&d->audioLock); + QMutexLocker locker(&audioLock); - if (!(d->alOutDev && d->outputInitialized)) + if (!(alOutDev && outputInitialized)) return; ALuint bufid; @@ -541,7 +490,7 @@ void Audio::playAudioBuffer(quint32 alSource, const int16_t *data, int samples, Close active audio input device. */ -void AudioPrivate::cleanupInput() +void Audio::cleanupInput() { inputInitialized = false; @@ -565,7 +514,7 @@ void AudioPrivate::cleanupInput() Close active audio output device */ -void AudioPrivate::cleanupOutput() +void Audio::cleanupOutput() { outputInitialized = false; @@ -593,8 +542,8 @@ Returns true if the input device is open and suscribed to */ bool Audio::isInputReady() { - QMutexLocker locker(&d->audioLock); - return d->alInDev && d->inputInitialized; + QMutexLocker locker(&audioLock); + return alInDev && inputInitialized; } /** @@ -602,8 +551,8 @@ Returns true if the output device is open */ bool Audio::isOutputReady() { - QMutexLocker locker(&d->audioLock); - return d->alOutDev && d->outputInitialized; + QMutexLocker locker(&audioLock); + return alOutDev && outputInitialized; } const char* Audio::outDeviceNames() @@ -622,23 +571,23 @@ const char* Audio::inDeviceNames() return alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); } -void Audio::subscribeOutput(SID& sid) +void Audio::subscribeOutput(ALuint& sid) { - QMutexLocker locker(&d->audioLock); + QMutexLocker locker(&audioLock); - if (!d->autoInitOutput()) { + if (!autoInitOutput()) { qWarning("Failed to subscribe to audio output device."); return; } - if (!alcMakeContextCurrent(d->alOutContext)) { + if (!alcMakeContextCurrent(alOutContext)) { qWarning("Failed to activate output context."); return; } alGenSources(1, &sid); assert(sid); - d->outSources << sid; + outSources << sid; // initialize source alSourcef(sid, AL_GAIN, 1.f); CHECK_AL_ERROR; @@ -647,20 +596,20 @@ void Audio::subscribeOutput(SID& sid) alSource3f(sid, AL_POSITION, 0.f, 0.f, 0.f); CHECK_AL_ERROR; qDebug() << "Audio source" << sid << "created. Sources active:" - << d->outSources.size(); + << outSources.size(); } -void Audio::unsubscribeOutput(SID& sid) +void Audio::unsubscribeOutput(ALuint &sid) { - QMutexLocker locker(&d->audioLock); + QMutexLocker locker(&audioLock); - d->outSources.removeAll(sid); + outSources.removeAll(sid); if (sid) { if (alIsSource(sid)) { alDeleteSources(1, &sid); qDebug() << "Audio source" << sid << "deleted. Sources active:" - << d->outSources.size(); + << outSources.size(); } else { qWarning() << "Trying to delete invalid audio source" << sid; } @@ -668,21 +617,21 @@ void Audio::unsubscribeOutput(SID& sid) sid = 0; } - if (d->outSources.isEmpty()) - d->cleanupOutput(); + if (outSources.isEmpty()) + cleanupOutput(); } void Audio::startLoop() { - QMutexLocker locker(&d->audioLock); - alSourcei(d->alMainSource, AL_LOOPING, AL_TRUE); + QMutexLocker locker(&audioLock); + alSourcei(alMainSource, AL_LOOPING, AL_TRUE); } void Audio::stopLoop() { - QMutexLocker locker(&d->audioLock); - alSourcei(d->alMainSource, AL_LOOPING, AL_FALSE); - alSourceStop(d->alMainSource); + QMutexLocker locker(&audioLock); + alSourcei(alMainSource, AL_LOOPING, AL_FALSE); + alSourceStop(alMainSource); } /** @@ -690,17 +639,17 @@ Does nothing and return false on failure */ bool Audio::tryCaptureSamples(int16_t* buf, int samples) { - QMutexLocker lock(&d->audioLock); + QMutexLocker lock(&audioLock); - if (!(d->alInDev && d->inputInitialized)) + if (!(alInDev && inputInitialized)) return false; ALint curSamples = 0; - alcGetIntegerv(d->alInDev, ALC_CAPTURE_SAMPLES, sizeof(curSamples), &curSamples); + alcGetIntegerv(alInDev, ALC_CAPTURE_SAMPLES, sizeof(curSamples), &curSamples); if (curSamples < samples) return false; - alcCaptureSamples(d->alInDev, buf, samples); + alcCaptureSamples(alInDev, buf, samples); for (size_t i = 0; i < samples * AUDIO_CHANNELS; ++i) { @@ -720,14 +669,14 @@ bool Audio::tryCaptureSamples(int16_t* buf, int samples) #if defined(QTOX_FILTER_AUDIO) && defined(ALC_LOOPBACK_CAPTURE_SAMPLES) void Audio::getEchoesToFilter(AudioFilterer* filterer, int samples) { - QMutexLocker locker(&d->audioLock); + QMutexLocker locker(&audioLock); ALint samples; - alcGetIntegerv(&d->alOutDev, ALC_LOOPBACK_CAPTURE_SAMPLES, sizeof(samples), &samples); + alcGetIntegerv(&alOutDev, ALC_LOOPBACK_CAPTURE_SAMPLES, sizeof(samples), &samples); if (samples >= samples) { int16_t buf[samples]; - alcCaptureSamplesLoopback(&d->alOutDev, buf, samples); + alcCaptureSamplesLoopback(&alOutDev, buf, samples); filterer->passAudioOutput(buf, samples); filterer->setEchoDelayMs(5); // This 5ms is configurable I believe } diff --git a/src/audio/audio.h b/src/audio/audio.h index f9fa32a49..9af89db65 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -25,11 +25,23 @@ #include #include -#include +#include + +#if defined(__APPLE__) && defined(__MACH__) + #include + #include +#else + #include + #include +#endif + + +#ifndef ALC_ALL_DEVICES_SPECIFIER +// compatibility with older versions of OpenAL +#include +#endif -struct Tox; class AudioFilterer; -class AudioPrivate; // Public default audio settings static constexpr uint32_t AUDIO_SAMPLE_RATE = 48000; ///< The next best Opus would take is 24k @@ -39,10 +51,9 @@ static constexpr uint32_t AUDIO_CHANNELS = 2; ///< Ideally, we'd auto-detect, bu class Audio : public QObject { - Q_OBJECT + using SID = unsigned int; -public: - typedef quint32 SID; + Q_OBJECT public: static Audio& getInstance(); @@ -62,8 +73,8 @@ public: static const char* outDeviceNames(); static const char* inDeviceNames(); - void subscribeOutput(SID& sid); - void unsubscribeOutput(SID& sid); + void subscribeOutput(ALuint& sid); + void unsubscribeOutput(ALuint& sid); void startLoop(); void stopLoop(); @@ -94,8 +105,28 @@ private: Audio(); ~Audio(); + bool autoInitInput(); + bool autoInitOutput(); + bool initInput(QString inDevDescr); + bool initOutput(QString outDevDescr); + void cleanupInput(); + void cleanupOutput(); + private: - AudioPrivate* d; + QThread* audioThread; + QMutex audioLock; + + ALCdevice* alInDev; + ALfloat gain; + bool inputInitialized; + quint32 inSubscriptions; + + ALCdevice* alOutDev; + ALCcontext* alOutContext; + ALuint alMainSource; + bool outputInitialized; + + QList outSources; }; #endif // AUDIO_H From ce2f8fd1d5948b6df6769ece4568d52040ce36fb Mon Sep 17 00:00:00 2001 From: tux3 Date: Thu, 21 Jan 2016 20:17:18 +0100 Subject: [PATCH 166/210] Cleanup and improve audio input We now subscribe to an event and wait for frames when capturing audio input, the big avdantage is that we only have to fetch the frames from the hardware once, and we don't need to cache anything. The frames are simply dispatched to the client's callbacks immediately. Also removes some outdated ifdefs that did not apply anymore. --- src/audio/audio.cpp | 174 ++++++++++++++++--------------------------- src/audio/audio.h | 50 +++++++------ src/core/coreav.cpp | 106 ++++++++++---------------- src/core/coreav.h | 5 +- src/core/toxcall.cpp | 70 ++++------------- src/core/toxcall.h | 11 +-- 6 files changed, 149 insertions(+), 267 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index dfa4cda15..86007bef1 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -17,14 +17,6 @@ along with qTox. If not, see . */ -// Output some extra debug info -#define AUDIO_DEBUG 1 - -// Fix a 7 years old openal-soft/alsa bug -// http://blog.gmane.org/gmane.comp.lib.openal.devel/month=20080501 -// If set to 1, the capture will be started as long as the device is open -#define FIX_SND_PCM_PREPARE_BUG 0 - #include "audio.h" #include "src/core/core.h" #include "src/core/coreav.h" @@ -117,7 +109,7 @@ Audio& Audio::getInstance() Audio::Audio() : audioThread(new QThread) , alInDev(nullptr) - , inputInitialized(false) + , inGain{1.f} , inSubscriptions(0) , alOutDev(nullptr) , alOutContext(nullptr) @@ -129,6 +121,15 @@ Audio::Audio() moveToThread(audioThread); +#ifdef QTOX_FILTER_AUDIO + filterer.startFilter(AUDIO_SAMPLE_RATE); +#endif + + connect(&captureTimer, &QTimer::timeout, this, &Audio::doCapture); + captureTimer.setInterval(AUDIO_FRAME_DURATION/2); + captureTimer.setSingleShot(false); + captureTimer.start(); + if (!audioThread->isRunning()) audioThread->start(); else @@ -141,12 +142,13 @@ Audio::~Audio() audioThread->wait(); cleanupInput(); cleanupOutput(); + filterer.closeFilter(); } /** Returns the current output volume (between 0 and 1) */ -qreal Audio::outputVolume() +ALfloat Audio::outputVolume() { QMutexLocker locker(&audioLock); @@ -165,38 +167,28 @@ Set the master output volume. @param[in] volume the master volume (between 0 and 1) */ -void Audio::setOutputVolume(qreal volume) +void Audio::setOutputVolume(ALfloat volume) { QMutexLocker locker(&audioLock); - if (volume < 0.0) { - volume = 0.0; - } else if (volume > 1.0) { - volume = 1.0; - } + volume = std::max(0.f, std::min(volume, 1.f)); alListenerf(AL_GAIN, volume); CHECK_AL_ERROR; } -qreal Audio::inputVolume() +ALfloat Audio::inputVolume() { QMutexLocker locker(&audioLock); - return gain; + return inGain; } -void Audio::setInputVolume(qreal volume) +void Audio::setInputVolume(ALfloat volume) { QMutexLocker locker(&audioLock); - if (volume < 0.0) { - volume = 0.0; - } else if (volume > 1.0) { - volume = 1.0; - } - - gain = volume; + inGain = std::max(0.f, std::min(volume, 1.f)); } void Audio::reinitInput(const QString& inDevDesc) @@ -240,10 +232,11 @@ void Audio::unsubscribeInput() { QMutexLocker locker(&audioLock); - if (inSubscriptions > 0) { - inSubscriptions--; - qDebug() << "Unsubscribed from audio input device [" << inSubscriptions << "subscriptions left ]"; - } + if (!inSubscriptions) + return; + + inSubscriptions--; + qDebug() << "Unsubscribed from audio input device [" << inSubscriptions << "subscriptions left ]"; if (!inSubscriptions) cleanupInput(); @@ -273,7 +266,6 @@ bool Audio::initInput(QString inDevDescr) { qDebug() << "Opening audio input" << inDevDescr; - inputInitialized = false; if (inDevDescr == "none") return true; @@ -304,7 +296,6 @@ bool Audio::initInput(QString inDevDescr) qDebug() << "Opened audio input" << inDevDescr; alcCaptureStart(alInDev); - inputInitialized = true; return true; } @@ -416,36 +407,7 @@ void Audio::playGroupAudioQueued(void*,int group, int peer, const int16_t* data, emit static_cast(core)->groupPeerAudioPlaying(group, peer); } -/** -Must be called from the audio thread, plays a group call's received audio -*/ -void Audio::playGroupAudio(int group, int peer, const int16_t* data, - unsigned samples, uint8_t channels, unsigned sample_rate) -{ - assert(QThread::currentThread() == audioThread); - QMutexLocker locker(&audioLock); - - if (!CoreAV::groupCalls.contains(group)) - return; - - ToxGroupCall& call = CoreAV::groupCalls[group]; - - if (call.inactive || call.muteVol) - return; - - qreal volume = 0.; - int bufsize = samples * 2 * channels; - for (int i = 0; i < bufsize; ++i) - volume += abs(data[i]); - - emit groupAudioPlayed(group, peer, volume / bufsize); - - locker.unlock(); - - playAudioBuffer(call.alSource, data, samples, channels, sample_rate); -} - -void Audio::playAudioBuffer(quint32 alSource, const int16_t *data, int samples, unsigned channels, int sampleRate) +void Audio::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, unsigned channels, int sampleRate) { assert(channels == 1 || channels == 2); QMutexLocker locker(&audioLock); @@ -492,21 +454,15 @@ Close active audio input device. */ void Audio::cleanupInput() { - inputInitialized = false; + if (!alInDev) + return; - if (alInDev) - { -#if (!FIX_SND_PCM_PREPARE_BUG) - qDebug() << "stopping audio capture"; - alcCaptureStop(alInDev); -#endif - - qDebug() << "Closing audio input"; - if (alcCaptureCloseDevice(alInDev) == ALC_TRUE) - alInDev = nullptr; - else - qWarning() << "Failed to close input"; - } + qDebug() << "Closing audio input"; + alcCaptureStop(alInDev); + if (alcCaptureCloseDevice(alInDev) == ALC_TRUE) + alInDev = nullptr; + else + qWarning() << "Failed to close input"; } /** @@ -537,13 +493,43 @@ void Audio::cleanupOutput() } } +void Audio::doCapture() +{ + QMutexLocker lock(&audioLock); + + if (!alInDev || !inSubscriptions) + return; + + ALint curSamples = 0; + alcGetIntegerv(alInDev, ALC_CAPTURE_SAMPLES, sizeof(curSamples), &curSamples); + if (curSamples < AUDIO_FRAME_SAMPLE_COUNT) + return; + + int16_t buf[AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS]; + alcCaptureSamples(alInDev, buf, AUDIO_FRAME_SAMPLE_COUNT); + + if (Settings::getInstance().getFilterAudio()) + { +#ifdef ALC_LOOPBACK_CAPTURE_SAMPLES + // compatibility with older versions of OpenAL + getEchoesToFilter(filterer, AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS); +#endif + filterer.filterAudio(buf, AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS); + } + + for (size_t i = 0; i < AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS; ++i) + buf[i] *= inGain; + + emit frameAvailable(buf, AUDIO_FRAME_SAMPLE_COUNT, AUDIO_CHANNELS, AUDIO_SAMPLE_RATE); +} + /** Returns true if the input device is open and suscribed to */ bool Audio::isInputReady() { QMutexLocker locker(&audioLock); - return alInDev && inputInitialized; + return alInDev && inSubscriptions; } /** @@ -634,43 +620,9 @@ void Audio::stopLoop() alSourceStop(alMainSource); } -/** -Does nothing and return false on failure -*/ -bool Audio::tryCaptureSamples(int16_t* buf, int samples) -{ - QMutexLocker lock(&audioLock); - - if (!(alInDev && inputInitialized)) - return false; - - ALint curSamples = 0; - alcGetIntegerv(alInDev, ALC_CAPTURE_SAMPLES, sizeof(curSamples), &curSamples); - if (curSamples < samples) - return false; - - alcCaptureSamples(alInDev, buf, samples); - - for (size_t i = 0; i < samples * AUDIO_CHANNELS; ++i) - { - int sample = buf[i]; - - if (sample < std::numeric_limits::min()) - sample = std::numeric_limits::min(); - else if (sample > std::numeric_limits::max()) - sample = std::numeric_limits::max(); - - buf[i] = sample; - } - - return true; -} - #if defined(QTOX_FILTER_AUDIO) && defined(ALC_LOOPBACK_CAPTURE_SAMPLES) void Audio::getEchoesToFilter(AudioFilterer* filterer, int samples) { - QMutexLocker locker(&audioLock); - ALint samples; alcGetIntegerv(&alOutDev, ALC_LOOPBACK_CAPTURE_SAMPLES, sizeof(samples), &samples); if (samples >= samples) diff --git a/src/audio/audio.h b/src/audio/audio.h index 9af89db65..14a85ddc7 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -26,6 +26,7 @@ #include #include +#include #if defined(__APPLE__) && defined(__MACH__) #include @@ -41,29 +42,28 @@ #include #endif -class AudioFilterer; +#ifdef QTOX_FILTER_AUDIO +#include "audiofilterer.h" +#endif // Public default audio settings static constexpr uint32_t AUDIO_SAMPLE_RATE = 48000; ///< The next best Opus would take is 24k static constexpr uint32_t AUDIO_FRAME_DURATION = 20; ///< In milliseconds -static constexpr uint32_t AUDIO_FRAME_SAMPLE_COUNT = AUDIO_FRAME_DURATION * AUDIO_SAMPLE_RATE/1000; +static constexpr ALint AUDIO_FRAME_SAMPLE_COUNT = AUDIO_FRAME_DURATION * AUDIO_SAMPLE_RATE/1000; static constexpr uint32_t AUDIO_CHANNELS = 2; ///< Ideally, we'd auto-detect, but that's a sane default class Audio : public QObject { - using SID = unsigned int; - Q_OBJECT public: static Audio& getInstance(); -public: - qreal outputVolume(); - void setOutputVolume(qreal volume); + ALfloat outputVolume(); + void setOutputVolume(ALfloat volume); - qreal inputVolume(); - void setInputVolume(qreal volume); + ALfloat inputVolume(); + void setInputVolume(ALfloat volume); void reinitInput(const QString& inDevDesc); bool reinitOutput(const QString& outDevDesc); @@ -75,31 +75,25 @@ public: static const char* inDeviceNames(); void subscribeOutput(ALuint& sid); void unsubscribeOutput(ALuint& sid); + void subscribeInput(); + void unsubscribeInput(); void startLoop(); void stopLoop(); void playMono16Sound(const QByteArray& data); void playMono16Sound(const QString& path); - bool tryCaptureSamples(int16_t *buf, int samples); - void playAudioBuffer(quint32 alSource, const int16_t *data, int samples, + void playAudioBuffer(ALuint alSource, const int16_t *data, int samples, unsigned channels, int sampleRate); static void playGroupAudioQueued(void *, int group, int peer, const int16_t* data, unsigned samples, uint8_t channels, unsigned sample_rate, void*); -#if defined(QTOX_FILTER_AUDIO) && defined(ALC_LOOPBACK_CAPTURE_SAMPLES) - void getEchoesToFilter(AudioFilterer* filter, int samples); -#endif - -public slots: - void subscribeInput(); - void unsubscribeInput(); - void playGroupAudio(int group, int peer, const int16_t* data, - unsigned samples, uint8_t channels, unsigned sample_rate); - signals: void groupAudioPlayed(int group, int peer, unsigned short volume); + /// When there are input subscribers, we regularly emit captured audio frames with this signal + /// Always connect with a blocking queued connection or a lambda, or the behavior is undefined + void frameAvailable(const int16_t *pcm, size_t sample_count, uint8_t channels, uint32_t sampling_rate); private: Audio(); @@ -111,22 +105,30 @@ private: bool initOutput(QString outDevDescr); void cleanupInput(); void cleanupOutput(); + /// Called on the captureTimer events to capture audio + void doCapture(); +#if defined(QTOX_FILTER_AUDIO) && defined(ALC_LOOPBACK_CAPTURE_SAMPLES) + void getEchoesToFilter(AudioFilterer* filter, int samples); +#endif private: QThread* audioThread; QMutex audioLock; ALCdevice* alInDev; - ALfloat gain; - bool inputInitialized; + ALfloat inGain; quint32 inSubscriptions; + QTimer captureTimer; ALCdevice* alOutDev; ALCcontext* alOutContext; ALuint alMainSource; bool outputInitialized; - QList outSources; + QList outSources; +#ifdef QTOX_FILTER_AUDIO + AudioFilterer filterer; +#endif }; #endif // AUDIO_H diff --git a/src/core/coreav.cpp b/src/core/coreav.cpp index 43c0faaf7..ac93794df 100644 --- a/src/core/coreav.cpp +++ b/src/core/coreav.cpp @@ -238,7 +238,7 @@ void CoreAV::timeoutCall(uint32_t friendNum) emit avEnd(friendNum); } -bool CoreAV::sendCallAudio(uint32_t callId) +bool CoreAV::sendCallAudio(uint32_t callId, const int16_t *pcm, size_t samples, uint8_t chans, uint32_t rate) { if (!calls.contains(callId)) return false; @@ -246,58 +246,54 @@ bool CoreAV::sendCallAudio(uint32_t callId) ToxFriendCall& call = calls[callId]; if (call.muteMic || call.inactive - || !(call.state & TOXAV_FRIEND_CALL_STATE_ACCEPTING_A) - || !Audio::getInstance().isInputReady()) + || !(call.state & TOXAV_FRIEND_CALL_STATE_ACCEPTING_A)) { return true; } - int16_t buf[AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS] = {0}; - if (Audio::getInstance().tryCaptureSamples(buf, AUDIO_FRAME_SAMPLE_COUNT)) - { +#if 0 #ifdef QTOX_FILTER_AUDIO - if (Settings::getInstance().getFilterAudio()) + if (Settings::getInstance().getFilterAudio()) + { + if (!call.filterer) { - if (!call.filterer) - { - call.filterer = new AudioFilterer(); - call.filterer->startFilter(AUDIO_SAMPLE_RATE); - } + call.filterer = new AudioFilterer(); + call.filterer->startFilter(AUDIO_SAMPLE_RATE); + } #ifdef ALC_LOOPBACK_CAPTURE_SAMPLES - // compatibility with older versions of OpenAL - Audio::getInstance().getEchoesToFilter(call.filterer, AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS); + // compatibility with older versions of OpenAL + Audio::getInstance().getEchoesToFilter(call.filterer, AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS); +#endif + call.filterer->filterAudio(buf, AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS); + } + else if (call.filterer) + { + delete call.filterer; + call.filterer = nullptr; + } #endif - call.filterer->filterAudio(buf, AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS); - } - else if (call.filterer) - { - delete call.filterer; - call.filterer = nullptr; - } #endif - // TOXAV_ERR_SEND_FRAME_SYNC means toxav failed to lock, retry 5 times in this case - TOXAV_ERR_SEND_FRAME err; - int retries = 0; - do { - if (!toxav_audio_send_frame(toxav, callId, buf, AUDIO_FRAME_SAMPLE_COUNT, - AUDIO_CHANNELS, AUDIO_SAMPLE_RATE, &err)) + // TOXAV_ERR_SEND_FRAME_SYNC means toxav failed to lock, retry 5 times in this case + TOXAV_ERR_SEND_FRAME err; + int retries = 0; + do { + if (!toxav_audio_send_frame(toxav, callId, pcm, samples, chans, rate, &err)) + { + if (err == TOXAV_ERR_SEND_FRAME_SYNC) { - if (err == TOXAV_ERR_SEND_FRAME_SYNC) - { - retries++; - QThread::usleep(500); - } - else - { - qDebug() << "toxav_audio_send_frame error: "<startFilter(AUDIO_SAMPLE_RATE); - } -#ifdef ALC_LOOPBACK_CAPTURE_SAMPLES - Audio::getInstance().getEchoesToFilter(call.filterer, AUDIO_FRAME_SAMPLE_COUNT); -#endif - } - else if (call.filterer) - { - delete call.filterer; - call.filterer = nullptr; - } -#endif - - if (toxav_group_send_audio(toxav_get_tox(toxav), groupId, buf, AUDIO_FRAME_SAMPLE_COUNT, - AUDIO_CHANNELS, AUDIO_SAMPLE_RATE) != 0) - qDebug() << "toxav_group_send_audio error"; - } + if (toxav_group_send_audio(toxav_get_tox(toxav), groupId, pcm, samples, chans, rate) != 0) + qDebug() << "toxav_group_send_audio error"; return true; } diff --git a/src/core/coreav.h b/src/core/coreav.h index 46071362a..f8b5f204f 100644 --- a/src/core/coreav.h +++ b/src/core/coreav.h @@ -52,9 +52,10 @@ public: bool anyActiveCalls(); ///< true is any calls are currently active (note: a call about to start is not yet active) bool isCallVideoEnabled(uint32_t friendNum); - bool sendCallAudio(uint32_t friendNum); ///< Returns false only on error, but not if there's nothing to send + /// Returns false only on error, but not if there's nothing to send + bool sendCallAudio(uint32_t friendNum, const int16_t *pcm, size_t samples, uint8_t chans, uint32_t rate); void sendCallVideo(uint32_t friendNum, std::shared_ptr frame); - bool sendGroupCallAudio(int groupNum); + bool sendGroupCallAudio(int groupNum, const int16_t *pcm, size_t samples, uint8_t chans, uint32_t rate); VideoSource* getVideoSourceFromCall(int callNumber); ///< Get a call's video source void invalidateCallSources(); ///< Forces to regenerate each call's audio sources diff --git a/src/core/toxcall.cpp b/src/core/toxcall.cpp index 191034f1e..237eab033 100644 --- a/src/core/toxcall.cpp +++ b/src/core/toxcall.cpp @@ -14,71 +14,40 @@ using namespace std; ToxCall::ToxCall(uint32_t CallId) - : sendAudioTimer{new QTimer}, callId{CallId}, - inactive{true}, muteMic{false}, muteVol{false}, alSource{0} + : callId{CallId}, alSource{0}, + inactive{true}, muteMic{false}, muteVol{false} { - sendAudioTimer->setInterval(5); - sendAudioTimer->setSingleShot(true); - Audio& audio = Audio::getInstance(); audio.subscribeInput(); audio.subscribeOutput(alSource); - -#ifdef QTOX_FILTER_AUDIO - if (Settings::getInstance().getFilterAudio()) - { - filterer = new AudioFilterer(); - filterer->startFilter(AUDIO_SAMPLE_RATE); - } - else - { - filterer = nullptr; - } -#endif } ToxCall::ToxCall(ToxCall&& other) noexcept - : sendAudioTimer{other.sendAudioTimer}, callId{other.callId}, - inactive{other.inactive}, muteMic{other.muteMic}, muteVol{other.muteVol}, - alSource{other.alSource} + : audioInConn{other.audioInConn}, callId{other.callId}, alSource{other.alSource}, + inactive{other.inactive}, muteMic{other.muteMic}, muteVol{other.muteVol} { - other.sendAudioTimer = nullptr; + other.audioInConn = QMetaObject::Connection(); other.callId = numeric_limits::max(); other.alSource = 0; // required -> ownership of audio input is moved to new instance Audio& audio = Audio::getInstance(); audio.subscribeInput(); - -#ifdef QTOX_FILTER_AUDIO - filterer = other.filterer; - other.filterer = nullptr; -#endif } ToxCall::~ToxCall() { Audio& audio = Audio::getInstance(); - if (sendAudioTimer) - { - QObject::disconnect(sendAudioTimer, nullptr, nullptr, nullptr); - sendAudioTimer->stop(); - } - + QObject::disconnect(audioInConn); audio.unsubscribeInput(); audio.unsubscribeOutput(alSource); - -#ifdef QTOX_FILTER_AUDIO - if (filterer) - delete filterer; -#endif } const ToxCall& ToxCall::operator=(ToxCall&& other) noexcept { - sendAudioTimer = other.sendAudioTimer; - other.sendAudioTimer = nullptr; + audioInConn = other.audioInConn; + other.audioInConn = QMetaObject::Connection(); callId = other.callId; other.callId = numeric_limits::max(); inactive = other.inactive; @@ -91,11 +60,6 @@ const ToxCall& ToxCall::operator=(ToxCall&& other) noexcept Audio& audio = Audio::getInstance(); audio.subscribeInput(); - #ifdef QTOX_FILTER_AUDIO - filterer = other.filterer; - other.filterer = nullptr; - #endif - return *this; } @@ -132,14 +96,11 @@ ToxFriendCall::ToxFriendCall(uint32_t FriendNum, bool VideoEnabled, CoreAV& av) state{static_cast(0)}, av{&av}, timeoutTimer{nullptr} { - auto audioTimerCopy = sendAudioTimer; // this might change after a move, but not sendAudioTimer - QObject::connect(sendAudioTimer, &QTimer::timeout, [FriendNum,&av,audioTimerCopy]() + audioInConn = QObject::connect(&Audio::getInstance(), &Audio::frameAvailable, + [&av,FriendNum](const int16_t *pcm, size_t samples, uint8_t chans, uint32_t rate) { - // If sendCallAudio returns false, there was a serious error and we might as well stop the timer - if (av.sendCallAudio(FriendNum)) - audioTimerCopy->start(); + av.sendCallAudio(FriendNum, pcm, samples, chans, rate); }); - sendAudioTimer->start(); if (videoEnabled) { @@ -205,14 +166,11 @@ ToxGroupCall::ToxGroupCall(int GroupNum, CoreAV &av) static_assert(numeric_limits::max() >= numeric_limits::max(), "The callId must be able to represent any group number, change its type if needed"); - auto audioTimerCopy = sendAudioTimer; // this might change after a move, but not sendAudioTimer - QObject::connect(sendAudioTimer, &QTimer::timeout, [GroupNum,&av,audioTimerCopy]() + audioInConn = QObject::connect(&Audio::getInstance(), &Audio::frameAvailable, + [&av,GroupNum](const int16_t *pcm, size_t samples, uint8_t chans, uint32_t rate) { - // If sendGroupCallAudio returns false, there was a serious error and we might as well stop the timer - if (av.sendGroupCallAudio(GroupNum)) - audioTimerCopy->start(); + av.sendGroupCallAudio(GroupNum, pcm, samples, chans, rate); }); - sendAudioTimer->start(); } ToxGroupCall::ToxGroupCall(ToxGroupCall&& other) noexcept diff --git a/src/core/toxcall.h b/src/core/toxcall.h index b0b35cc91..cf559db88 100644 --- a/src/core/toxcall.h +++ b/src/core/toxcall.h @@ -3,6 +3,7 @@ #include #include +#include #include "src/core/indexedlist.h" @@ -28,18 +29,14 @@ public: const ToxCall& operator=(ToxCall&& other) noexcept; protected: - QTimer* sendAudioTimer; + QMetaObject::Connection audioInConn; public: - uint32_t callId; ///< Could be a friendNum or groupNum, must uniquely identify the call + uint32_t callId; ///< Could be a friendNum or groupNum, must uniquely identify the call. Do not modify! + quint32 alSource; bool inactive; ///< True while we're not participating. (stopped group call, ringing but hasn't started yet, ...) bool muteMic; bool muteVol; - quint32 alSource; - -#ifdef QTOX_FILTER_AUDIO - AudioFilterer* filterer; -#endif }; struct ToxFriendCall : public ToxCall From f57bf331d6d50c592af056c640b66674b8a6519c Mon Sep 17 00:00:00 2001 From: tux3 Date: Fri, 22 Jan 2016 00:07:31 +0100 Subject: [PATCH 167/210] Fix avform mic slider enabling --- src/widget/form/settings/avform.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widget/form/settings/avform.cpp b/src/widget/form/settings/avform.cpp index 82efacbb0..849eaa3f2 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -339,7 +339,7 @@ void AVForm::onInDevChanged(QString deviceDescriptor) Settings::getInstance().setInDev(deviceDescriptor); Audio& audio = Audio::getInstance(); audio.reinitInput(deviceDescriptor); - bodyUI->microphoneSlider->setEnabled(audio.isInputReady()); + bodyUI->microphoneSlider->setEnabled(bodyUI->inDevCombobox->currentIndex() != 0); bodyUI->microphoneSlider->setSliderPosition(audio.inputVolume() * 100.f); } From 642544819601bdd28e918b3b9ed41f9ab282c6da Mon Sep 17 00:00:00 2001 From: tux3 Date: Fri, 22 Jan 2016 00:10:54 +0100 Subject: [PATCH 168/210] Implement the playMono16Sound API sanely This API used to start *A NEW THREAD* for every sound played!! Now we simply have a dedicated source and buffer to play those sounds, we use a timer to cleanup the buffer 50ms after the sound is done playing (if a new sound hasn't started in the meantime) --- src/audio/audio.cpp | 111 +++++++++++++++++++------------------------- src/audio/audio.h | 5 +- 2 files changed, 51 insertions(+), 65 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 86007bef1..22ba8be8c 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -51,52 +51,6 @@ } while (0) #endif -/** -@class AudioPlayer - -@brief Non-blocking audio player. - -The audio data is played from start to finish (no streaming). -*/ -class AudioPlayer : public QThread -{ -public: - AudioPlayer(ALuint source, const QByteArray& data) - : mSource(source) - { - alGenBuffers(1, &mBuffer); - alBufferData(mBuffer, AL_FORMAT_MONO16, data.constData(), data.size(), 44100); - alSourcei(mSource, AL_BUFFER, mBuffer); - - connect(this, &AudioPlayer::finished, this, &AudioPlayer::deleteLater); - } - -private: - void run() override final - { - alSourceRewind(mSource); - alSourcePlay(mSource); - - QMutexLocker locker(&playLock); - ALint state = AL_PLAYING; - while (state == AL_PLAYING) { - alGetSourcei(mSource, AL_SOURCE_STATE, &state); - waitPlaying.wait(&playLock, 2000); - } - - alSourceStop(mSource); - alDeleteBuffers(1, &mBuffer); - } - -public: - QMutex playLock; - QWaitCondition waitPlaying; - -private: - ALuint mBuffer; - ALuint mSource; -}; - /** Returns the singleton instance. */ @@ -114,6 +68,7 @@ Audio::Audio() , alOutDev(nullptr) , alOutContext(nullptr) , alMainSource(0) + , alMainBuffer(0) , outputInitialized(false) { audioThread->setObjectName("qTox Audio"); @@ -129,6 +84,8 @@ Audio::Audio() captureTimer.setInterval(AUDIO_FRAME_DURATION/2); captureTimer.setSingleShot(false); captureTimer.start(); + connect(&playMono16Timer, &QTimer::timeout, this, &Audio::playMono16SoundCleanup); + playMono16Timer.setSingleShot(true); if (!audioThread->isRunning()) audioThread->start(); @@ -360,6 +317,16 @@ bool Audio::initOutput(QString outDevDescr) return true; } +/** +Play a 44100Hz mono 16bit PCM sound from a file +*/ +void Audio::playMono16Sound(const QString& path) +{ + QFile sndFile(path); + sndFile.open(QIODevice::ReadOnly); + playMono16Sound(QByteArray(sndFile.readAll())); +} + /** Play a 44100Hz mono 16bit PCM sound */ @@ -370,27 +337,23 @@ void Audio::playMono16Sound(const QByteArray& data) if (!autoInitOutput()) return; - AudioPlayer *player = new AudioPlayer(alMainSource, data); - connect(player, &AudioPlayer::finished, [=]() { - QMutexLocker locker(&audioLock); + if (!alMainBuffer) + alGenBuffers(1, &alMainBuffer); - if (outSources.isEmpty()) - cleanupOutput(); - else - qDebug("Audio output not closed -> there are pending subscriptions."); - }); + ALint state; + alGetSourcei(alMainSource, AL_SOURCE_STATE, &state); + if (state == AL_PLAYING) + { + alSourceStop(alMainSource); + alSourcei(alMainSource, AL_BUFFER, AL_NONE); + } - player->start(); -} + alBufferData(alMainBuffer, AL_FORMAT_MONO16, data.constData(), data.size(), 44100); + alSourcei(alMainSource, AL_BUFFER, static_cast(alMainBuffer)); + alSourcePlay(alMainSource); -/** -Play a 44100Hz mono 16bit PCM sound from a file -*/ -void Audio::playMono16Sound(const QString& path) -{ - QFile sndFile(path); - sndFile.open(QIODevice::ReadOnly); - playMono16Sound(QByteArray(sndFile.readAll())); + int durationMs = data.size() * 1000 / 2 / 44100; + playMono16Timer.start(durationMs + 50); } /** @@ -479,6 +442,12 @@ void Audio::cleanupOutput() alSourceStop(alMainSource); alDeleteSources(1, &alMainSource); + if (alMainBuffer) + { + alDeleteBuffers(1, &alMainBuffer); + alMainBuffer = 0; + } + if (!alcMakeContextCurrent(nullptr)) qWarning("Failed to clear audio context."); @@ -493,6 +462,20 @@ void Audio::cleanupOutput() } } +void Audio::playMono16SoundCleanup() +{ + QMutexLocker locker(&audioLock); + + ALint state; + alGetSourcei(alMainSource, AL_SOURCE_STATE, &state); + if (state == AL_STOPPED) + { + alSourcei(alMainSource, AL_BUFFER, AL_NONE); + alDeleteBuffers(1, &alMainBuffer); + alMainBuffer = 0; + } +} + void Audio::doCapture() { QMutexLocker lock(&audioLock); diff --git a/src/audio/audio.h b/src/audio/audio.h index 14a85ddc7..273253874 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -105,6 +105,8 @@ private: bool initOutput(QString outDevDescr); void cleanupInput(); void cleanupOutput(); + /// Called after a mono16 sound stopped playing + void playMono16SoundCleanup(); /// Called on the captureTimer events to capture audio void doCapture(); #if defined(QTOX_FILTER_AUDIO) && defined(ALC_LOOPBACK_CAPTURE_SAMPLES) @@ -118,11 +120,12 @@ private: ALCdevice* alInDev; ALfloat inGain; quint32 inSubscriptions; - QTimer captureTimer; + QTimer captureTimer, playMono16Timer; ALCdevice* alOutDev; ALCcontext* alOutContext; ALuint alMainSource; + ALuint alMainBuffer; bool outputInitialized; QList outSources; From 6cad8d8fe9aafdb5d0d950a4970ecd8876057fbe Mon Sep 17 00:00:00 2001 From: tux3 Date: Fri, 22 Jan 2016 00:44:23 +0100 Subject: [PATCH 169/210] Remove redundant check starting audio thread Thanks to @antis81 for spotting it --- src/audio/audio.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 22ba8be8c..3f7ef38c8 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -87,10 +87,7 @@ Audio::Audio() connect(&playMono16Timer, &QTimer::timeout, this, &Audio::playMono16SoundCleanup); playMono16Timer.setSingleShot(true); - if (!audioThread->isRunning()) - audioThread->start(); - else - qWarning("Audio thread already started -> ignored."); + audioThread->start(); } Audio::~Audio() From a2fbc277fcaaf9dc5bc7caf7151e9197e3cb57c3 Mon Sep 17 00:00:00 2001 From: tux3 Date: Fri, 22 Jan 2016 00:58:50 +0100 Subject: [PATCH 170/210] Replace audio check macros by functions --- src/audio/audio.cpp | 56 ++++++++++++++++++++++----------------------- src/audio/audio.h | 3 +++ 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 3f7ef38c8..d4f1bc318 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -35,22 +35,6 @@ #include "audiofilterer.h" #endif -#ifndef CHECK_AL_ERROR -#define CHECK_AL_ERROR \ - do { \ - const ALenum al_err = alGetError(); \ - if (al_err) { qWarning("OpenAL error: %d", al_err); } \ - } while (0) -#endif - -#ifndef CHECK_ALC_ERROR -#define CHECK_ALC_ERROR(device) \ - do { \ - const ALCenum alc_err = alcGetError(device); \ - if (alc_err) { qWarning("OpenAL error: %d", alc_err); } \ - } while (0) -#endif - /** Returns the singleton instance. */ @@ -99,6 +83,20 @@ Audio::~Audio() filterer.closeFilter(); } +void Audio::checkAlError() +{ + const ALenum al_err = alGetError(); + if (al_err != AL_NO_ERROR) + qWarning("OpenAL error: %d", al_err); +} + +void Audio::checkAlcError(ALCdevice *device) +{ + const ALCenum alc_err = alcGetError(device); + if (alc_err) + qWarning("OpenAL error: %d", alc_err); +} + /** Returns the current output volume (between 0 and 1) */ @@ -110,7 +108,7 @@ ALfloat Audio::outputVolume() if (alOutDev) { alGetListenerf(AL_GAIN, &volume); - CHECK_AL_ERROR; + checkAlError(); } return volume; @@ -128,7 +126,7 @@ void Audio::setOutputVolume(ALfloat volume) volume = std::max(0.f, std::min(volume, 1.f)); alListenerf(AL_GAIN, volume); - CHECK_AL_ERROR; + checkAlError(); } ALfloat Audio::inputVolume() @@ -287,22 +285,22 @@ bool Audio::initOutput(QString outDevDescr) qDebug() << "Opened audio output" << outDevDescr; alOutContext = alcCreateContext(alOutDev, nullptr); - CHECK_ALC_ERROR(alOutDev); + checkAlcError(alOutDev); if (!alcMakeContextCurrent(alOutContext)) { qWarning() << "Cannot create output audio context"; return false; } - alGenSources(1, &alMainSource); CHECK_AL_ERROR; - alSourcef(alMainSource, AL_GAIN, 1.f); CHECK_AL_ERROR; - alSourcef(alMainSource, AL_PITCH, 1.f); CHECK_AL_ERROR; - alSource3f(alMainSource, AL_VELOCITY, 0.f, 0.f, 0.f); CHECK_AL_ERROR; - alSource3f(alMainSource, AL_POSITION, 0.f, 0.f, 0.f); CHECK_AL_ERROR; + alGenSources(1, &alMainSource); checkAlError(); + alSourcef(alMainSource, AL_GAIN, 1.f); checkAlError(); + alSourcef(alMainSource, AL_PITCH, 1.f); checkAlError(); + alSource3f(alMainSource, AL_VELOCITY, 0.f, 0.f, 0.f); checkAlError(); + alSource3f(alMainSource, AL_POSITION, 0.f, 0.f, 0.f); checkAlError(); // init master volume alListenerf(AL_GAIN, Settings::getInstance().getOutVolume() * 0.01f); - CHECK_AL_ERROR; + checkAlError(); Core* core = Core::getInstance(); if (core) { @@ -556,10 +554,10 @@ void Audio::subscribeOutput(ALuint& sid) outSources << sid; // initialize source - alSourcef(sid, AL_GAIN, 1.f); CHECK_AL_ERROR; - alSourcef(sid, AL_PITCH, 1.f); CHECK_AL_ERROR; - alSource3f(sid, AL_VELOCITY, 0.f, 0.f, 0.f); CHECK_AL_ERROR; - alSource3f(sid, AL_POSITION, 0.f, 0.f, 0.f); CHECK_AL_ERROR; + alSourcef(sid, AL_GAIN, 1.f); checkAlError(); + alSourcef(sid, AL_PITCH, 1.f); checkAlError(); + alSource3f(sid, AL_VELOCITY, 0.f, 0.f, 0.f); checkAlError(); + alSource3f(sid, AL_POSITION, 0.f, 0.f, 0.f); checkAlError(); qDebug() << "Audio source" << sid << "created. Sources active:" << outSources.size(); diff --git a/src/audio/audio.h b/src/audio/audio.h index 273253874..8499358f8 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -99,6 +99,9 @@ private: Audio(); ~Audio(); + static void checkAlError() noexcept; + static void checkAlcError(ALCdevice *device) noexcept; + bool autoInitInput(); bool autoInitOutput(); bool initInput(QString inDevDescr); From 87c49070541c45339ac0ca27c99694815f3c96bd Mon Sep 17 00:00:00 2001 From: tux3 Date: Sat, 23 Jan 2016 16:22:32 +0100 Subject: [PATCH 171/210] Remove redundant source init code --- src/audio/audio.cpp | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index d4f1bc318..3e8f9cdc1 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -292,11 +292,8 @@ bool Audio::initOutput(QString outDevDescr) return false; } - alGenSources(1, &alMainSource); checkAlError(); - alSourcef(alMainSource, AL_GAIN, 1.f); checkAlError(); - alSourcef(alMainSource, AL_PITCH, 1.f); checkAlError(); - alSource3f(alMainSource, AL_VELOCITY, 0.f, 0.f, 0.f); checkAlError(); - alSource3f(alMainSource, AL_POSITION, 0.f, 0.f, 0.f); checkAlError(); + alGenSources(1, &alMainSource); + checkAlError(); // init master volume alListenerf(AL_GAIN, Settings::getInstance().getOutVolume() * 0.01f); @@ -553,12 +550,6 @@ void Audio::subscribeOutput(ALuint& sid) assert(sid); outSources << sid; - // initialize source - alSourcef(sid, AL_GAIN, 1.f); checkAlError(); - alSourcef(sid, AL_PITCH, 1.f); checkAlError(); - alSource3f(sid, AL_VELOCITY, 0.f, 0.f, 0.f); checkAlError(); - alSource3f(sid, AL_POSITION, 0.f, 0.f, 0.f); checkAlError(); - qDebug() << "Audio source" << sid << "created. Sources active:" << outSources.size(); } From 26e7bde991a5dba14d9ab5e3215187f98372f5d1 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sat, 23 Jan 2016 12:32:28 +0100 Subject: [PATCH 172/210] initialize OpenAL error stack --- src/audio/audio.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 3e8f9cdc1..40f1aca75 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -55,6 +55,10 @@ Audio::Audio() , alMainBuffer(0) , outputInitialized(false) { + // initialize OpenAL error stack + alGetError(); + alcGetError(nullptr); + audioThread->setObjectName("qTox Audio"); QObject::connect(audioThread, &QThread::finished, audioThread, &QThread::deleteLater); From fdd956779d414d3ff2f3fb667ffae51a17f30321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D9=85=D8=AD=D9=85=D9=88=D8=AF=20=D8=A7=D9=84=D8=B9=D9=85?= =?UTF-8?q?=D9=88=D8=B4?= Date: Sun, 24 Jan 2016 14:29:52 +0200 Subject: [PATCH 173/210] Adding arabic language file to the languages list --- res.qrc | 1 + src/widget/form/settings/generalform.cpp | 2 + translations/.ts | 2792 ++++++++++++++++++++++ translations/i18n.pri | 1 + 4 files changed, 2796 insertions(+) create mode 100644 translations/.ts diff --git a/res.qrc b/res.qrc index d5b940cb5..51f2706bb 100644 --- a/res.qrc +++ b/res.qrc @@ -62,6 +62,7 @@ translations/sv.qm translations/tr.qm translations/uk.qm + translations/ar.qm translations/zh.qm ui/fileTransferWidget/fileDone.svg ui/callButton/callButton.css diff --git a/src/widget/form/settings/generalform.cpp b/src/widget/form/settings/generalform.cpp index 8c88843ce..3def0ad9e 100644 --- a/src/widget/form/settings/generalform.cpp +++ b/src/widget/form/settings/generalform.cpp @@ -59,6 +59,7 @@ static QStringList locales = {"bg", "sv", "tr", "uk", + "ar", "zh"}; static QStringList langs = {"Български", "Čeština", @@ -81,6 +82,7 @@ static QStringList langs = {"Български", "Svenska", "Türkçe", "Українська", + "Arabic", "简体中文"}; static QStringList timeFormats = {"hh:mm AP", "hh:mm", "hh:mm:ss AP", "hh:mm:ss"}; diff --git a/translations/.ts b/translations/.ts new file mode 100644 index 000000000..8d35ad246 --- /dev/null +++ b/translations/.ts @@ -0,0 +1,2792 @@ + + + + + AVForm + + + %1x%2 + %1x%2 + + + + + Default resolution + الأبعاد الطبيعية + + + + at %1 FPS + + + + + + None + لا شيئ + + + + Audio/Video + صوت/فيديو + + + + AVSettings + + + Audio Settings + إعدادات الصوت + + + + + 0 + 0 + + + + Filter sound from your microphone, so that people hearing you would get better sound. + فلترة صوت المايكروفون, ستجعل الناس تسمع الصوت بشكل أفضل. + + + + Filter audio + فلترة الصوت + + + + Use slider to set volume of your speakers. + استخدام شريط التمرير لضبط مستوى الصوت من السماعة. + + + + Microphone + المايكروفون + + + + + 100 + + + + + Capture device + جهاز التسجيل + + + + Use slider to set volume of your microphone. + استخدام شريط التمرير لضبط مستوى الصوت من المايكروفون. + + + + Playback + السماعة + + + + Playback device + جهاز مكبر الصوت + + + + Video Settings + اعدادات الفيديو + + + + Video device + جهاز الفيديو + + + + + Set resolution of your camera. +The higher values, the better video quality your friends may get. +Note though that with better video quality there is needed better internet connection. +Sometimes your connection may not be good enough to handle higher video quality, +which may lead to problems with video calls. + ضع الدقة المناسبة للكاميرا. + + + + Resolution + الدقة + + + + Rescan devices + إعادة الكشف عن الأجهزة + + + + AboutForm + + + Qt version: + اصدار Qt: + + + + Restart qTox to install version %1 + اعادة التشغيل لتثبيت النسخة %1 + + + + qTox is downloading update %1 + %1 is the version of the update + جاري تحميل التحديث %1 + + + + About + نبذة + + + + AboutSettings + + + Version + الاصدار + + + + toxcore version: $TOXCOREVERSION + + + + + Qt version: + + + + + Commit hash: <a href="https://github.com/tux3/qTox/commit/$GIT_VERSION">$GIT_VERSION</a> + + + + + You are using qTox version $GIT_DESCRIBE. + + + + + Downloading update: %p% + + + + + License + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; color:#000000;">Copyright © 2014-2015 by The qTox Project</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu';">qTox is a Qt-based graphical interface for Tox.</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';">qTox is libre software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';">qTox is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. </span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu';">You should have received a copy of the GNU General Public License along with this program. If not, see </span><a href="https://www.gnu.org/copyleft/gpl.html"><span style=" font-family:'Ubuntu'; text-decoration: underline; color:#007af4;">https://www.gnu.org/copyleft/gpl.html</span></a><span style=" font-family:'Ubuntu';">.</span></p></body></html> + + + + + Authors + + + + + <html><head/><body><p>Original author: <a href="https://github.com/tux3"><span style=" text-decoration: underline; color:#0000ff;">tux3</span></a></p><p>See a full list of <a href="https://github.com/tux3/qTox/graphs/contributors"><span style=" text-decoration: underline; color:#0000ff;">contributors</span></a> at Github</p></body></html> + + + + + Known Issues + + + + + <html><head/><body><p>A list of all known issues may be found at our <a href="https://github.com/tux3/qTox/issues"><span style=" text-decoration: underline; color:#0000ff;">bug-tracker</span></a> at Github. If you discover a bug or security vulnerability within qTox, please report it according to the guidelines in our <a href="https://github.com/tux3/qTox/wiki/Writing-Useful-Bug-Reports"><span style=" text-decoration: underline; color:#0000ff;">Writing Useful Bug Reports</span></a> wiki article.</p></body></html> + + + + + AboutUser + + + Dialog + + + + + username + اسم المستخدم + + + + status message + الحالة + + + + Public key: + المعرف: + + + + Used aliases: + الاسم: + + + + HISTORY OF ALIASES + + + + + Default directory to save files: + مسار حفظ الملفات: + + + + + Auto accept for this contact is disabled + القبول التلقائي للملفات من هذا الشخص معطل + + + + Auto accept files + القبول التلقائي للملفات + + + + Remove history (operation can not be undone!) + حذف السجل (العملية لا يمكن التراجع عنها) + + + + Notes + ملاحظات + + + + You can save comment about this contact here. + يمكنك حفظ بعض الملاحظات عن هذا الشخص هنا. + + + + + Choose an auto accept directory + popup title + اختيار مجلد الحفظ التلقائي + + + + History removed + تم مسح السجل + + + + Chat history with %1 removed! + سجل المحادثة مع %1 تم حذفها! + + + + AddFriendForm + + + + Couldn't add friend + لا يمكن اضافة صديق + + + + You can't add yourself as a friend! + When trying to add your own Tox ID as friend + لا تستطيع اضافة نفسك كصديق! + + + + qTox needs to use the Tox DNS, but can't do it through a proxy. +Ignore the proxy and connect to the Internet directly? + + + + + This Tox ID does not exist + DNS error + هذا المعرف غير مستخدم + + + + Tox ID + Tox ID of the person you're sending a friend request to + المعرف (ID) + + + + either 76 hexadecimal characters or name@example.com + Tox ID format description + إما 76 حرف ست عشري أو name@example.com + + + + Invalid Tox ID format + صيغة المعرف خاطئة + + + + Add Friends + إضافة صديق + + + + Message + The message you send in friend requests + رسالة طلب الاضافة + + + + Send friend request + ارسال طلب اضافة + + + + %1 here! Tox me maybe? + Default message in friend requests if the field is left blank. Write something appropriate! + %1 هنا! + + + + AdvancedForm + + + Advanced + متقدم + + + + AdvancedSettings + + + Save settings to the working directory instead of the usual conf dir + describes makeToxPortable checkbox + حفظ الاعدادات الى مسار العمل + + + + Make Tox portable + اجعل توكس محمولا + + + + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">IMPORTANT NOTE</span></p><p><span style=" color:#ff0000;">Unless you </span><span style=" font-weight:600; color:#ff0000;">really</span><span style=" color:#ff0000;"> know what you are doing, please do </span><span style=" font-weight:600; color:#ff0000;">not</span><span style=" color:#ff0000;"> change anything here. Changes made here may lead to problems with qTox, and even to loss of your data, e.g. history.</span></p></body></html> + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">ملاحظة مهمة</span></p><p><span style=" color:#ff0000;">اذا كنت</span><span style=" font-weight:600; color:#ff0000;"> فعلا </span><span style=" color:#ff0000;"> لا تعرف ماذا تفعل</span><span style=" font-weight:600; color:#ff0000;"> لا </span><span style=" color:#ff0000;"> تغير شيئ هنا. التغيرات التي تحدث هنا قد تؤدي الى مشاكل في البرنامج وفقد الملفات , مثل السجل</span></p></body></html> + + + + Reset to default settings + إعادة الاعدادات الافتراضية + + + + Android + + + Form + + + + + qTox + qTox + + + + Someone + + + + + Someone else + + + + + Groupbot + + + + + That guy who I don't remember adding + + + + + NASA manager + + + + + Lorem + + + + + Ipsum + + + + + Dolor + + + + + ChatForm + + + Send a file + ارسال ملف + + + + + Unable to open + غير قادر على الفتح + + + + + qTox wasn't able to open %1 + qTox غير قادر على فتح %1 + + + + + Bad idea + فكرة سيئة + + + + + You're trying to send a special (sequential) file, that's not going to work! + انت تحاول ارسال ملف خاص , لن يعمل! + + + + Accept video call + قبول مكالمة فيديو + + + + Accept audio call + قبول مكالمة صوتية + + + + %1 calling + %1 يتصل + + + + End video call + انهاء مكالمة فيديو + + + + End audio call + انهاء مكالمة صوتية + + + + + + Mute microphone + كتم المايكروفون + + + + + + Mute call + كتم المكالمة + + + + Cancel video call + الغاء مكالمة الفيديو + + + + Cancel audio call + الغاء مكالمة الصوت + + + + Calling %1 + يتصل %1 + + + + Start audio call + بدء مكالمة صوتية + + + + Start video call + بدء مكالمة فيديو + + + + + Unmute microphone + الغاء كتم المايكروفون + + + + + Unmute call + الغاء كتم المكالمة + + + + Failed to send file "%1" + فشل ارسال الملف "%1" + + + + Failed to open temporary file + Temporary file for screenshot + فشل فتح الملف المؤقت + + + + qTox wasn't able to save the screenshot + qTox غير قادر على حفظ لقطة الشاشة + + + + Call with %1 ended. %2 + المكالمة مع %1 انتهت. %2 + + + + Call duration: + مدة المكالمة: + + + + Load chat history... + تحميل سجل الرسائل... + + + + ChatLog + + + pending + قيد الانتظار + + + + Copy + المحادثة + + + + Select all + تحديد الكل + + + + ChatTextEdit + + + Type your message here... + اكتب رسالتك هنا... + + + + CircleWidget + + + Rename circle + Menu for renaming a circle + اعادة تسمية القائمة + + + + Remove circle + Menu for removing a circle + ازالة القائمة + + + + Open all in new window + فتح الجميع في نوافذ مستقلة + + + + Core + + + Toxing on qTox + + + + + You need to write a message with your request + تحتاج كتابة رسالة مع الطلب + + + + Your message is too long! + رسالتك طويلة جدا! + + + + Friend is already added + تمت الاضافة فعلاً + + + + /me offers friendship. + + + + + /me offers friendship, "%1" + + + + + Encrypted chat history + تشفير سجل المحادثة + + + + No encrypted chat history file found, or it was corrupted. +History will be disabled! + لا يوجد سجل محادثة مشفر, او انه قد تلف. سيتم تعطيل السجل! + + + + Please enter the password for the chat history for the profile "%1". + used in load() when no hist pw set + يرجى ادخال كلمة المرور لسجل المحادثة لهذا الملف الشخصي "%1". + + + + The previous password is incorrect; please try again: + used on retries in load() + كلمة المرور السابقة خاطئة , يرجى المحاولة مرة اخرى: + + + + +Disabling chat history now will leave the encrypted history intact (but not usable); if you later remember the password, you may re-enable encryption from the Privacy tab with the correct password to use the history. + part of history password dialog + + + + + The chat history password failed. Please try another? + used only when pw set before load() doesn't work + كلمة مرور السجل خاطئة . يرجى المحاولة مرة اخرى؟ + + + + Disable chat history + تعطيل سجل المحادثات + + + + FileTransferWidget + + + Form + + + + + 10Mb + + + + + 0kb/s + + + + + ETA:10:10 + + + + + Filename + + + + + [preview] + + + + + Waiting to send... + file transfer widget + انتظار للارسال... + + + + Accept to receive this file + file transfer widget + قبول تسلم هذا الملف + + + + Location not writable + Title of permissions popup + المسار غير قابل للكتابة + + + + You do not have permission to write that location. Choose another, or cancel the save dialog. + text of permissions popup + لا يوجد لديك صلاحيات للكتابة في هذا المسار. اختر مسار اخر, او الغِ نافذة الحفظ. + + + + Paused + file transfer widget + موقَف + + + + Resuming... + file transfer widget + استكمال... + + + + Open file + فتح الملف + + + + Open file directory + فتح مسار الملف + + + + + Pause transfer + ايقاف النقل + + + + + + Cancel transfer + الغاء النقل + + + + Resume transfer + اكمال النقل + + + + Accept transfer + قبول النقل + + + + Save a file + Title of the file saving dialog + حفظ الملف + + + + FilesForm + + + Transferred Files + "Headline" of the window + الملفات المنقولة + + + + Downloads + التحميلات + + + + Uploads + المرسل(رفع) + + + + FriendListWidget + + + Today + Category for sorting friends by activity + اليوم + + + + Yesterday + Category for sorting friends by activity + امس + + + + Last 7 days + Category for sorting friends by activity + اخر سبع أيام + + + + This month + Category for sorting friends by activity + هذا الشهر + + + + Older than 6 Months + Category for sorting friends by activity + اكثر من 6 شهور + + + + Unknown + Category for sorting friends by activity + غير معروف + + + + FriendRequestDialog + + + Friend request + Title of the window to aceept/deny a friend request + طلب صداقة + + + + Someone wants to make friends with you + هناك شخص يريد ان يجعلك صديقاً + + + + User ID: + معرف الحساب: + + + + Friend request message: + رسالة طلب الصداقة: + + + + Accept + Accept a friend request + قبول + + + + Reject + Reject a friend request + رفض + + + + FriendWidget + + + Open chat in new window + فتح المحادثة في مجموعة جديدة + + + + Remove chat from this window + ازالة المحادثة من هذه النافذة + + + + Invite to group + Menu to invite a friend to a groupchat + دعوة لمجموعة + + + + Move to circle... + Menu to move a friend into a different circle + نقل الى قائمة... + + + + To new circle + الى قائمة جديدة + + + + Remove from circle '%1' + ازالة من القائمة '%1' + + + + Move to circle "%1" + نقل الى القائمة "%1" + + + + Set alias... + تعيين الاسم... + + + + Auto accept files from this friend + context menu entry + قبول الملفات تلقائياً من هذا الصديق + + + + Remove friend + Menu to remove the friend from our friendlist + ازالة صديق + + + + Show details + اظهار التفاصيل + + + + Choose an auto accept directory + popup title + اختر مجلد الحفظ التلقائي + + + + New message + رسالة جديدة + + + + Online + متصل + + + + Away + في الخارج + + + + Busy + مشغول + + + + Offline + غير متصل + + + + GUI + + + Enter your password + ادخل كلمة المرور + + + + Decrypt + فك تشفير + + + + You must enter a non-empty password: + يجب ان لا تدخل كلمة مرور فارغة: + + + + GeneralForm + + + + + None + + + + + Choose an auto accept directory + popup title + اختيار مسار الحفظ التلقائي + + + + Call active + popup title + المكالمة نشطة + + + + You can't disconnect while a call is active! + popup text + لا تستطيع قطع الاتصال اثناء المكالمة! + + + + General + عام + + + + GeneralSettings + + + General Settings + الإعدادات العامة + + + + + The translation may not load until qTox restarts. + قد لا يتم تحميل الترجمة حتى تعيد تشغيل qTox . + + + + Language: + اللغة: + + + + Start qTox on operating system startup (current profile). + تشغيل البرنامج بشكل تلقائي عند تشغيل النظام(بالحساب الحالي). + + + + Autostart + تشغيل تلقائي + + + + Check for updates on startup + التحقق من وجود تحديثات عن بدء تشغيل النظام + + + + Enable light tray icon. + toolTip for light icon setting + تفعيل الأيقونة المضيئة. + + + + Light icon + تغيير شكل الايقونه + + + + Show system tray icon + إظهار الايقونة المصغرة + + + + qTox will start minimized in tray. + toolTip for Start in tray setting + تشغيل البرنامج في أيقونة الشاشة. + + + + Start in tray + التشغيل في الأيقونة + + + + After pressing minimize (_) qTox will minimize itself to tray, +instead of system taskbar. + toolTip for minimize to tray setting + عند الضغط على رمز تصغير الشاشه (_) سيذهب البرنامج الى أيقونه الشاشه بدلا من شريط المهام. + + + + Minimize to tray + التصغير للأيقونة + + + + After pressing close (X) qTox will minimize to tray, +instead of closing itself. + toolTip for close to tray setting + عند الضغط على رمز إغلاق الشاشه (X) سيذهب البرنامج الى أيقونه الشاشه بدلا من أن يغلق تلقائيا. + + + + Close to tray + الإغلاق للأيقونة + + + + Your status is changed to Away after set period of inactivity. + يتم تغيير حالتك إلى بالخارج بعد فترة من الخمول. + + + + Auto away after (0 to disable): + تغيير الحالة الى في الخارج بعد ( 0 للتعطيل): + + + + Set to 0 to disable + 0 للتعطيل + + + + Set where files will be saved. + إختر اين يجب أن تحفظ الملفات. + + + + Default directory to save files: + مسار حفظ الملفات: + + + + You can set this on a per-friend basis by right clicking them. + autoaccept cb tooltip + يمكنك تفعيلها عن طريق النقر بالزر الايمن على جهة الإتصال. + + + + Autoaccept files + قبول تلقائي للملفات + + + + Chat + المحادثة + + + + On new message: + عند وصول رسالة: + + + + Play a sound when you recieve message. + toolTip for Notify sound setting + تشغيل الصوت عند التوصل برسالة جديدة. + + + + Play sound + تشغيل صوت + + + + Open qTox's window when you receive a new message and no window is open yet. + tooltip for Show window setting + فتح نافذة qTox عند التوصل برسالة جديدة . + + + + Open window + افتح النافذة + + + + Focus qTox when you receive message. + toolTip for Focus window setting + التركيز على نافذة qTox عند التوصل برسالة. + + + + Focus window + التركيز على النافذة + + + + Show contacts' status changes + إظهار تغيرات حالات جهات الإتصال + + + + Always notify about new messages in groupchats. + toolTip for Group chat always notify + الاشعار عن الرسائل الجديدة في المجموعات. + + + + Group chats always notify + اشعارات المجموعات + + + + If checked, groupchats will be placed at the top of the friends list, otherwise, they'll be placed below online friends. + toolTip for groupchat positioning + إذا فعلتها, المجموعات ستصبح فوق قائمة الأصدقاء, خلاف ذلك, ستكون المجموعات تحت الأصدقاء المتصلين. + + + + Place groupchats at top of friend list + ضع المجموعات اعلى من قائمه الاصدقاء + + + + Messages you are trying to send to your friends when they are not online +will be sent to them when they appear online to you. + toolTip for Faux offline messaging setting + الرسائل التي ترسلها الى الاصدقاء غير متصلين سترسل عند دخولهم. + + + + Faux offline messaging + ارسال رساله الى صديق غير متصل + + + + Your contact list will be shown in compact mode. + toolTip for compact layout setting + سيتم عرض جهات الاتصال بوضع مضغوط. + + + + Compact contact list + اظهار القائمه بالوضع المضغوط + + + + Multiple windows mode + خاصيه النوافذ المتعدد + + + + Open each chat in an individual window + افتح كل محادثه في نافذه مستقله + + + + Theme + المظهر + + + + Use emoticons + إستخدام الإبتسامات + + + + Smiley Pack: + Text on smiley pack label + حزمة الإبتسامات: + + + + Emoticon size: + حجم الإبتسامات: + + + + px + بكسل + + + + Style: + السِمة: + + + + Theme color: + لون السِمة: + + + + Timestamp format: + صيغة الوقت: + + + + Date format: + صيغة التاريخ: + + + + Connection Settings + إعدادات الإتصال + + + + Enable IPv6 (recommended) + Text on a checkbox to enable IPv6 + تفعيل IPv6 (موصى به ) + + + + Disabling this allows, e.g., toxing over Tor. It adds load to the Tox network however, so uncheck only when necessary. + force tcp checkbox tooltip + + + + + Enable UDP (recommended) + Text on checkbox to disable UDP + تفعيل UDP (موصى ب ه) + + + + Proxy type: + نوع الوكيل(بروكسي): + + + + Address: + Text on proxy addr label + العنوان: + + + + Port: + Text on proxy port label + المنفذ: + + + + None + لا شيئ + + + + SOCKS5 + SOCKS5 + + + + HTTP + HTTP + + + + Reconnect + reconnect button + إعادة الإتصال + + + + GenericChatForm + + + + Save chat log + حفظ سجل المحادثة + + + + Not sent + لم ترسل + + + + Cleared + تم التنظيف + + + + Start audio call + بدء مكالمة صوتية + + + + Accept audio call + قبول مكالمة صوتية + + + + End audio call + إنهاء مكالمة صوتية + + + + Start video call + بدء مكالمة فيديو + + + + Accept video call + قبول مكالمة فيديو + + + + End video call + إنهاء مكالمة فيديو + + + + Send message + إرسال رسالة + + + + Smileys + الإبتسامات + + + + Send file(s) + ارسال ملف + + + + Send a screenshot + ارسال لقطة شاشة + + + + Clear displayed messages + تنظيف الرسائل المعروضة(حذفها) + + + + GenericNetCamView + + + Tox video + فيديو Tox + + + + Show Messages + اضهار الرسائل + + + + Hide Messages + إخفاء الرسائل + + + + GroupChatForm + + + + 1 user in chat + Number of users in chat + 1 مستخدم في المحادثة + + + + + %1 users in chat + Number of users in chat + %1 مستخدم في المحادثة + + + + + Start audio call + بدء المكالمة الصوتية + + + + + Mute microphone + كتم المايكروفون + + + + Unmute microphone + ازالة كتم المايكروفون + + + + + Mute call + كتم المكالمة + + + + Unmute call + ازالة كتم المكالمة + + + + End audio call + انهاء المكالمة الصوتية + + + + GroupWidget + + + Open chat in new window + فتح المحادثة في نافذة مستقلة + + + + Remove chat from this window + ازالة المحادثة من هذه النافذة + + + + Set title... + ضع عنواناً... + + + + Quit group + Menu to quit a groupchat + الخروج من المجموعة + + + + + 1 user in chat + 1 مستخدم في المحادثة + + + + + %1 users in chat + %1 في المحادثة + + + + IdentitySettings + + + Public Information + معلومات عامة + + + + Name: + الإسم: + + + + Status: + الحالة: + + + + Tox ID + (ID)معرف Tox + + + + This bunch of characters tells other Tox clients how to contact you. +Share it with your friends to communicate. + Tox ID tooltip + هذا معرفك الخاص , شاركه مع اصدقائك في Tox . + + + + Your Tox ID (click to copy) + المعرف الخاص بك (اضغط هنا للنسخ) + + + + This QR code contains your Tox ID. You may share this with your friends as well. + رمز QR هذا يتعلق بمعرفك . تستطيع مشاركته مع اصدقائك. + + + + Save image + حفظ الصورة + + + + Copy image + نسخ الصورة + + + + Profile + الملف الشخصي + + + + <p><a href="file:///Dir_Path"><span style=" text-decoration: NONE; color:#000000;">Current profile location: Dir_Path</span></a></p> + <p><a href="file:///Dir_Path"><span style=" text-decoration: NONE; color:#000000;">مسار الملف الشخصي: Dir_Path</span></a></p> + + + + Rename profile. + tooltip for renaming profile button + اعادة تسمية الحساب. + + + + Rename + rename profile button + اعادة تسمية + + + + Delete profile. + delete profile button tooltip + حذف الحساب. + + + + Delete + delete profile button + حذف + + + + Allows you to export your Tox profile to a file. +Profile does not contain your history. + tooltip for profile exporting button + يسمح لك بتصدير الملف الشخصي. +الملف الشخصي لا يحتوي السجل. + + + + Export + export profile button + تصدير + + + + Go back to the login screen + tooltip for logout button + الرجوع لنافذة تسجيل الدخول + + + + Logout + import profile button + تسجيل خروج + + + + Remove password + ازالة كلمة المرور + + + + Change password + تغيير كلمة المرور + + + + LoadHistoryDialog + + + Load History Dialog + نافذة عرض التاريخ + + + + Load history from: + عرض التاريخ من: + + + + LoginScreen + + + + Username: + اسم المستخدم: + + + + + Password: + كلمة المرور: + + + + Confirm: + تأكيدكلمة المرور: + + + + Password strength: %p% + قوة كلمة المرور: %p% + + + + Create Profile + إنشاء حساب + + + + If the profile does not have a password, qTox can skip the login screen + إذا كنت لا تملك كلمة المرور, qTox يستطيع تخطي شاشة الدخول + + + + Load automatically + دخول تلقائي + + + + Load + دخول + + + + New Profile + حساب جديد + + + + Load Profile + تسجيل دخول + + + + + + + + Couldn't create a new profile + لا يمكن إنشاء حساب جديد + + + + The username must not be empty. + لا يجوز أن يكون اسم المستخدم فارغاً. + + + + The password must be at least 6 characters long. + كلمة المرور يجب أن تحتوي على أكثر من 6 مقاطع. + + + + The passwords you've entered are different. +Please make sure to enter same password twice. + كلمة المرور التي أدخلتها مختلفة. أدخل نفس كلمة المرور في المرتين. + + + + A profile with this name already exists. + يوجد حساب بهذا الاسم فعلا. + + + + Unknown error: Couldn't create a new profile. +If you encountered this error, please report it. + خطأ غير معروف: لا يمكن إنشاء حساب جديد. إذا واجهت هذا الخطأ, نرجو أن تبلغ عنه. + + + + Couldn't load profile + لا يستطيع الدخول + + + + There is no selected profile. + +You may want to create one. + لم يتم إختيار حساب. + +ربما تريد إنشاء واحد.. + + + + + + Couldn't load this profile + لا تستطيع الدخول لهذا الحساب + + + + This profile is already in use. + هذا الحساب مستخدم فعلا. + + + + Profile already in use. Close other clients. + الحساب مستخدم فعلا. أغلقه من باقي الاجهزة. + + + + Wrong password. + كلمة المرور خاطئة. + + + + MainWindow + + + Your name + إسمك + + + + Your status + حالتك + + + + ... + ... + + + + Add friends + إضافة أصدقاء + + + + Create a group chat + إنشاء غرفة محادثة + + + + View completed file transfers + إعرض الملفات التي تم نقلها + + + + Change your settings + تغيير الإعدادات + + + + Close + إغلاق + + + + Nexus + + + Images (%1) + filetype filter + صور (%1) + + + + View + OS X Menu bar + عرض + + + + Window + OS X Menu bar + نافذة + + + + Minimize + OS X Menu bar + تصغير + + + + Bring All to Front + OS X Menu bar + في المقدمة + + + + Exit Fullscreen + إلغاء ملئ الشاشة + + + + Enter Fullscreen + ملئ الشاشة + + + + NotificationEdgeWidget + + + Unread message(s) + + لا يوجد رسائل غير مقروءة + رسالة غير مقروءة + رسالتين غير مقروءة + رسائل غير مقروءة + عدة رسائل غير مقروءة + مئات الرسائل غير مقروءة + + + + + PrivacyForm + + + Confirmation + تأكيد + + + + Do you want to permanently delete all chat history? + هل تريد حذف سجل المحادثات بشكل دائم ؟ + + + + Privacy + خصوصية + + + + PrivacySettings + + + Your friends will be able to see when you are typing. + tooltip for typing notifications setting + اصدقائك سيرون اشعاراً عندما تكون تكتب. + + + + Send typing notifications + ارسال اشعار كتابة + + + + Chat history keeping is still in development. +Save format changes are possible, which may result in data loss. + toolTip for Keep History setting + سجل المحادثات لا يزال قيد التطوير. +تغييرات الصيغة المعروفة ممكنة , هذا قد يؤدي الى فقدان البيانات. + + + + + Keep chat history + حفظ سجل المحادثة + + + + NoSpam is part of your Tox ID. +If you are being spammed with friend requests, you should change your NoSpam. +People will be unable to add you with your old ID, but you will keep your current friends. + toolTip for nospam + + + + + NoSpam + + + + + NoSpam is a part of your ID that can be changed at will. +If you are getting spammed with friend requests, change the NoSpam. + + + + + Generate random NoSpam + + + + + ProfileForm + + + Current profile: + الملف الشخصي الحالي: + + + + Remove + ازالة + + + + Choose a profile picture + اختيار صورة الملف الشخصي + + + + + + Error + خطأ + + + + Unable to open this file. + غير قابل لفتح هذا الملف. + + + + Unable to read this image. + غير قابل لقراءة هذه الصورة. + + + + The supplied image is too large. +Please use another image. + الصورة المختارة كبيرة جداً. +نرجو استخدام صورة اخرى. + + + + Rename "%1" + renaming a profile + اعادة تسمية "%1" + + + + Profile already exists + rename failure title + الملف الشخصي موجود فعلا + + + + A profile named "%1" already exists. + rename confirm text + الملف الشخصي باسم "%1" موجود فعلا. + + + + Failed to rename + rename failed title + فشلة اعادة التسمية + + + + Couldn't rename the profile to "%1" + غير قادر على اعادة تسمية الملف الشخصية لــ "%1" + + + + Export profile + save dialog title + تصدير الملف الشخصي + + + + Tox save file (*.tox) + save dialog filter + (*.tox) حفظ ملفات Tox + + + + + Location not writable + Title of permissions popup + المسار غير قابل للكتابة + + + + + You do not have permission to write that location. Choose another, or cancel the save dialog. + text of permissions popup + ليس لديك تصريح للكتابة في هذا المسار. اختر غيره, او الغِ نافذة الحفظ. + + + + + Failed to copy file + فشل في النسخ + + + + + The file you chose could not be written to. + الملف الذي اخترته غير قابل للكتابة عليه. + + + + Really delete profile? + deletion confirmation title + حقاً حذف الملف الشخصي؟ + + + + Are you sure you want to delete this profile? + deletion confirmation text + هل انت متأكد من حذف هذا الملف الشخصي؟ + + + + Save + save qr image + حفظ + + + + Save QrCode (*.png) + save dialog filter + (*.png) حفظ QrCode + + + + Nothing to remove + لا شيء لإزالته + + + + Your profile does not have a password! + ملفك الشخصي لا يملك كلمة مرور! + + + + Really delete password? + deletion confirmation title + حقاً حذف كلمة المرور؟ + + + + Are you sure you want to delete your password? + deletion confirmation text + هل انت متأكد من حذف كلمة المرور الخاصة بك؟ + + + + Please enter a new password. + يرجى إدخال كلمة مرور جديدة. + + + + User Profile + مستخدم الملف الشخصي + + + + This bunch of characters tells other Tox clients how to contact you. +Share it with your friends to communicate. + هذه الباقة من الحروف تسمح لبقية المستخدمين بالتواصل معك. +شاركها مع اصدقائك لتتواصلوا. + + + + QObject + + + Resizing + تغيير الحجم + + + + Tox URI to parse + + + + + Starts new instance and loads specified profile. + + + + + profile + ملف شخصي + + + + An update is available, do you want to download it now? +It will be installed when qTox restarts. + هناك تحديث متاح, هل تريد تحميله الان؟ +اذا تم تثبيته سيتم اعادة تشغيل البرنامج. + + + + Version %1, %2 + النسخة %1, %2 + + + + Update + The title of a message box + تحديث + + + + Incorrect responce + استجابة خاطئة + + + + No password in response + + + + + Server doesn't support Toxme + الخادم لا يدعم Toxme + + + + You must send POST requests to /api + + + + + Please try again using a HTTPS connection + يرجى المحاولة مرة اخرة بإستخدام اتصال HTTPS + + + + I was unable to read your encrypted payload + غير قادر على قراءة المشفر + + + + You're making too many requests. Wait an hour and try again + لقد عملت الكثير من الطلبات. انتظر ساعة وأعد المحاولة + + + + This name is already in use + الاسم مستخدم فعلا + + + + This Tox ID is already registered under another name + هذا المعرف مسجل فعلا تحت اسم اخر + + + + Please don't use a space in your name + يرجى عدم استخدام مسافات في اسمك + + + + Password incorrect + كلمة المرور خاطئة + + + + You can't use this name + لا تستطيع استخدام هذا الاسم + + + + Name not found + لم يتم ايجاد الاسم + + + + Tox ID not sent + لم يتم ارسال المعرف + + + + Lookup failed because the other server replied with invalid data + فشل البحث بسبب السيرفر الاخر وجّه ملفات غير صالحة + + + + That user does not exist + هذا المستخدم غير موجود + + + + Internal lookup error. Please file a bug + البحث الداخلي فشل + + + + Unknown error (%1) + خطأ غير معروف (%1) + + + + %1 here! Tox me maybe? + Default message in Tox URI friend requests. Write something appropriate! + %1 هنا! + + + + Error + خطأ + + + + qTox couldn't open your chat logs, they will be disabled. + غير قادر على فتح سجل المحادثات , قد يكون معطلاً. + + + + Ignoring non-Tox file + popup title + تخطي , ليس ملف Tox + + + + Warning: you've chosen a file that is not a Tox save file; ignoring. + popup text + تحذير: لم يتم اختيار ملف حفظ Tox ; تجاهل. + + + + Profile already exists + import confirm title + الملف الشخصي موجود فعلا + + + + A profile named "%1" already exists. Do you want to erase it? + import confirm text + الملف الشخصي "%1" موجود فعلا . هل تريد محوه ؟ + + + + Profile imported + ملف شخصي مستورد + + + + %1.tox was successfully imported + %1.نجحت اضافته + + + + None + No camera device set + لا شيئ + + + + + Desktop + Desktop as a camera input for screen sharing + سطح المكتب + + + + Default + افتراضي + + + + Blue + ازرق + + + + Olive + زيتوني + + + + Red + احمر + + + + Violet + بنفسجي + + + + Incoming call... + مكالمة واردة... + + + + RemoveFriendDialog + + + Remove friend + ازالة صديق + + + + <html><head/><body><p>Are you sure you want to remove <span style=" font-weight:600;">&lt;name&gt;</span> from your contacts list?</p></body></html> + <html><head/><body><p>هل انت متأكد من ازالة <span style=" font-weight:600;">&lt;name&gt;</span>من جهات الاتصال ؟</p></body></html> + + + + Also remove chat history + ايضا حذف سجل المحادثة + + + + Remove + ازالة + + + + ScreenshotGrabber + + + Click and drag to select a region. Press <b>Space</b> to hide/show qTox window, or <b>Escape</b> to cancel. + Help text shown when no region has been selected yet + اضغط وافلت للتحديد. اضغط <b>مسافة</b> لـ اخفاء/إظهار نافذة qTox او <b>Esc</b> للالغاء. + + + + Press <b>Enter</b> to send a screenshot of the selection, <b>Space</b> to hide/show qTox window, or <b>Escape</b> to cancel. + Help text shown when a region has been selected + اضغط <b>Enter</b> لارسال لقطة الشاشة المحددةاضغط <b>مسافة</b> لـ اخفاء/إظهار نافذة qTox او <b>Esc</b> للالغاء. + + + + SetPasswordDialog + + + Set your password + اختيار كلمة المرور + + + + Confirm: + التأكيد: + + + + Password: + كلمة المرور: + + + + Password strength: %p% + قوة كلمة المرور: %p% + + + + The password is too short + كلمة المرور قصيرة جدا + + + + The password doesn't match. + كلمة المرور ليست متطابقة. + + + + Settings + + + Circle #%1 + قائمة #%1 + + + + ToxDNS + + + The connection timed out + The DNS gives the Tox ID associated to toxme.se addresses + مهلة الاتصال + + + + This address does not exist + The DNS gives the Tox ID associated to toxme.se addresses + هذا العنوان غير موجود + + + + Error while looking up DNS + The DNS gives the Tox ID associated to toxme.se addresses + خطأ اثناء البحث عن DNS + + + + No text record found + Error with the DNS + + + + + Unexpected number of values in text record + Error with the DNS + + + + + ToxURIDialog + + + Add a friend + Title of the window to add a friend through Tox URI + إضافة صديق + + + + Do you want to add %1 as a friend? + هل تريد اضافة %1 كصديق؟ + + + + User ID: + ID المستخدم: + + + + Friend request message: + رسالة طلب الاضافة: + + + + Send + Send a friend request + ارسال + + + + Cancel + Don't send a friend request + إلغاء + + + + Widget + + + Status + الحالة + + + + toxcore failed to start, the application will terminate after you close this message. + toxcore فشل في البدء , البرنامج سيغلق بعد الخروج من هذه الرسالة. + + + + toxcore failed to start with your proxy settings. qTox cannot run; please modify your settings and restart. + popup text + toxcore فشل في البدء مع اعدادات الوكيل"البروكسي" الخاصة بك .qTox لا ستطيع البدء , يرجى تغيير الاعدادات واعادة المحاولة. + + + + Executable file + popup title + ملف تنفيدي + + + + You have asked qTox to open an executable file. Executable files can potentially damage your computer. Are you sure want to open this file? + popup text + هل انت متأكد من فتح الملف ؟ + + + + + Your name + اسمك + + + + + Your status + حالتك + + + + Couldn't request friendship + لا يمكن طلب الصداقة + + + + away + contact status + في الخارج + + + + busy + contact status + مشغول + + + + offline + contact status + غير متصل + + + + online + contact status + متصل + + + + %1 is now %2 + e.g. "Dubslow is now online" + + + + + Add friend + إضافة صديق + + + + File transfers + نقل الملفات + + + + Settings + الاعدادات + + + + Profile + الملف الشخصي + + + + Group invite + popup title + دعوة لمجموعة + + + + %1 has invited you to a groupchat. Would you like to join? + popup text + %1 قد دعاك الى مجموعة . هل تريد الانضمام؟ + + + + <Unknown> + Placeholder when we don't know someone's name in a group chat + + + + + %1 has set the title to %2 + + + + + Message failed to send + فشل ارسال الرسالة + + + + Add new circle... + اضافة قائمة جديدة... + + + + By Name + بالاسم + + + + By Activity + بالنشاط + + + + All + الجميع + + + + Online + متصل + + + + Offline + غير متصل + + + + Friends + الأصدقاء + + + + Groups + المجموعات + + + + + Search Contacts + بحث عن جهة إتصال + + + + Online + Button to set your status to 'Online' + متصل + + + + Away + Button to set your status to 'Away' + في الخارج + + + + Busy + Button to set your status to 'Busy' + مشغول + + + + Logout + Tray action menu to logout user + تسجيل خروج + + + + Exit + Tray action menu to exit tox + خروج + + + + Filter... + فلتر... + + + + File + ملف + + + + Edit + تعديل + + + + Contacts + جهات الاتصال + + + + Change Status + تغيير الحالة + + + + Edit Profile + تعديل الملف الشخصي + + + + Log out + تسجيل خروج + + + + Add Contact... + اضافة جهة اتصال... + + + + Next Conversation + المحادثة التالية + + + + Previous Conversation + المحادثة السابقة + + + diff --git a/translations/i18n.pri b/translations/i18n.pri index def441f81..a76986326 100644 --- a/translations/i18n.pri +++ b/translations/i18n.pri @@ -20,6 +20,7 @@ TRANSLATIONS = translations/es.ts \ translations/tr.ts \ translations/uk.ts \ translations/zh.ts \ + translations/ar.ts \ translations/pt.ts #rules to generate ts From 9251f1f4ca2ce6e2d8366e44a4c6bf7ff4f9bbdd Mon Sep 17 00:00:00 2001 From: tux3 Date: Mon, 25 Jan 2016 16:27:02 +0100 Subject: [PATCH 174/210] Fix #2854: Missing noexcept in Audio --- src/audio/audio.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 40f1aca75..8b56f410a 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -87,14 +87,14 @@ Audio::~Audio() filterer.closeFilter(); } -void Audio::checkAlError() +void Audio::checkAlError() noexcept { const ALenum al_err = alGetError(); if (al_err != AL_NO_ERROR) qWarning("OpenAL error: %d", al_err); } -void Audio::checkAlcError(ALCdevice *device) +void Audio::checkAlcError(ALCdevice *device) noexcept { const ALCenum alc_err = alcGetError(device); if (alc_err) From c82e41ff6f029dacb92ca32e8eac144505339082 Mon Sep 17 00:00:00 2001 From: tux3 Date: Mon, 25 Jan 2016 16:35:45 +0100 Subject: [PATCH 175/210] Properly ifdef filteraudio usage --- src/audio/audio.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 8b56f410a..a061b0fc0 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -84,7 +84,9 @@ Audio::~Audio() audioThread->wait(); cleanupInput(); cleanupOutput(); +#ifdef QTOX_FILTER_AUDIO filterer.closeFilter(); +#endif } void Audio::checkAlError() noexcept @@ -487,6 +489,7 @@ void Audio::doCapture() int16_t buf[AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS]; alcCaptureSamples(alInDev, buf, AUDIO_FRAME_SAMPLE_COUNT); +#ifdef QTOX_FILTER_AUDIO if (Settings::getInstance().getFilterAudio()) { #ifdef ALC_LOOPBACK_CAPTURE_SAMPLES @@ -495,6 +498,7 @@ void Audio::doCapture() #endif filterer.filterAudio(buf, AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS); } +#endif for (size_t i = 0; i < AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS; ++i) buf[i] *= inGain; From 36ecde07da26a1fb19c5e5a825d0e12477cd42ad Mon Sep 17 00:00:00 2001 From: RowenStipe Date: Tue, 26 Jan 2016 06:52:15 -0500 Subject: [PATCH 176/210] Added script to set up OS X clients to build qTox --- osx/qTox-Mac-Deployer-ULTIMATE.sh | 234 ++++++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100755 osx/qTox-Mac-Deployer-ULTIMATE.sh diff --git a/osx/qTox-Mac-Deployer-ULTIMATE.sh b/osx/qTox-Mac-Deployer-ULTIMATE.sh new file mode 100755 index 000000000..d52a6289c --- /dev/null +++ b/osx/qTox-Mac-Deployer-ULTIMATE.sh @@ -0,0 +1,234 @@ +#!/usr/bin/env bash + +# qTox OSX auto BASH builder script by RowenStipe +# This uses the same process as doing it manually but with a few varients + +# Use:./qTox-Mac-Deployer-ULTIMATE.sh [Processes/Install] +# Process: -u to update -b to build -d to make the aplication productionr eady or -ubd to run all at once +# Install: use -i to start install functionality + +# Your home DIR really (Most of this happens in it) {DONT USE: ~ } +if [[ $TRAVIS = true ]]; then #travis check + MAIN_DIR="/Users/${USER}/${TRAVIS_BUILD_DIR}" +else + MAIN_DIR="/Users/${USER}" +fi +QT_DIR="/usr/local/Cellar/qt5" # Folder name of QT install +VER="${QT_DIR}/5.5.1_2" # Potential future proffing for version testing +QMAKE="${VER}/bin/qmake" # Don't change +MACDEPLOYQT="${VER}/bin/macdeployqt" # Don't change + +QTOX_DIR="${MAIN_DIR}/qTox" # Change to Git location + +TOXCORE_DIR="${MAIN_DIR}/toxcore" # Change to Git location + +FA_DIR="${MAIN_DIR}/filter_audio" + +BUILD_DIR="${MAIN_DIR}/qTox-Mac_Build" # Change if needed + +DEPLOY_DIR="${MAIN_DIR}/qTox-Mac_Deployed" + + +function fcho() { + local msg="$1"; shift + printf "\n$msg\n" "$@" +} + +function build-toxcore { + echo "Starting Toxcore build and install" + cd $TOXCORE_DIR + echo "Now working in: ${PWD}" + + #Check if libsodium is correct version + if [ -e /usr/local/opt/libsodium/lib/libsodium.17.dylib ]; then + fcho " Beginnning Toxcore compile " + else + echo "Error: libsodium.17.dylib not found! Unable to build!" + echo "Please make sure your Homebrew packages are up to date before retrying." + exit 1 + fi + sleep 3 + + autoreconf -i + + #Make sure the correct version of libsodium is used + ./configure --with-libsodium-headers=/usr/local/Cellar/libsodium/1.0.6/include/ --with-libsodium-libs=/usr/local/Cellar/libsodium/1.0.6/lib/ + + sudo make clean + make + echo "------------------------------" + echo "Sudo required, please enter your password:" + sudo make install +} + +function install { + fcho "==============================" + fcho "This script will install the nessicarry applications and libraries needed to compile qTox properly." + fcho "Note that this is not a 100 percent automated install it just helps simplfiy the process for less experianced or lazy users." + if [[ $TRAVIS = true ]]; then #travis check + echo "Oh... It's just Travis...." + else + read -n1 -rsp $'Press any key to continue or Ctrl+C to exit...\n' + fi + + if [ -e /usr/local/bin/brew ]; then + fcho "Homebrew already installed!" + else + fcho "Installing homebrew ..." + ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" + fi + fcho "Updating brew formulas ..." + brew update + fcho "Getting home brew formulas ..." + sleep 3 + brew install git ffmpeg qrencode wget libtool automake autoconf libsodium check qt5 + + fcho "Installing x-code Comand line tools ..." + xcode-select --install + + fcho "Starting git repo checks ..." + + cd $MAIN_DIR # just in case + if [ -e $TOX_DIR/.git/index ]; then # Check if this exists + fcho "Toxcore git repo already inplace !" + cd $TOX_DIR + git pull + else + fcho "Cloning Toxcore git ... " + git clone https://github.com/irungentoo/toxcore.git + fi + if [ -e $QTOX_DIR/.git/index ]; then # Check if this exists + fcho "qTox git repo already inplace !" + cd $QTOX_DIR + git pull + else + fcho "Cloning qTox git ... " + git clone https://github.com/tux3/qTox.git + fi + if [ -e $FA_DIR/.git/index ]; then # Check if this exists + fcho "Filter_Audio git repo already inplace !" + cd $FA_DIR + git pull + fcho "Please enter your password to install Filter_Audio:" + sudo make install + else + fcho "Cloning Filter_Audio git ... " + git clone https://github.com/irungentoo/filter_audio.git + cd $FA_DIR + fcho "Please enter your password to install Filter_Audio:" + sudo make install + fi + if [[ $TRAVIS = true ]]; then #travis check + build-toxcore + else + fcho "If all went well you should now have all the tools needed to compile qTox!" + read -r -p "Would you like to install toxcore now? [y/N] " response + if [[ $response =~ ^([yY][eE][sS]|[yY])$ ]]; then + build-toxcore + else + fcho "You can simply use the -u command and say [Yes/n] when prompted" + fi + fi +} + +function update { + fcho "------------------------------" + fcho "Starting update process ..." + #First update Toxcore from git + cd $TOXCORE_DIR + fcho "Now in ${PWD}" + fcho "Pulling ..." + git pull + read -r -p "Did Toxcore update from git? [y/N] " response + if [[ $response =~ ^([yY][eE][sS]|[yY])$ ]]; then + build-toxcore + else + fcho "Moving on!" + fi + + #Now let's update qTox! + cd $QTOX_DIR + fcho "Now in ${PWD}" + fcho "Pulling ..." + git pull + read -r -p "Did qTox update from git? [y/N] " response + if [[ $response =~ ^([yY][eE][sS]|[yY])$ ]]; then + fcho "Starting OSX bootstrap ..." + fcho "Sudo required:" + sudo bash ./bootstrap-osx.sh + else + fcho "Moving on!" + fi +} + +function build { + fcho "------------------------------" + fcho "Starting build process ..." + rm -r $BUILD_DIR + rm -r $DEPLOY_DIR + mkdir $BUILD_DIR + cd $BUILD_DIR + fcho "Now working in ${PWD}" + fcho "Starting qmake ... " + $QMAKE $QTOX_DIR/qtox.pro + make +} + +function deploy { + fcho "------------------------------" + fcho "starting deployment process ..." + cd $BUILD_DIR + if [ ! -d $BUILD_DIR ]; then + fcho "Error: Build directory not detected, please run -ubd, or -b before deploying" + exit 0 + fi + mkdir $DEPLOY_DIR + cp -r $BUILD_DIR/qTox.app $DEPLOY_DIR/qTox.app + cd $DEPLOY_DIR + fcho "Now working in ${PWD}" + $MACDEPLOYQT qTox.app +} + +# The commands +if [ "$1" == "-i" ]; then + install + exit 0 +fi + +if [ "$1" == "-u" ]; then + update + exit 0 +fi + +if [ "$1" == "-b" ]; then + build + exit 0 +fi + +if [ "$1" == "-d" ]; then + deploy + exit 0 +fi + +if [ "$1" == "-ubd" ]; then + update + build + deploy + exit 0 +fi + +if [ "$1" == "-h" ]; then + echo "This script was created to help ease the process of compiling and creating a distribuable qTox package for OSX systems." + echo "The avilable commands are:" + echo "-h -- This help text." + echo "-i -- A slightly automated process for getting an OSX machine ready to build Toxcore and qTox." + echo "-u -- Check for updates and build Toxcore from git & update qTox from git." + echo "-b -- Builds qTox in: ${BUILD_DIR}" + echo "-d -- Makes a distributeable qTox.app file in: ${DEPLOY_DIR}" + echo "-ubd -- Does -u, -b, and -d sequentially" + fcho "Issues with Toxcore or qTox should be reported to their respective repos: https://github.com/irungentoo/toxcore | https://github.com/tux3/qTox" + exit 0 +fi + +fcho "Oh dear! You seemed to of started this script improperly! Use -h to get avilable commands and information!" +exit 0 \ No newline at end of file From f6d7033b515609db94ae0649a02df4052a78ee15 Mon Sep 17 00:00:00 2001 From: RowenStipe Date: Tue, 26 Jan 2016 06:55:28 -0500 Subject: [PATCH 177/210] Added copyright header --- osx/qTox-Mac-Deployer-ULTIMATE.sh | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/osx/qTox-Mac-Deployer-ULTIMATE.sh b/osx/qTox-Mac-Deployer-ULTIMATE.sh index d52a6289c..598fea059 100755 --- a/osx/qTox-Mac-Deployer-ULTIMATE.sh +++ b/osx/qTox-Mac-Deployer-ULTIMATE.sh @@ -1,11 +1,25 @@ #!/usr/bin/env bash -# qTox OSX auto BASH builder script by RowenStipe +# +# Copyright © 2015 by RowenStipe +# Copyright © 2016 by The qTox Project +# +# This program is libre software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + # This uses the same process as doing it manually but with a few varients -# Use:./qTox-Mac-Deployer-ULTIMATE.sh [Processes/Install] -# Process: -u to update -b to build -d to make the aplication productionr eady or -ubd to run all at once -# Install: use -i to start install functionality +# Use: ./qTox-Mac-Deployer-ULTIMATE.sh -h # Your home DIR really (Most of this happens in it) {DONT USE: ~ } if [[ $TRAVIS = true ]]; then #travis check From cc4dd1ab0f2a1c700b44a483522160beeaa51ac7 Mon Sep 17 00:00:00 2001 From: RowenStipe Date: Tue, 26 Jan 2016 07:28:07 -0500 Subject: [PATCH 178/210] fixed small issue with functions --- osx/qTox-Mac-Deployer-ULTIMATE.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osx/qTox-Mac-Deployer-ULTIMATE.sh b/osx/qTox-Mac-Deployer-ULTIMATE.sh index 598fea059..2a87627de 100755 --- a/osx/qTox-Mac-Deployer-ULTIMATE.sh +++ b/osx/qTox-Mac-Deployer-ULTIMATE.sh @@ -48,7 +48,7 @@ function fcho() { printf "\n$msg\n" "$@" } -function build-toxcore { +function build-toxcore() { echo "Starting Toxcore build and install" cd $TOXCORE_DIR echo "Now working in: ${PWD}" @@ -75,7 +75,7 @@ function build-toxcore { sudo make install } -function install { +function install() { fcho "==============================" fcho "This script will install the nessicarry applications and libraries needed to compile qTox properly." fcho "Note that this is not a 100 percent automated install it just helps simplfiy the process for less experianced or lazy users." @@ -145,7 +145,7 @@ function install { fi } -function update { +function update() { fcho "------------------------------" fcho "Starting update process ..." #First update Toxcore from git @@ -175,7 +175,7 @@ function update { fi } -function build { +function build() { fcho "------------------------------" fcho "Starting build process ..." rm -r $BUILD_DIR @@ -188,7 +188,7 @@ function build { make } -function deploy { +function deploy() { fcho "------------------------------" fcho "starting deployment process ..." cd $BUILD_DIR From 75607bcecceb101b4e2cf79f7c9a7b5df63ba6fc Mon Sep 17 00:00:00 2001 From: Zetok Zalbavar Date: Tue, 26 Jan 2016 07:46:35 +0000 Subject: [PATCH 179/210] Add travis (again) Beside making it work again, there are some improvements: Linux side: * use minimal supported Qt version, currently it's 5.3 * use minimal supported GCC version, currently 4.8 * use newer ffmpeg version to compile against - 2.8.5 * compile qTox 2 times, first run without support for optional dependencies * use ubuntu 14.04 for building (less deps needs to be compiled/added from PPAs) OSX: * add osx to build targets --- .travis.yml | 13 ++++ .travis/build-ubuntu_14_04.sh | 101 ++++++++++++++++++++++++++++++ README.md | 2 + osx/qTox-Mac-Deployer-ULTIMATE.sh | 4 +- 4 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 .travis.yml create mode 100755 .travis/build-ubuntu_14_04.sh diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..1d573a497 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,13 @@ +sudo: required +dist: trusty + +language: cpp + +os: + - linux + - osx + +script: +- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then bash ./.travis/build-ubuntu_14_04.sh; fi +- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then bash ./osx/qTox-Mac-Deployer-ULTIMATE.sh -i ; fi +- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then bash ./osx/qTox-Mac-Deployer-ULTIMATE.sh -b ; fi diff --git a/.travis/build-ubuntu_14_04.sh b/.travis/build-ubuntu_14_04.sh new file mode 100755 index 000000000..95da5b4ed --- /dev/null +++ b/.travis/build-ubuntu_14_04.sh @@ -0,0 +1,101 @@ +#!/bin/bash +# +# Copyright © 2014-2015 by The qTox Project +# +# This program is libre software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +# Qt 5.3, since that's the lowest supported version +sudo add-apt-repository -y ppa:beineri/opt-qt532-trusty +sudo apt-get update -qq + +# install needed Qt, OpenAL, opus, qrencode, GTK tray deps, sqlcipher +sudo apt-get install -y build-essential \ + qt53base \ + qt53script \ + qt53svg \ + qt53tools \ + qt53xmlpatterns \ + libopenal-dev \ + libxss-dev qrencode \ + libqrencode-dev \ + libglib2.0-dev \ + libgdk-pixbuf2.0-dev \ + libgtk2.0-dev \ + libsqlcipher-dev \ + libtool \ + autotools-dev \ + automake \ + checkinstall \ + check \ + libopus-dev \ + libvpx-dev + +# Qt +source /opt/qt53/bin/qt53-env.sh + +# ffmpeg +if [ ! -e "libs" ]; then mkdir libs; fi +if [ ! -e "ffmpeg" ]; then mkdir ffmpeg; fi +# +cd libs/ +export PREFIX_DIR="$PWD" +# +cd ../ffmpeg +wget http://ffmpeg.org/releases/ffmpeg-2.8.5.tar.bz2 +tar xf ffmpeg* +cd ffmpeg* +./configure --prefix="$PREFIX_DIR" --enable-shared --disable-static --disable-programs --disable-protocols --disable-doc --disable-sdl --disable-avfilter --disable-avresample --disable-filters --disable-iconv --disable-network --disable-muxers --disable-postproc --disable-swresample --disable-swscale-alpha --disable-dct --disable-dwt --disable-lsp --disable-lzo --disable-mdct --disable-rdft --disable-fft --disable-faan --disable-vaapi --disable-vdpau --disable-zlib --disable-xlib --disable-bzlib --disable-lzma --disable-encoders --disable-yasm --enable-memalign-hack +make -j$(nproc) +make install +cd ../../ +# filter_audio +git clone https://github.com/irungentoo/filter_audio +cd filter_audio +make -j$(nproc) +sudo make install +cd .. +# libsodium +git clone git://github.com/jedisct1/libsodium.git +cd libsodium +git checkout tags/1.0.8 +./autogen.sh +./configure && make -j$(nproc) +sudo checkinstall --install --pkgname libsodium --pkgversion 1.0.8 --nodoc -y +sudo ldconfig +cd .. +# toxcore +git clone https://github.com/irungentoo/toxcore.git +cd toxcore +autoreconf -if +./configure +make -j$(nproc) > /dev/null +sudo make install +echo '/usr/local/lib/' | sudo tee -a /etc/ld.so.conf.d/locallib.conf +sudo ldconfig +cd .. + +$CC --version +$CXX --version +# first build qTox without support for optional dependencies +echo '*** BUILDING "MINIMAL" VERSION ***' +qmake qtox.pro QMAKE_CC="$CC" QMAKE_CXX="$CXX" DISABLE_FILTER_AUDIO=YES ENABLE_SYSTRAY_STATUSNOTIFIER_BACKEND=NO ENABLE_SYSTRAY_GTK_BACKEND=NO DISABLE_PLATFORM_EXT=YES +# ↓ with $(nproc) fails, since travis gives 32 threads, and it leads to OOM +make -j10 +# clean it up, and build normal version +make clean +echo '*** BUILDING "FULL" VERSION ***' +qmake qtox.pro QMAKE_CC="$CC" QMAKE_CXX="$CXX" +# ↓ with $(nproc) fails, since travis gives 32 threads, and it leads to OOM +make -j10 diff --git a/README.md b/README.md index 4205546cd..a8a2db2a7 100644 --- a/README.md +++ b/README.md @@ -51,3 +51,5 @@ Note: The screenshots may not always be up to date, but they should give a good - Emoticons - Auto-updates on Windows and Mac, packages on Linux - And many more options! + +[![Build Status](https://travis-ci.org/tux3/qTox.svg)](https://travis-ci.org/tux3/qTox) diff --git a/osx/qTox-Mac-Deployer-ULTIMATE.sh b/osx/qTox-Mac-Deployer-ULTIMATE.sh index 2a87627de..c5027b531 100755 --- a/osx/qTox-Mac-Deployer-ULTIMATE.sh +++ b/osx/qTox-Mac-Deployer-ULTIMATE.sh @@ -23,7 +23,7 @@ # Your home DIR really (Most of this happens in it) {DONT USE: ~ } if [[ $TRAVIS = true ]]; then #travis check - MAIN_DIR="/Users/${USER}/${TRAVIS_BUILD_DIR}" + MAIN_DIR="${TRAVIS_BUILD_DIR}" else MAIN_DIR="/Users/${USER}" fi @@ -245,4 +245,4 @@ if [ "$1" == "-h" ]; then fi fcho "Oh dear! You seemed to of started this script improperly! Use -h to get avilable commands and information!" -exit 0 \ No newline at end of file +exit 0 From ab769d117502d279b0de57aea5d2c23ee758ca24 Mon Sep 17 00:00:00 2001 From: RowenStipe Date: Tue, 26 Jan 2016 08:45:39 -0500 Subject: [PATCH 180/210] Updated libsodium check --- osx/qTox-Mac-Deployer-ULTIMATE.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osx/qTox-Mac-Deployer-ULTIMATE.sh b/osx/qTox-Mac-Deployer-ULTIMATE.sh index c5027b531..03e34f247 100755 --- a/osx/qTox-Mac-Deployer-ULTIMATE.sh +++ b/osx/qTox-Mac-Deployer-ULTIMATE.sh @@ -54,10 +54,10 @@ function build-toxcore() { echo "Now working in: ${PWD}" #Check if libsodium is correct version - if [ -e /usr/local/opt/libsodium/lib/libsodium.17.dylib ]; then + if [ -e /usr/local/opt/libsodium/lib/libsodium.18.dylib ]; then fcho " Beginnning Toxcore compile " else - echo "Error: libsodium.17.dylib not found! Unable to build!" + echo "Error: libsodium.18.dylib not found! Unable to build!" echo "Please make sure your Homebrew packages are up to date before retrying." exit 1 fi @@ -66,7 +66,7 @@ function build-toxcore() { autoreconf -i #Make sure the correct version of libsodium is used - ./configure --with-libsodium-headers=/usr/local/Cellar/libsodium/1.0.6/include/ --with-libsodium-libs=/usr/local/Cellar/libsodium/1.0.6/lib/ + ./configure --with-libsodium-headers=/usr/local/Cellar/libsodium/1.0.8/include/ --with-libsodium-libs=/usr/local/Cellar/libsodium/1.0.8/lib/ sudo make clean make From 5a020914410c2f0529239ebdee9ec1bc5b7f66b3 Mon Sep 17 00:00:00 2001 From: Zetok Zalbavar Date: Tue, 26 Jan 2016 14:14:04 +0000 Subject: [PATCH 181/210] Fix osx travis - use bootstrap-osx.sh --- osx/qTox-Mac-Deployer-ULTIMATE.sh | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/osx/qTox-Mac-Deployer-ULTIMATE.sh b/osx/qTox-Mac-Deployer-ULTIMATE.sh index 03e34f247..0afe5f696 100755 --- a/osx/qTox-Mac-Deployer-ULTIMATE.sh +++ b/osx/qTox-Mac-Deployer-ULTIMATE.sh @@ -37,6 +37,7 @@ QTOX_DIR="${MAIN_DIR}/qTox" # Change to Git location TOXCORE_DIR="${MAIN_DIR}/toxcore" # Change to Git location FA_DIR="${MAIN_DIR}/filter_audio" +FA_INSTALL_PREFIX="${QTOX_DIR}/libs" BUILD_DIR="${MAIN_DIR}/qTox-Mac_Build" # Change if needed @@ -119,19 +120,22 @@ function install() { fcho "Cloning qTox git ... " git clone https://github.com/tux3/qTox.git fi + # filter_audio if [ -e $FA_DIR/.git/index ]; then # Check if this exists fcho "Filter_Audio git repo already inplace !" cd $FA_DIR git pull - fcho "Please enter your password to install Filter_Audio:" - sudo make install else fcho "Cloning Filter_Audio git ... " git clone https://github.com/irungentoo/filter_audio.git cd $FA_DIR - fcho "Please enter your password to install Filter_Audio:" - sudo make install fi + if [ ! -e "$FA_INSTALL_PREFIX" ]; then + mkdir "$FA_INSTALL_PREFIX" + fi + fcho "Please enter your password to install Filter_Audio:" + make install PREFIX="${FA_INSTALL_PREFIX}" + # toxcore if [[ $TRAVIS = true ]]; then #travis check build-toxcore else @@ -143,6 +147,7 @@ function install() { fcho "You can simply use the -u command and say [Yes/n] when prompted" fi fi + $QTOX_DIR/bootstrap-osx.sh } function update() { From 3a452a700fa0fe2d61ec1a3df5bea691889adb1f Mon Sep 17 00:00:00 2001 From: RowenStipe Date: Tue, 26 Jan 2016 10:48:21 -0500 Subject: [PATCH 182/210] General clean up --- osx/qTox-Mac-Deployer-ULTIMATE.sh | 41 +++++++++++++++++-------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/osx/qTox-Mac-Deployer-ULTIMATE.sh b/osx/qTox-Mac-Deployer-ULTIMATE.sh index 0afe5f696..ff04357c2 100755 --- a/osx/qTox-Mac-Deployer-ULTIMATE.sh +++ b/osx/qTox-Mac-Deployer-ULTIMATE.sh @@ -32,7 +32,11 @@ VER="${QT_DIR}/5.5.1_2" # Potential future proffing for version testing QMAKE="${VER}/bin/qmake" # Don't change MACDEPLOYQT="${VER}/bin/macdeployqt" # Don't change -QTOX_DIR="${MAIN_DIR}/qTox" # Change to Git location +if [ $TRAVIS = true ]]; then #travis check + QTOX_DIR="${MAIN_DIR}" +else + QTOX_DIR="${MAIN_DIR}/qTox" # Change to Git location +fi TOXCORE_DIR="${MAIN_DIR}/toxcore" # Change to Git location @@ -55,7 +59,7 @@ function build-toxcore() { echo "Now working in: ${PWD}" #Check if libsodium is correct version - if [ -e /usr/local/opt/libsodium/lib/libsodium.18.dylib ]; then + if [[ -e /usr/local/opt/libsodium/lib/libsodium.18.dylib ]]; then fcho " Beginnning Toxcore compile " else echo "Error: libsodium.18.dylib not found! Unable to build!" @@ -86,7 +90,7 @@ function install() { read -n1 -rsp $'Press any key to continue or Ctrl+C to exit...\n' fi - if [ -e /usr/local/bin/brew ]; then + if [[ -e /usr/local/bin/brew ]]; then fcho "Homebrew already installed!" else fcho "Installing homebrew ..." @@ -104,7 +108,7 @@ function install() { fcho "Starting git repo checks ..." cd $MAIN_DIR # just in case - if [ -e $TOX_DIR/.git/index ]; then # Check if this exists + if [[ -e $TOX_DIR/.git/index ]]; then # Check if this exists fcho "Toxcore git repo already inplace !" cd $TOX_DIR git pull @@ -112,7 +116,7 @@ function install() { fcho "Cloning Toxcore git ... " git clone https://github.com/irungentoo/toxcore.git fi - if [ -e $QTOX_DIR/.git/index ]; then # Check if this exists + if [[ -e $QTOX_DIR/.git/index ]]; then # Check if this exists fcho "qTox git repo already inplace !" cd $QTOX_DIR git pull @@ -121,7 +125,7 @@ function install() { git clone https://github.com/tux3/qTox.git fi # filter_audio - if [ -e $FA_DIR/.git/index ]; then # Check if this exists + if [[ -e $FA_DIR/.git/index ]]; then # Check if this exists fcho "Filter_Audio git repo already inplace !" cd $FA_DIR git pull @@ -142,7 +146,8 @@ function install() { fcho "If all went well you should now have all the tools needed to compile qTox!" read -r -p "Would you like to install toxcore now? [y/N] " response if [[ $response =~ ^([yY][eE][sS]|[yY])$ ]]; then - build-toxcore + build_toxcore + else fcho "You can simply use the -u command and say [Yes/n] when prompted" fi @@ -209,34 +214,34 @@ function deploy() { } # The commands -if [ "$1" == "-i" ]; then +if [[ "$1" == "-i" ]]; then install - exit 0 + exit fi -if [ "$1" == "-u" ]; then +if [[ "$1" == "-u" ]]; then update - exit 0 + exit fi -if [ "$1" == "-b" ]; then +if [[ "$1" == "-b" ]]; then build - exit 0 + exit fi -if [ "$1" == "-d" ]; then +if [[ "$1" == "-d" ]]; then deploy - exit 0 + exit fi -if [ "$1" == "-ubd" ]; then +if [[ "$1" == "-ubd" ]]; then update build deploy - exit 0 + exit fi -if [ "$1" == "-h" ]; then +if [[ "$1" == "-h" ]]; then echo "This script was created to help ease the process of compiling and creating a distribuable qTox package for OSX systems." echo "The avilable commands are:" echo "-h -- This help text." From 529349d8d38ef91c3c0ae346d76795b80fc4e23a Mon Sep 17 00:00:00 2001 From: Zetok Zalbavar Date: Tue, 26 Jan 2016 16:49:10 +0000 Subject: [PATCH 183/210] osx build script: install toxcore into `libs/` --- osx/qTox-Mac-Deployer-ULTIMATE.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osx/qTox-Mac-Deployer-ULTIMATE.sh b/osx/qTox-Mac-Deployer-ULTIMATE.sh index ff04357c2..6f03c383d 100755 --- a/osx/qTox-Mac-Deployer-ULTIMATE.sh +++ b/osx/qTox-Mac-Deployer-ULTIMATE.sh @@ -32,7 +32,7 @@ VER="${QT_DIR}/5.5.1_2" # Potential future proffing for version testing QMAKE="${VER}/bin/qmake" # Don't change MACDEPLOYQT="${VER}/bin/macdeployqt" # Don't change -if [ $TRAVIS = true ]]; then #travis check +if [[ $TRAVIS = true ]]; then #travis check QTOX_DIR="${MAIN_DIR}" else QTOX_DIR="${MAIN_DIR}/qTox" # Change to Git location @@ -41,7 +41,7 @@ fi TOXCORE_DIR="${MAIN_DIR}/toxcore" # Change to Git location FA_DIR="${MAIN_DIR}/filter_audio" -FA_INSTALL_PREFIX="${QTOX_DIR}/libs" +LIB_INSTALL_PREFIX="${QTOX_DIR}/libs" BUILD_DIR="${MAIN_DIR}/qTox-Mac_Build" # Change if needed @@ -71,7 +71,7 @@ function build-toxcore() { autoreconf -i #Make sure the correct version of libsodium is used - ./configure --with-libsodium-headers=/usr/local/Cellar/libsodium/1.0.8/include/ --with-libsodium-libs=/usr/local/Cellar/libsodium/1.0.8/lib/ + ./configure --with-libsodium-headers=/usr/local/Cellar/libsodium/1.0.8/include/ --with-libsodium-libs=/usr/local/Cellar/libsodium/1.0.8/lib/ --prefix="${LIB_INSTALL_PREFIX}" sudo make clean make @@ -134,11 +134,11 @@ function install() { git clone https://github.com/irungentoo/filter_audio.git cd $FA_DIR fi - if [ ! -e "$FA_INSTALL_PREFIX" ]; then - mkdir "$FA_INSTALL_PREFIX" + if [ ! -e "$LIB_INSTALL_PREFIX" ]; then + mkdir "$LIB_INSTALL_PREFIX" fi fcho "Please enter your password to install Filter_Audio:" - make install PREFIX="${FA_INSTALL_PREFIX}" + make install PREFIX="${LIB_INSTALL_PREFIX}" # toxcore if [[ $TRAVIS = true ]]; then #travis check build-toxcore From 0abeaa4b62ff66bac95106508d5bd9500321ef65 Mon Sep 17 00:00:00 2001 From: Zetok Zalbavar Date: Tue, 26 Jan 2016 17:36:03 +0000 Subject: [PATCH 184/210] osx build script: install vpx and opus --- osx/qTox-Mac-Deployer-ULTIMATE.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osx/qTox-Mac-Deployer-ULTIMATE.sh b/osx/qTox-Mac-Deployer-ULTIMATE.sh index 6f03c383d..2a99f67b0 100755 --- a/osx/qTox-Mac-Deployer-ULTIMATE.sh +++ b/osx/qTox-Mac-Deployer-ULTIMATE.sh @@ -100,7 +100,10 @@ function install() { brew update fcho "Getting home brew formulas ..." sleep 3 - brew install git ffmpeg qrencode wget libtool automake autoconf libsodium check qt5 + if [[ $TRAVIS != true ]]; then #travis check + brew install wget libtool automake + fi + brew install git ffmpeg qrencode autoconf check qt5 libvpx opus sqlcipher libsodium fcho "Installing x-code Comand line tools ..." xcode-select --install From 3723f4b465c4906498556bcf01f2e42edf309b5e Mon Sep 17 00:00:00 2001 From: Zetok Zalbavar Date: Wed, 27 Jan 2016 01:22:04 +0000 Subject: [PATCH 185/210] osx build script: fix building on travis copy libs/headers required by qTox into `libs/` --- bootstrap-osx.sh | 4 ---- osx/qTox-Mac-Deployer-ULTIMATE.sh | 28 +++++++++++++++------------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/bootstrap-osx.sh b/bootstrap-osx.sh index 3b6eba2eb..ac2cd90d1 100755 --- a/bootstrap-osx.sh +++ b/bootstrap-osx.sh @@ -21,18 +21,14 @@ echo Creating directories… mkdir -p libs/lib mkdir -p libs/include echo Copying libraries… -cp /usr/local/lib/libtox* libs/lib cp /usr/local/lib/libsodium* libs/lib cp /usr/local/lib/libvpx* libs/lib cp /usr/local/lib/libopus* libs/lib cp /usr/local/lib/libav* libs/lib cp /usr/local/lib/libswscale* libs/lib cp /usr/local/lib/libqrencode* libs/lib -cp /usr/local/lib/libfilteraudio* libs/lib cp /usr/local/lib/libsqlcipher* libs/lib echo Copying include files... -cp /usr/local/include/filter_audio* libs/include -cp -r /usr/local/include/tox* libs/include cp -r /usr/local/include/vpx* libs/include cp -r /usr/local/include/sodium* libs/include cp -r /usr/local/include/qrencode* libs/include diff --git a/osx/qTox-Mac-Deployer-ULTIMATE.sh b/osx/qTox-Mac-Deployer-ULTIMATE.sh index 2a99f67b0..5a91cfc7f 100755 --- a/osx/qTox-Mac-Deployer-ULTIMATE.sh +++ b/osx/qTox-Mac-Deployer-ULTIMATE.sh @@ -43,6 +43,10 @@ TOXCORE_DIR="${MAIN_DIR}/toxcore" # Change to Git location FA_DIR="${MAIN_DIR}/filter_audio" LIB_INSTALL_PREFIX="${QTOX_DIR}/libs" +if [[ ! -e "${LIB_INSTALL_PREFIX}" ]]; then + mkdir -p "${LIB_INSTALL_PREFIX}" +fi + BUILD_DIR="${MAIN_DIR}/qTox-Mac_Build" # Change if needed DEPLOY_DIR="${MAIN_DIR}/qTox-Mac_Deployed" @@ -68,16 +72,16 @@ function build-toxcore() { fi sleep 3 - autoreconf -i + autoreconf -if #Make sure the correct version of libsodium is used ./configure --with-libsodium-headers=/usr/local/Cellar/libsodium/1.0.8/include/ --with-libsodium-libs=/usr/local/Cellar/libsodium/1.0.8/lib/ --prefix="${LIB_INSTALL_PREFIX}" - sudo make clean - make - echo "------------------------------" - echo "Sudo required, please enter your password:" - sudo make install + make clean &> /dev/null + fcho "Compiling toxcore." + make > /dev/null || exit 1 + fcho "Installing toxcore." + make install > /dev/null || exit 1 } function install() { @@ -137,10 +141,7 @@ function install() { git clone https://github.com/irungentoo/filter_audio.git cd $FA_DIR fi - if [ ! -e "$LIB_INSTALL_PREFIX" ]; then - mkdir "$LIB_INSTALL_PREFIX" - fi - fcho "Please enter your password to install Filter_Audio:" + fcho "Installing filter_audio." make install PREFIX="${LIB_INSTALL_PREFIX}" # toxcore if [[ $TRAVIS = true ]]; then #travis check @@ -155,7 +156,9 @@ function install() { fcho "You can simply use the -u command and say [Yes/n] when prompted" fi fi - $QTOX_DIR/bootstrap-osx.sh + # put required by qTox libs/headers in `libs/` + cd "${QTOX_DIR}" + ./bootstrap-osx.sh } function update() { @@ -181,8 +184,7 @@ function update() { read -r -p "Did qTox update from git? [y/N] " response if [[ $response =~ ^([yY][eE][sS]|[yY])$ ]]; then fcho "Starting OSX bootstrap ..." - fcho "Sudo required:" - sudo bash ./bootstrap-osx.sh + ./bootstrap-osx.sh else fcho "Moving on!" fi From 3307855130a1a4fd285be85709ad26e384aa09b2 Mon Sep 17 00:00:00 2001 From: Zetok Zalbavar Date: Wed, 27 Jan 2016 19:06:32 +0000 Subject: [PATCH 186/210] travis build script: fix copyright date --- .travis/build-ubuntu_14_04.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis/build-ubuntu_14_04.sh b/.travis/build-ubuntu_14_04.sh index 95da5b4ed..db7b52427 100755 --- a/.travis/build-ubuntu_14_04.sh +++ b/.travis/build-ubuntu_14_04.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright © 2014-2015 by The qTox Project +# Copyright © 2015-2016 by The qTox Project # # This program is libre software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by From 53330daab739d5fec01e89639c1264354fbaccb9 Mon Sep 17 00:00:00 2001 From: sudden6 Date: Fri, 29 Jan 2016 23:30:07 +0100 Subject: [PATCH 187/210] toxme now supports proxies --- src/widget/form/addfriendform.cpp | 40 ++++++++++++++----------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/src/widget/form/addfriendform.cpp b/src/widget/form/addfriendform.cpp index 03d30c2bd..e5de57e48 100644 --- a/src/widget/form/addfriendform.cpp +++ b/src/widget/form/addfriendform.cpp @@ -109,29 +109,19 @@ void AddFriendForm::onSendTriggered() { QString id = toxId.text().trimmed(); - if (ToxId::isToxId(id)) + if (!ToxId::isToxId(id)) { - if (id.toUpper() == Core::getInstance()->getSelfId().toString().toUpper()) - GUI::showWarning(tr("Couldn't add friend"), tr("You can't add yourself as a friend!","When trying to add your own Tox ID as friend")); - else - emit friendRequested(id, getMessage()); - - this->toxId.clear(); - this->message.clear(); - } - else - { - if (Settings::getInstance().getProxyType() != ProxyType::ptNone) - { - QMessageBox::StandardButton btn = QMessageBox::warning(main, "qTox", tr("qTox needs to use the Tox DNS, but can't do it through a proxy.\n\ -Ignore the proxy and connect to the Internet directly?"), QMessageBox::Yes|QMessageBox::No, QMessageBox::No); - if (btn != QMessageBox::Yes) - return; - } - ToxId toxId = Toxme::lookup(id); // Try Toxme if (toxId.toString().isEmpty()) // If it isn't supported { + qDebug() << "Toxme didn't return a ToxID, trying ToxDNS"; + if (Settings::getInstance().getProxyType() != ProxyType::ptNone) + { + QMessageBox::StandardButton btn = QMessageBox::warning(main, "qTox", tr("qTox needs to use the Tox DNS, but can't do it through a proxy.\n\ + Ignore the proxy and connect to the Internet directly?"), QMessageBox::Yes|QMessageBox::No, QMessageBox::No); + if (btn != QMessageBox::Yes) + return; + } toxId = ToxDNS::resolveToxAddress(id, true); // Use ToxDNS if (toxId.toString().isEmpty()) { @@ -139,10 +129,16 @@ Ignore the proxy and connect to the Internet directly?"), QMessageBox::Yes|QMess return; } } - emit friendRequested(toxId.toString(), getMessage()); - this->toxId.clear(); - this->message.clear(); + id = toxId.toString(); } + + if (id.toUpper() == Core::getInstance()->getSelfId().toString().toUpper()) + GUI::showWarning(tr("Couldn't add friend"), tr("You can't add yourself as a friend!","When trying to add your own Tox ID as friend")); + else + emit friendRequested(id, getMessage()); + + this->toxId.clear(); + this->message.clear(); } void AddFriendForm::onIdChanged(const QString &id) From 25359d55b588b57ddd14d51f80a69def8597e99f Mon Sep 17 00:00:00 2001 From: sudden6 Date: Sat, 30 Jan 2016 00:15:14 +0100 Subject: [PATCH 188/210] Fix proxy set only after request sent. --- src/net/autoupdate.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/net/autoupdate.cpp b/src/net/autoupdate.cpp index fe40ea143..eb13952ea 100644 --- a/src/net/autoupdate.cpp +++ b/src/net/autoupdate.cpp @@ -107,8 +107,8 @@ AutoUpdater::VersionInfo AutoUpdater::getUpdateVersion() return versionInfo; QNetworkAccessManager *manager = new QNetworkAccessManager; - QNetworkReply* reply = manager->get(QNetworkRequest(QUrl(checkURI))); manager->setProxy(Settings::getInstance().getProxy()); + QNetworkReply* reply = manager->get(QNetworkRequest(QUrl(checkURI))); while (!reply->isFinished()) { if (abortFlag) @@ -222,8 +222,8 @@ QByteArray AutoUpdater::getUpdateFlist() QByteArray flist; QNetworkAccessManager *manager = new QNetworkAccessManager; - QNetworkReply* reply = manager->get(QNetworkRequest(QUrl(flistURI))); manager->setProxy(Settings::getInstance().getProxy()); + QNetworkReply* reply = manager->get(QNetworkRequest(QUrl(flistURI))); while (!reply->isFinished()) { if (abortFlag) From 0dae1a6af073c465839091f79674d6e61346018d Mon Sep 17 00:00:00 2001 From: Zetok Zalbavar Date: Sun, 31 Jan 2016 12:42:27 +0000 Subject: [PATCH 189/210] docs: put in INSTALL.md info about installing qTox from Arch repo thanks to @DX37 for the info in #2900 --- INSTALL.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index d92434a7d..264e15f00 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -78,10 +78,10 @@ There are available generic binaries for Linux:
#### Arch -**Please note that installing toxcore/qTox from AUR is not supported**, although installing other dependencies, provided that they met requirements, should be fine, unless you are installing cryptography library from AUR, which should rise red flags by itself… - -That being said, there are supported PKGBUILDs at https://github.com/Tox/arch-repo-tox - +PKGBUILD is available in the `community` repo, to install: +```bash +pacman -S qtox +``` #### Gentoo From 6d9551b1fd9d4ad3700944152e5d6d8c51de5c49 Mon Sep 17 00:00:00 2001 From: RowenStipe Date: Sun, 31 Jan 2016 11:25:38 -0500 Subject: [PATCH 190/210] Updated script to work on user machines and not just travis. --- osx/qTox-Mac-Deployer-ULTIMATE.sh | 39 +++++++++++++++++-------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/osx/qTox-Mac-Deployer-ULTIMATE.sh b/osx/qTox-Mac-Deployer-ULTIMATE.sh index 5a91cfc7f..b5d47a9a4 100755 --- a/osx/qTox-Mac-Deployer-ULTIMATE.sh +++ b/osx/qTox-Mac-Deployer-ULTIMATE.sh @@ -57,7 +57,7 @@ function fcho() { printf "\n$msg\n" "$@" } -function build-toxcore() { +function build_toxcore() { echo "Starting Toxcore build and install" cd $TOXCORE_DIR echo "Now working in: ${PWD}" @@ -81,13 +81,13 @@ function build-toxcore() { fcho "Compiling toxcore." make > /dev/null || exit 1 fcho "Installing toxcore." - make install > /dev/null || exit 1 + sudo make install > /dev/null || exit 1 } function install() { fcho "==============================" - fcho "This script will install the nessicarry applications and libraries needed to compile qTox properly." - fcho "Note that this is not a 100 percent automated install it just helps simplfiy the process for less experianced or lazy users." + fcho "This script will install the necessary applications and libraries needed to compile qTox properly." + fcho "Note that this is not a 100 percent automated install it just helps simplify the process for less experienced or lazy users." if [[ $TRAVIS = true ]]; then #travis check echo "Oh... It's just Travis...." else @@ -109,22 +109,24 @@ function install() { fi brew install git ffmpeg qrencode autoconf check qt5 libvpx opus sqlcipher libsodium - fcho "Installing x-code Comand line tools ..." + fcho "Installing x-code Command line tools ..." xcode-select --install fcho "Starting git repo checks ..." cd $MAIN_DIR # just in case + # Toxcore if [[ -e $TOX_DIR/.git/index ]]; then # Check if this exists - fcho "Toxcore git repo already inplace !" + fcho "Toxcore git repo already in place !" cd $TOX_DIR git pull else fcho "Cloning Toxcore git ... " git clone https://github.com/irungentoo/toxcore.git fi + # qTox if [[ -e $QTOX_DIR/.git/index ]]; then # Check if this exists - fcho "qTox git repo already inplace !" + fcho "qTox git repo already in place !" cd $QTOX_DIR git pull else @@ -133,7 +135,7 @@ function install() { fi # filter_audio if [[ -e $FA_DIR/.git/index ]]; then # Check if this exists - fcho "Filter_Audio git repo already inplace !" + fcho "Filter_Audio git repo already in place !" cd $FA_DIR git pull else @@ -142,10 +144,11 @@ function install() { cd $FA_DIR fi fcho "Installing filter_audio." - make install PREFIX="${LIB_INSTALL_PREFIX}" - # toxcore + sudo make install PREFIX="${LIB_INSTALL_PREFIX}" + + # toxcore build if [[ $TRAVIS = true ]]; then #travis check - build-toxcore + build_toxcore else fcho "If all went well you should now have all the tools needed to compile qTox!" read -r -p "Would you like to install toxcore now? [y/N] " response @@ -158,7 +161,7 @@ function install() { fi # put required by qTox libs/headers in `libs/` cd "${QTOX_DIR}" - ./bootstrap-osx.sh + sudo ./bootstrap-osx.sh } function update() { @@ -184,7 +187,7 @@ function update() { read -r -p "Did qTox update from git? [y/N] " response if [[ $response =~ ^([yY][eE][sS]|[yY])$ ]]; then fcho "Starting OSX bootstrap ..." - ./bootstrap-osx.sh + sudo ./bootstrap-osx.sh else fcho "Moving on!" fi @@ -247,17 +250,19 @@ if [[ "$1" == "-ubd" ]]; then fi if [[ "$1" == "-h" ]]; then - echo "This script was created to help ease the process of compiling and creating a distribuable qTox package for OSX systems." - echo "The avilable commands are:" + echo "This script was created to help ease the process of compiling and creating a distributable qTox package for OSX systems." + echo "The available commands are:" echo "-h -- This help text." echo "-i -- A slightly automated process for getting an OSX machine ready to build Toxcore and qTox." echo "-u -- Check for updates and build Toxcore from git & update qTox from git." echo "-b -- Builds qTox in: ${BUILD_DIR}" - echo "-d -- Makes a distributeable qTox.app file in: ${DEPLOY_DIR}" + echo "-d -- Makes a distributable qTox.app file in: ${DEPLOY_DIR}" echo "-ubd -- Does -u, -b, and -d sequentially" fcho "Issues with Toxcore or qTox should be reported to their respective repos: https://github.com/irungentoo/toxcore | https://github.com/tux3/qTox" exit 0 fi -fcho "Oh dear! You seemed to of started this script improperly! Use -h to get avilable commands and information!" +fcho "Oh dear! You seemed to of started this script improperly! Use -h to get available commands and information!" +echo " " +say -v Kathy -r 255 "Oh dear! You seemed to of started this script improperly! Use -h to get available commands and information!" exit 0 From fa5cd325edff9f7796ed8201605b38710b743271 Mon Sep 17 00:00:00 2001 From: RowenStipe Date: Sun, 31 Jan 2016 11:27:00 -0500 Subject: [PATCH 191/210] Updated Compiling instructions --- INSTALL.md | 84 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 61 insertions(+), 23 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index 264e15f00..ccbabb4f8 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -456,13 +456,51 @@ packages necessary for building .debs, so be prepared to type your password for ## OS X + Compiling qTox on OS X for development requires 3 tools, [Xcode](https://developer.apple.com/xcode/) and [Qt 5.4+](http://www.qt.io/qt5-4/), and [homebrew](http://brew.sh). -### Required Libraries +### Automated Script +You can now set up your OS X system to compile qTox automatically thanks to the script: +`./osx/qTox-Mac-Deployer-ULTIMATE.sh` + +This script can be run independently of the qTox repo and is all that's needed to build from scratch on OS X. + +To use this script you must launch terminal which can be found: `Applications > Utilities > Terminal.app` + +#### First Run / Install +If you are running the script for the first time you will want to makesure your system is ready. +To do this simply run `./qTox-Mac-Deployer-ULTIMATE.sh -i` to run you through the automated install set up. + +After running the installation setup you are now ready to build qTox from source, to do this simply run: +`./qTox-Mac-Deployer-ULTIMATE.sh -b` + +If there aren't any errors then you'll find a locally working qTox application in your home folder under +`~/qTox-Mac_Build` + +#### Updating +If you want to update your application for testing purposes or you want to run a nightly build setup then run: +`./qTox-Mac-Deployer-ULTIMATE.sh -u` and follow the prompts. +(NOTE: If you know you updated the repos before running this hit Y) +followed by +`./qTox-Mac-Deployer-ULTIMATE.sh -b` +to build the application once more. (NOTE: This will delete your previous build.) + +#### Deploying +OS X requires an extra step to make the `qTox.app` file shareable on a system that doesn't have the required libraries installed already. + +If you want to share the build you've made with your other friends who use OS X then simply run: +`./qTox-Mac-Deployer-ULTIMATE.sh -d` + +### Manual Compiling +#### Required Libraries +Install homebrew if you don't have it: +```bash +ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" +``` First, let's install the dependencies available via brew. ```bash -brew install git ffmpeg qrencode +brew install git ffmpeg qrencode libtool automake autoconf check qt5 libvpx opus sqlcipher libsodium ``` Next, install [filter_audio](https://github.com/irungentoo/filter_audio) (you may delete the directory it creates afterwards): @@ -473,6 +511,8 @@ sudo make install cd ../ ``` +Next, install [Toxcore](https://github.com/irungentoo/toxcore/blob/master/INSTALL.md#osx) + Then, clone qTox: ```bash git clone https://github.com/tux3/qTox`` @@ -480,38 +520,36 @@ git clone https://github.com/tux3/qTox`` Finally, copy all required files. Whenever you update your brew packages, you may skip all of the above steps and simply run the following commands: ```bash -cd qTox +cd ./git/qTox sudo bash bootstrap-osx.sh ``` -###Compiling +#### Compiling +You can build qTox with Qt Creator [seperate download](http://www.qt.io/download-open-source/#section-6) or you can hunt down the version of home brew qt5 your using in the `/usr/local/Cellar/qt5/` directory. +e.g. `/usr/local/Cellar/qt5/5.5.1_2/bin/qmake` with `5.5.1_2` being the version of Qt5 that's been installed. -Either open Qt creator and hit build or run ```qmake && make``` in your qTox folder and it'll just work™. - -Note that if you use the CLI to build you'll need to add Qt5's bins to your path. +With that; in your terminal you can compile qTox in the git dir: ```bash -export PATH=$PATH:~/Qt/5.4/clang_64/bin/ +/usr/local/Cellar/qt5/5.5.1_2/bin/qmake ./qtox.pro ``` -### Fixing things up - -The bad news is that Qt breaks our linker paths so we need to fix those. First cd in to your qtox.app directory, if you used Qt Creator it's in ```~/build-qtox-Desktop_Qt_5_4_1_clang_64bit-Release``` most likely, otherwise it's in your qTox folder. - -Install qTox so we can copy its libraries and shove the following in a script somewhere: - +Or a cleaner method would be to: ```bash -~macdeployqt qtox.app -cp -r /Applications/qtox.app qtox_old.app -cp qtox.app/Contents/MacOS/qtox qtox_old.app/Contents/MacOS/qtox -rm -rf qtox.app -mv qtox_old.app qtox.app +cd ./git/dir/qTox +mkdir ./build +cd build +/usr/local/Cellar/qt5/5.5.1_2/bin/qmake ../qtox.pro ``` -* Give it a name like ~/deploy.qtox.sh -* cd in to the folder with qtox.app -* run ```bash ~/deploy.qtox.sh``` +#### Deploying +If you compiled qTox properly you can now deploy the `qTox.app` that's created where you built qTox so you can distribute the package. -### Running qTox +Using your qt5 homebrew installation from the build directory: +```bash +/usr/local/Cellar/qt5/5.5.1_2/bin/macdeployqt ./qTox.app +``` + +#### Running qTox You've got 2 choices, either click on the qTox app that suddenly exists, or do the following: ```bash qtox.app/Contents/MacOS/qtox From 62e067903295c2a0cee46ca4b5d5d899cb0936bd Mon Sep 17 00:00:00 2001 From: RowenStipe Date: Sun, 31 Jan 2016 11:32:24 -0500 Subject: [PATCH 192/210] Quick changes for clarity --- INSTALL.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index ccbabb4f8..35a3243b5 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -460,13 +460,15 @@ packages necessary for building .debs, so be prepared to type your password for Compiling qTox on OS X for development requires 3 tools, [Xcode](https://developer.apple.com/xcode/) and [Qt 5.4+](http://www.qt.io/qt5-4/), and [homebrew](http://brew.sh). ### Automated Script -You can now set up your OS X system to compile qTox automatically thanks to the script: -`./osx/qTox-Mac-Deployer-ULTIMATE.sh` +You can now set up your OS X system to compile qTox automatically thanks to the script in: +`.dir/git/qTox/osx/qTox-Mac-Deployer-ULTIMATE.sh` This script can be run independently of the qTox repo and is all that's needed to build from scratch on OS X. To use this script you must launch terminal which can be found: `Applications > Utilities > Terminal.app` +If you wish to lean more you can run `./qTox-Mac-Deployer-ULTIMATE.sh -h` + #### First Run / Install If you are running the script for the first time you will want to makesure your system is ready. To do this simply run `./qTox-Mac-Deployer-ULTIMATE.sh -i` to run you through the automated install set up. From 0e9347cff1a0a0dd1f4d6691268f242102d247ae Mon Sep 17 00:00:00 2001 From: RowenStipe Date: Sun, 31 Jan 2016 11:39:58 -0500 Subject: [PATCH 193/210] Revert change --- INSTALL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/INSTALL.md b/INSTALL.md index 35a3243b5..a2d071816 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -461,7 +461,7 @@ Compiling qTox on OS X for development requires 3 tools, [Xcode](https://develop ### Automated Script You can now set up your OS X system to compile qTox automatically thanks to the script in: -`.dir/git/qTox/osx/qTox-Mac-Deployer-ULTIMATE.sh` +`./osx/qTox-Mac-Deployer-ULTIMATE.sh` This script can be run independently of the qTox repo and is all that's needed to build from scratch on OS X. From 6e1b7b3464002a2882361708291168cfadb94011 Mon Sep 17 00:00:00 2001 From: RowenStipe Date: Sun, 31 Jan 2016 12:16:19 -0500 Subject: [PATCH 194/210] Fix travis trying to pull qTox --- osx/qTox-Mac-Deployer-ULTIMATE.sh | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/osx/qTox-Mac-Deployer-ULTIMATE.sh b/osx/qTox-Mac-Deployer-ULTIMATE.sh index b5d47a9a4..c5a09fd18 100755 --- a/osx/qTox-Mac-Deployer-ULTIMATE.sh +++ b/osx/qTox-Mac-Deployer-ULTIMATE.sh @@ -125,13 +125,17 @@ function install() { git clone https://github.com/irungentoo/toxcore.git fi # qTox - if [[ -e $QTOX_DIR/.git/index ]]; then # Check if this exists - fcho "qTox git repo already in place !" - cd $QTOX_DIR - git pull + if [[ $TRAVIS = true ]]; then #travis check + fcho "Travis... You already have qTox..." else - fcho "Cloning qTox git ... " - git clone https://github.com/tux3/qTox.git + if [[ -e $QTOX_DIR/.git/index ]]; then # Check if this exists + fcho "qTox git repo already in place !" + cd $QTOX_DIR + git pull + else + fcho "Cloning qTox git ... " + git clone https://github.com/tux3/qTox.git + fi fi # filter_audio if [[ -e $FA_DIR/.git/index ]]; then # Check if this exists From d22b7cb1400f79919a95089c5b75984e43baee8c Mon Sep 17 00:00:00 2001 From: sudden6 Date: Sun, 31 Jan 2016 23:17:43 +0100 Subject: [PATCH 195/210] make qt version in about window copy paste able --- src/widget/form/settings/aboutsettings.ui | 29 ++++++++++++++++------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/widget/form/settings/aboutsettings.ui b/src/widget/form/settings/aboutsettings.ui index 054542e82..fde64a4af 100644 --- a/src/widget/form/settings/aboutsettings.ui +++ b/src/widget/form/settings/aboutsettings.ui @@ -29,9 +29,9 @@ 0 - 0 + -72 496 - 626 + 648 @@ -79,9 +79,17 @@ + + + Noto Sans + + Qt version: + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + @@ -196,6 +204,11 @@ 0 + + + Noto Sans + + Qt::NoFocus @@ -209,12 +222,12 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; color:#000000;">Copyright © 2014-2015 by The qTox Project</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu';">qTox is a Qt-based graphical interface for Tox.</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';">qTox is libre software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';">qTox is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. </span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu';">You should have received a copy of the GNU General Public License along with this program. If not, see </span><a href="https://www.gnu.org/copyleft/gpl.html"><span style=" font-family:'Ubuntu'; text-decoration: underline; color:#007af4;">https://www.gnu.org/copyleft/gpl.html</span></a><span style=" font-family:'Ubuntu';">.</span></p></body></html> +</style></head><body style=" font-family:'Noto Sans'; font-size:12pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:10pt; color:#000000;">Copyright © 2014-2015 by The qTox Project</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:10pt;">qTox is a Qt-based graphical interface for Tox.</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:10pt;">qTox is libre software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:10pt;">qTox is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. </span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:10pt;">You should have received a copy of the GNU General Public License along with this program. If not, see </span><a href="https://www.gnu.org/copyleft/gpl.html"><span style=" font-family:'Ubuntu'; font-size:10pt; text-decoration: underline; color:#007af4;">https://www.gnu.org/copyleft/gpl.html</span></a><span style=" font-family:'Ubuntu'; font-size:10pt;">.</span></p></body></html> From 26e9208a05e7474d137571e9075a584909ca6d36 Mon Sep 17 00:00:00 2001 From: Andrii Zymohliad Date: Thu, 4 Feb 2016 15:58:31 +0200 Subject: [PATCH 196/210] Almost full translation into Ukrainian --- translations/uk.ts | 2391 ++++++++++++++++---------------------------- 1 file changed, 885 insertions(+), 1506 deletions(-) diff --git a/translations/uk.ts b/translations/uk.ts index 44fe858cd..091a2d188 100644 --- a/translations/uk.ts +++ b/translations/uk.ts @@ -1,105 +1,88 @@ - + AVForm - Audio/Video Аудіо/Відео - - Initializing Camera... - Ініціалізація камери... + %1x%2 + + + + Default resolution + Роздільна здатність за замовчуванням + + + at %1 FPS + з %1 FPS + + + None + Відсутній AVSettings - - Playback - Відтворення - - - - Microphone - Мікрофон - - - Audio Settings Аудіо параметри - + Volume + Гучність + + Use slider to set volume of your speakers. Використовуйте повзунок для регулювання гучності пристрою відтворення. - - Use slider to set volume of your microphone. -WARNING: slider is not supposed to work yet. - + Gain + Підсилення + + + Use slider to set volume of your microphone. + Використовуйте повзунок для регулювання чутливості мікрофону. + + + Rescan devices + Пересканувати пристрої - Playback device Пристрій відтворення - + ... + + + Capture device Пристрій захоплення - - Rescan audio devices - Пересканувати аудіо пристрої - - - Filter audio Фільтр звуку - - - - - - - 100 - 100 - - - Filter sound from your microphone, so that people hearing you would get better sound. Фільтрація звуку вашого мікрофону для того, щоб люди краще вас чули. - - - - - - - 0 - 0 - - - Video Settings Параметри відео - + Video device + Відео пристрій + + Resolution Роздільна здатність - - Set resolution of your camera. The higher values, the better video quality your friends may get. Note though that with better video quality there is needed better internet connection. @@ -111,90 +94,208 @@ which may lead to problems with video calls. Іноді ваше інтернет з’єднання може бути недостатньо якісним для досить високої якості відео, що може спричинити проблеми під час відео зв’язку. + + + AboutForm - - Hue - Відтінок + Qt version: + Версія Qt: - - Brightness - Яскравість + Restart qTox to install version %1 + Перезапустіть qTox для встановлення версіїі %1 - - Saturation - Насиченість + qTox is downloading update %1 + %1 is the version of the update + qTox завантажує оновлення %1 - - Contrast - Контраст + About + Про програму + + + + AboutSettings + + Version + Версія + + + toxcore version: $TOXCOREVERSION + Версія toxcore: $TOXCOREVERSION + + + Qt version: + Версія Qt: + + + Commit hash: <a href="https://github.com/tux3/qTox/commit/$GIT_VERSION">$GIT_VERSION</a> + Хеш коміту: <a href="https://github.com/tux3/qTox/commit/$GIT_VERSION">$GIT_VERSION</a> + + + You are using qTox version $GIT_DESCRIBE. + Ви використовуєте qTox версії $GIT_DESCRIBE. + + + Downloading update: %p% + Завантаження оновлень: %p% + + + License + Ліцензія + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Noto Sans'; font-size:12pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:10pt; color:#000000;">Copyright © 2014-2015 by The qTox Project</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:10pt;">qTox is a Qt-based graphical interface for Tox.</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:10pt;">qTox is libre software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:10pt;">qTox is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. </span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:10pt;">You should have received a copy of the GNU General Public License along with this program. If not, see </span><a href="https://www.gnu.org/copyleft/gpl.html"><span style=" font-family:'Ubuntu'; font-size:10pt; text-decoration: underline; color:#007af4;">https://www.gnu.org/copyleft/gpl.html</span></a><span style=" font-family:'Ubuntu'; font-size:10pt;">.</span></p></body></html> + + + + Authors + Автори + + + <html><head/><body><p>Original author: <a href="https://github.com/tux3"><span style=" text-decoration: underline; color:#0000ff;">tux3</span></a></p><p>See a full list of <a href="https://github.com/tux3/qTox/graphs/contributors"><span style=" text-decoration: underline; color:#0000ff;">contributors</span></a> at Github</p></body></html> + <html><head/><body><p> Оригінальний автор: <a href="https://github.com/tux3"><span style=" text-decoration: underline; color:#0000ff;">tux3</span></a></p><p>Дивіться повний список <a href="https://github.com/tux3/qTox/graphs/contributors"><span style=" text-decoration: underline; color:#0000ff;">учасників</span></a> на Github</p></body></html> + + + Known Issues + Відомі проблеми + + + <html><head/><body><p>A list of all known issues may be found at our <a href="https://github.com/tux3/qTox/issues"><span style=" text-decoration: underline; color:#0000ff;">bug-tracker</span></a> at Github. If you discover a bug or security vulnerability within qTox, please report it according to the guidelines in our <a href="https://github.com/tux3/qTox/wiki/Writing-Useful-Bug-Reports"><span style=" text-decoration: underline; color:#0000ff;">Writing Useful Bug Reports</span></a> wiki article.</p></body></html> + <html><head/><body><p>Повний перелік відомих проблем можна переглянути на нашому <a href="https://github.com/tux3/qTox/issues"><span style=" text-decoration: underline; color:#0000ff;">баг-трекері</span></a> на Github. Якщо Ви знайшли баг чи вразливість в безпеці qTox, будь ласка, повідомте про це відповідно до вказівок нашої wiki-статті: <a href="https://github.com/tux3/qTox/wiki/Writing-Useful-Bug-Reports"><span style=" text-decoration: underline; color:#0000ff;">Writing Useful Bug Reports</span></a></p></body></html> + + + + AboutUser + + Dialog + Діалог + + + username + Ім'я користувача + + + status message + Статус + + + Public key: + Відкритий ключ: + + + Used aliases: + Використовуємі псевдоніми: + + + HISTORY OF ALIASES + ІСТОРІЯ ПСЕВДОНІМІВ + + + Default directory to save files: + To reduce string length it is also possible: "Каталог для збергіання файлів:", which means "Directory to save files" (withot default). + Каталог для зберігання файлів за замовчуванням: + + + Auto accept for this contact is disabled + To reduce string length it is also possible: +1) "Автоприйом файлів для цього контакту вимкнено". Where "Автоприйом" means the same as "Автоматичний прийом" but is not a dictionary word. +2) "Автоматичний прийом файлів вимкнено". Which means "auto accept files is disabled", without "for this contact". + Автоматичний прийом файлів для цього контакту вимкнено + + + Auto accept files + Автоматично приймати файли + + + Remove history (operation can not be undone!) + Видалити історію (операцію відмінити неможливо!) + + + Notes + Нотатки + + + You can save comment about this contact here. + Ви можете залишити коментар про даний контакт тут. + + + Choose an auto accept directory + popup title + I changed "Оберіть теку, для автоматичного отримання файлів" to "Оберіть каталог для автоматичного отримання файлів", because there is no need to put comma there and "Каталог" is more common word for "Directory" then "тека (теку)" + Оберіть каталог для автоматичного отримання файлів + + + History removed + Історію видалено + + + Chat history with %1 removed! + Історію переписки з %1 видалено! AddFriendForm - Add Friends Додати друзів - Tox ID Tox ID of the person you're sending a friend request to Tox ID - + qTox needs to use the Tox DNS, but can't do it through a proxy. + Ignore the proxy and connect to the Internet directly? + qTox повинен використовувати Tox DNS, але це неможливо через проксі. + Ігнорувати проксі та під'єднатись до Інтернету напряму? + + + either 76 hexadecimal characters or name@example.com + Tox ID format description + 76 шістнадцяткових цифр або name@example.com + + + Invalid Tox ID format + Некоректний формат Tox ID + + Message The message you send in friend requests Повідомлення - Send friend request Надіслати запит на дружбу - %1 here! Tox me maybe? Default message in friend requests if the field is left blank. Write something appropriate! - + That means "Hi, I'm %1! Please, add me to you contact list. +It's difficult to translate "Tox me maybe" because in Ukrainian noun can't mean a verb (like "call" for noun and verb in English) + Привіт, я %1! Додай мене в свій список контактів, будь ласка. + - Tox me maybe? - Default message in friend requests if the field is left blank. Write something appropriate! - Може поспілкуємось? - - - - Please fill in a valid Tox ID - Tox ID of the friend you're sending a friend request to - Введіть коректний Tox ID - - - - - Couldn't add friend Не можемо додати друга - You can't add yourself as a friend! When trying to add your own Tox ID as friend Ви не можете додати самого себе до друзів! - - qTox needs to use the Tox DNS, but can't do it through a proxy. -Ignore the proxy and connect to the Internet directly? - qTox потребує Tox DNS, але не може скористатися ним через проксі. -Проігнорувати проксі та під'єднатися напряму? - - - This Tox ID does not exist DNS error Даного Tox ID не існує @@ -203,362 +304,190 @@ Ignore the proxy and connect to the Internet directly? AdvancedForm - Advanced Додатково - - - FULL - very safe, slowest (recommended) - ПОВНА - найбезпечніше, але повільніше (рекомендується) - - - - NORMAL - almost as safe as FULL, about 20% faster than FULL - ЗВИЧАЙНА - менш безпечно, а ніж ПОВНА, але на 20% швидше - - - - OFF - disables all safety, when something goes wrong your history may be lost, fastest (not recommended) - ВІДСУТНЯ - вимкнені всі перевірки, якщо щось піде не так Вашу історію буде втрачено, найшвидша робота (не рекомендується) - AdvancedSettings - - Form - Form - - - Save settings to the working directory instead of the usual conf dir describes makeToxPortable checkbox Зберігати налаштування в робочій теці замість звичайної теки конфігурацій - Make Tox portable Портативний запуск Tox - <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">IMPORTANT NOTE</span></p><p><span style=" color:#ff0000;">Unless you </span><span style=" font-weight:600; color:#ff0000;">really</span><span style=" color:#ff0000;"> know what you are doing, please do </span><span style=" font-weight:600; color:#ff0000;">not</span><span style=" color:#ff0000;"> change anything here. Changes made here may lead to problems with qTox, and even to loss of your data, e.g. history.</span></p></body></html> <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">ВАЖЛИВЕ ЗАУВАЖЕННЯ</span></p><p><span style=" color:#ff0000;">Доки ви </span><span style=" font-weight:600; color:#ff0000;">дійсно</span><span style=" color:#ff0000;"> не зрозумієте, що робите, будь ласка, </span><span style=" font-weight:600; color:#ff0000;">не</span><span style=" color:#ff0000;"> змінюйте жодні параметри тут. Внесені зміни можуть викликати проблеми із qTox, і призвести до втрати Ваших даних, наприклад історії.</span></p></body></html> - Reset to default settings Скинути на типові значення - - - Chat history - Історія чату - - - - License - Ліцензія - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:10pt;">qTox is a Qt-based graphical interface for Tox.</span></p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Ubuntu'; font-size:10pt;"><br /></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:10pt;">This program is libre software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.</span></p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Ubuntu'; font-size:10pt;"><br /></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:10pt;">This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.</span></p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Ubuntu'; font-size:10pt;"><br /></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:10pt;">You should have received a copy of the GNU General Public License along with this program. If not, see </span><a href="https://www.gnu.org/copyleft/gpl.html"><span style=" font-family:'Ubuntu'; font-size:10pt; text-decoration: underline; color:#007af4;">https://www.gnu.org/copyleft/gpl.html</span></a><span style=" font-family:'Ubuntu'; font-size:10pt;">.</span></p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Ubuntu'; font-size:10pt;"><br /></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:10pt;">Author: </span><a href="https://github.com/tux3"><span style=" font-family:'Ubuntu'; font-size:10pt; text-decoration: underline; color:#007af4;">tux3</span></a></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:10pt;">Contributors: </span><a href="https://github.com/tux3/qTox/graphs/contributors"><span style=" font-family:'Ubuntu'; font-size:10pt; text-decoration: underline; color:#007af4;">see all on GitHub.com</span></a></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:10pt;">Known issues: </span><a href="https://github.com/tux3/qTox/issues"><span style=" font-family:'Ubuntu'; font-size:10pt; text-decoration: underline; color:#007af4;">see all on GitHub.com</span></a></p></body></html> - - - - History - Історія - - - - <html><head/><body><p><a href="http://www.sqlite.org/pragma.html#pragma_synchronous"><span style=" text-decoration: underline; color:#0000ff;">Synchronous writing to DB</span></a></p></body></html> - <html><head/><body><p><a href="http://www.sqlite.org/pragma.html#pragma_synchronous"><span style=" text-decoration: underline; color:#0000ff;">Синхронізація запису в БД</span></a></p></body></html> - Android - Form Form - qTox - Someone - Someone else - Groupbot - That guy who I don't remember adding - NASA manager - Lorem - Ipsum - Dolor - - Your name - Ваше ім'я - - - Your status - Ваш статус - - - Add friends - Додати друзів - - - Create a group chat - Створити груповий чат - - - View completed file transfers - Переглянути завершені передачі файлів - - - Change your settings - Змінити параметри - - - - AndroidGUI - - Online - Button to set your status to 'Online' - В мережі - - - Away - Button to set your status to 'Away' - Відійшов - - - Busy - Button to set your status to 'Busy' - Зайнятий - ChatForm - - Load History... - Завантажити історію… - Load chat history... Завантажити історію чату... - Send a file Надіслати файл - - - File not read - Файл не читається - - - - qTox wasn't able to open %1 qTox не може відкрити файл %1 - - - Bad Idea - Погана ідея - - - - You're trying to send a special (sequential) file, that's not going to work! Ви намагаєтесь передати спеціальний (послідовний) файл, це не так працює! - Accept video call Прийняти відеодзвінок - Accept audio call Прийняти аудіо дзвінок - %1 calling Дзвінок від %1 - - End video call Завершити відеодзвінок - - End audio call Завершити аудіодзвінок - - Mute microphone Вимкнути мікрофон - - Mute call (переклад може бути неточний) Призупинити дзвінок - %1 is calling - %1 дзвонить - - - - %1 stopped calling - %1 припинив виклик - - - Cancel video call Скинути відеодзвінок - Cancel audio call Скинути аудіодзвінок - - Calling to %1 - Викликаємо %1 + Unable to open + Неможливо відкрити + + + Bad idea + Погана ідея + + + Calling %1 + Дзінок до %1 - Start audio call Почати аудіодзвінок - Start video call Почати відеодзвінок - Unmute microphone Увімкнути мікрофон - Unmute call (переклад може бути неточний) Відновити дзвінок - Failed to send file "%1" Не вдалось відправити файл «%1» - Failed to open temporary file Temporary file for screenshot Помилка під час відкриття тимчасового файлу - qTox wasn't able to save the screenshot qTox не може зберегти снімок екрану - Call with %1 ended. %2 Виклик із %1 завершено. %2 - Call duration: Тривалість дзвінка: - - is typing... - набирає... - - - - Call rejected - Дзвінок відхилено - ChatLog - Copy Копіювати - Select all Виділити всі - pending очікування @@ -566,375 +495,250 @@ p, li { white-space: pre-wrap; } ChatTextEdit - Type your message here... Наберіть Ваше повідомлення тут… + + CircleWidget + + Rename circle + Menu for renaming a circle + Перейменувати коло + + + Remove circle + Menu for removing a circle + Видалити коло + + + Open all in new window + Відкрити всі в новому вікні + + Core - Toxing on qTox Вітання з qTox - - qTox User - Користувач qTox - - - You need to write a message with your request Напишіть повідомлення з вашим запитом - Your message is too long! Ваше повідомлення завелике! - Friend is already added Друга вже додано - /me offers friendship. - /me offers friendship, "%1" - - - Profile already in use - Профіль вже використовується - - - - - This profile is already used by another qTox instance -Please select another profile - - - - - Encryption error - Помилка шифрування - - - - The .tox file is encrypted, but encryption was not checked, continuing regardless. - Файл .tox зашифровано, але шифрування не перевірено, попри це продовжуємо. - - - - Please enter the password for the %1 profile. - used in load() when no pw is already set - Будь-ласка, введіть пароль для профілю %1. - - - - The previous password is incorrect; please try again: used on retries in load() можливо, не "попередній", а "перший" Попередній пароль неправильний; спробуйте ще раз: - - The profile password failed. Please try another? - used only when pw set before load() doesn't work - - - - Encrypted chat history Зашифрована історія - No encrypted chat history file found, or it was corrupted. History will be disabled! Не знайдено зашифрованої історії чату або вона була пошкоджена. Історія чату буде вимкнена! - - Please enter the password for the chat history for the %1 profile. + Please enter the password for the chat history for the profile "%1". used in load() when no hist pw set - Будь-ласка, введіть пароль для історії чату з профілю %1. + Будь ласка, введіть пароль для історії переписки для профілю "%1". - Disabling chat history now will leave the encrypted history intact (but not usable); if you later remember the password, you may re-enable encryption from the Privacy tab with the correct password to use the history. part of history password dialog - The chat history password failed. Please try another? used only when pw set before load() doesn't work Щось не так з паролем для історії чату. Спробуйте інший? - Disable chat history Вимкнути історію чату - - - Local file encryption is enabled, but there is no password! It will be disabled. - - - - Tox datafile decryption password - Розшифрування файлу даних Tox - - - Password error - Помилка паролю - - - Failed to setup password. -Empty password. - Не вдалось встановити пароль. -Пароль пустий. - - - Try Again - Спробуйте ще раз - - - - Change profile - Змінити профіль - - - Reinit current profile - Пере ініціалізувати поточний профіль - - - Wrong password has been entered - Введено хибний пароль - - - History Log decryption password - Розшифрування історії - - - Your history is encrypted with different password. -Do you want to try another password? - Ваша історія зашифрована інакшим паролем. -Бажаєте спробувати інший пароль? - - - History - Історія - - - Due to incorret password history will be disabled. - Введено некоректний пароль, звітування вимкнено. - - - Encrypted log - Зашифрований звіт - - - - NO Password - Відсутній пароль - - - Will be saved without encryption! - Буде збережено без шифрування! - - - - FileTransferInstance - - Save a file - Title of the file saving dialog - Зберегти файл - - - Location not writable - Title of permissions popup - Немає прав на запис - - - You do not have permission to write that location. Choose another, or cancel the save dialog. - text of permissions popup - Ви не маєте прав на запис за цим розташуванням. Оберіть інше місце призначення, або скасуйте передачу. - - - ETA - РЧЗ - FileTransferWidget - Form - Form + Form - 10Mb - + 10МБ - 0kb/s - + 0кБ/с - ETA:10:10 - Filename - + Назва файлу - [preview] - Waiting to send... file transfer widget - + Очікування передачі... - Accept to receive this file file transfer widget - + Підтвердіть щоб прийняти файл - Location not writable Title of permissions popup - Немає прав на запис + Немає прав на запис - You do not have permission to write that location. Choose another, or cancel the save dialog. text of permissions popup - Ви не маєте прав на запис за цим розташуванням. Оберіть інше місце призначення, або скасуйте передачу. + Ви не маєте прав на запис за цим розташуванням. Оберіть інше місце призначення, або скасуйте передачу. - - paused - file transfer widget - - - - Resuming... file transfer widget - + Продовження... - - Open file. - - - - - Open file directory. - - - - - - Cancel transfer - + Скасувати передачу - - Pause transfer - + Призупинити передачу + + + Paused + file transfer widget + Призупинено + + + Open file + Відкрити файл + + + Open file directory + Відкрити каталог з файлом - Resume transfer - + Продовжити передачу - Accept transfer - + Підтвердити передачу - Save a file Title of the file saving dialog - Зберегти файл + Зберегти файл FilesForm - - Transfered Files + Transferred Files "Headline" of the window Передані файли - Downloads Завантажені - Uploads Вивантажені + + FriendListWidget + + Today + Category for sorting friends by activity + Сьогодні + + + Yesterday + Category for sorting friends by activity + Вчора + + + Last 7 days + Category for sorting friends by activity + Останні 7 днів + + + This month + Category for sorting friends by activity + Цього місяця + + + Older than 6 Months + Category for sorting friends by activity + Раніше 6 місяців + + + Unknown + Category for sorting friends by activity + Невідомо + + FriendRequestDialog - Friend request Title of the window to aceept/deny a friend request Запит на дружбу - Someone wants to make friends with you Дехто хоче долучитися до переліку ваших друзів - User ID: ID користувача: - Friend request message: Повідомлення запиту: - Accept Accept a friend request Прийняти - Reject Reject a friend request Відхилити @@ -943,73 +747,74 @@ Do you want to try another password? FriendWidget - Invite to group Menu to invite a friend to a groupchat Запросити до групи - - Copy friend ID - Menu to copy the Tox ID of that friend - Копіювати дружній ID + Open chat in new window + Відкрити чат в новому вікні + + + Remove chat from this window + Видалити чат з цього вікна + + + Move to circle... + Menu to move a friend into a different circle + Перемістити в коло... + + + To new circle + До нового кола + + + Remove from circle '%1' + Видалити з кола '%1' + + + Move to circle "%1" + Перемістити в коло "%1" - Set alias... Встановити псевдонім… - Auto accept files from this friend context menu entry Автоматично приймати файли від даного друга - - New message - + Show details + Показати деталі + + + New message + Нове повідомлення - Online В мережі - Away Відійшов - Busy Зайнятий - Offline Не в мережі - - User alias - Псевдонім користувача - - - - You can also set this by clicking the chat form name. -Alias: - Ви також можете встановити його натиснувши на назву форми в чаті. -Псевдонім: - - - Choose an auto accept directory popup title Оберіть теку, для автоматичного отримання файлів - Remove friend Menu to remove the friend from our friendlist Вилучити з друзів @@ -1018,17 +823,14 @@ Alias: GUI - Enter your password Введіть ваш пароль - Decrypt Розшифрувати - You must enter a non-empty password: Введіть непустий пароль: @@ -1036,30 +838,24 @@ Alias: GeneralForm - General Основні - - None Відсутній - Choose an auto accept directory popup title Оберіть теку, для автоматичного отримання файлів - Call active popup title Дзвінок активний - You can't disconnect while a call is active! popup text Ви не можете від'єднатись під час активного дзвінка! @@ -1068,227 +864,159 @@ Alias: GeneralSettings - General Settings Основні параметри - - The translation may not load until qTox restarts. Переклад буде застосовано після перезавантаження qTox. - Save settings to the working directory instead of the usual conf dir - describes makeToxPortable checkbox - Зберігати налаштування в робочий теці - - - Make Tox portable - Портативний запуск - - - System tray integration - Інтеграція із системним лотком - - - Show system tray icon Показувати піктограму в системному лотку - Enable light tray icon. toolTip for light icon setting Увімкнути світлі піктограми. - + Start qTox on operating system startup (current profile). + Запускти qTox при завантаженні операційної системи (поточний профіль). + + qTox will start minimized in tray. toolTip for Start in tray setting qTox буде запускатися згорнутим в лоток. - Start in tray Запускати у системному лотку - After pressing close (X) qTox will minimize to tray, instead of closing itself. toolTip for close to tray setting При дії закриття (X) qTox буде згортатися до лотку, замість виходу з програми. - Close to tray Закривати до лотку - After pressing minimize (_) qTox will minimize itself to tray, instead of system taskbar. toolTip for minimize to tray setting При дії згортання (_) qTox буде згортатися до лотку, замість панелі задач. - Minimize to tray Мінімізувати до лотку - - <html><head/><body><p>Start qTox on operating system startup (current profile).</p></body></html> - <html><body><p>Запускати qTox при завантаженні системи (поточний профіль)</p></body></html> - - - Autostart Автозапуск - Check for updates on startup Перевіряти оновлення під час запуску - - Autoaccept and save files: - - - - Set where files will be saved. Вкажіть, куди саме зберігати файли. - Save to: - Зберігати в: - - - Your status is changed to Away after set period of inactivity. Ваш статус буде змінено на 'Відійшов' після вказаного проміжку часу. - Auto away after (0 to disable): Автостатус 'Відійшов' після (0, щоб вимкнути): - + Default directory to save files: + Каталог для зберігання файлів за замовчуванням: + + Chat Чат - + Open qTox's window when you receive a new message and no window is open yet. + tooltip for Show window setting + Відкривати вікно qTox при отриманні нового повідомлення, якщо вікно qTox ще не відкрите. + + + Open window + Відкрити вікно + + Always notify about new messages in groupchats. toolTip for Group chat always notify Завжди повідомляти про нові повідомлення у групових чатах. - Group chats always notify Постійні повідомлення з групових чатів - Show contacts' status changes Показувати зміну статусів контактів - Play a sound when you recieve message. toolTip for Notify sound setting - + Відтворювати звук при отриманні повідомлення. - Play sound Відтворювати звук - Messages you are trying to send to your friends when they are not online will be sent to them when they appear online to you. toolTip for Faux offline messaging setting - + Повідомлення, які Ви намагаєтесь відправити друзям, які зараз не в мережі, будуть відправлені їм, коли вони з'являться в мережі (одночасно з Вами). - If checked, groupchats will be placed at the top of the friends list, otherwise, they'll be placed below online friends. toolTip for groupchat positioning Групові чати будуть зверху в списку контактів. - Place groupchats at top of friend list Групові чати на початку - Date format: Формат дати: - Proxy type: Тип проксі: - Address: Text on proxy addr label Адреса проксі: - Provided in minutes - Встановлено в хвилинах - - - Set to 0 to disable Встановіть 0, аби вимкнути - - minutes - хвилин - - - Theme Графічна тема - Translation - Мова інтерфейсу - - - Light icon Світлі піктограми - Check for updates on startup (unstable) - Перевіряти оновлення під час запуску (нестабільна функція) - - - Focus qTox when a message is received - Перехоплювати фокус вікна при отриманні повідомлення - - - Faux offline messaging Фальшивий поза мережевий обмін повідомленнями - Auto away after (0 to disable) - Авто-статус «Відійшов» (0=вимкнено) - - - You can set this on a per-friend basis by right clicking them. autoaccept cb tooltip Ви також можете встановити це значення до кожного друга окремо викликавши правою кнопкою меню навпроти нього. @@ -1298,177 +1026,105 @@ will be sent to them when they appear online to you. Автоматично приймати файли - Save files in - Зберігати файли до - - - PushButton - Тисніть кнопку - - - Use emoticons Використовувати смайлики - Smiley Pack - Text on smiley pack label - Пакунок смайликів - - - Style - Стиль - - - Theme color - Колір графічної теми - - - Emoticon size - Розмір смайликів - - - px px - Timestamp format - Формати часового відбитку - - - Connection Settings Параметри підключення - Enable IPv6 (recommended) Text on a checkbox to enable IPv6 Дозволити IPv6 (рекомендовано) - Disabling this allows, e.g., toxing over Tor. It adds load to the Tox network however, so uncheck only when necessary. force tcp checkbox tooltip - + Вимкнення цього дозволить, наприклад, використовувати qTox через Tor. Проте це збільшить навантаження на мережу Tox, то ж вимикайте лише в разі необхідності. - Language: Мова: - - System tray - Системний лоток - - - On new message: За нового повідомлення: - - Show qTox's window when you receive new message. - tooltip for Show window setting - - - - - Show window - Показати вікно - - - Focus qTox when you receive message. toolTip for Focus window setting - + Фокусувати вікно qTox при отриманні повідомлення. - Focus window Фокусувати вікно - Your contact list will be shown in compact mode. toolTip for compact layout setting - + Ваш перелік контактів відображатиметься в компактному режимі. - Compact contact list Компактний список контактів - + Multiple windows mode + Багатовіконний режим + + + Open each chat in an individual window + Відкривати кожен чат в окремому вікні + + Smiley Pack: Text on smiley pack label Набір смайлів: - Emoticon size: Розмір смайлів: - Style: Стиль: - Theme color: Графічна тема: - Timestamp format: Формат часу: - Enable UDP (recommended) Text on checkbox to disable UDP Дозволити UDP (рекомендовано) - Proxy type - Тип проксі + Port: + Text on proxy port label + Порт: - None Відсутній - SOCKS5 SOCKS5 - HTTP HTTP - Use proxy (SOCKS5) - Використовувати проксі (SOCKS5) - - - Address - Text on proxy addr label - Адреса - - - - Port - Text on proxy port label - Порт - - - Reconnect reconnect button Повторно під'єднатись @@ -1477,116 +1133,110 @@ will be sent to them when they appear online to you. GenericChatForm - Send message Відправити повідомлення - Smileys Смайлики - Send file(s) Відправити файл(и) - Audio call: RED means you're on a call - Аудіо дзвінок: Червоний - дзвінок активний - - - Video call: RED means you're on a call - Відео дзвінок: Червоний - дзвінок активний - - - Toggle speakers volume: RED is OFF - Перемкнути стан гучності відтворення: Червоний - вимкнено - - - Toggle microphone: RED is OFF - Перемкнути рівень підсилення мікрофону: Червоний - вимкнено - - - Send a screenshot Відправити знімок екрану - - Start an audio call - Почати аудіодзвінок - - - - Start a video call - Почати відеодзвінок - - - - Save chat log Зберегти чат - + Start audio call + Почати аудіодзвінок + + + Accept audio call + Прийняти аудіо дзвінок + + + End audio call + Завершити аудіодзвінок + + + Start video call + Почати відеодзвінок + + + Accept video call + Прийняти відеодзвінок + + + End video call + Завершити відеодзвінок + + Clear displayed messages Очистити показані повідомлення - Not sent Не відправлено - Cleared Очищено + + GenericNetCamView + + Tox video + Tox відео + + + Show Messages + Показати повідомлення + + + Hide Messages + Приховати повідомлення + + GroupChatForm - %1 users in chat Number of users in chat Користувачів у чаті: %1 - - %1 users in chat - Користувачів у чаті: %1 + 1 user in chat + Number of users in chat + 1 користувач в чаті - - Start audio call Почати аудіодзвінок - - Mute microphone Вимкнути мікрофон - Unmute microphone Увімкнути мікрофон - - Mute call Призупинити дзвінок - Unmute call Відновити дзвінок - End audio call Завершити аудіодзвінок @@ -1594,806 +1244,522 @@ will be sent to them when they appear online to you. GroupWidget - - + Open chat in new window + Відкрити чат в новому вікні + + + Remove chat from this window + Видалити чат з цього вікна + + + 1 user in chat + 1 користувач в чаті + + %1 users in chat Користувачів у чаті: %1 - - - 0 users in chat - Немає користувачів - - - Quit group Menu to quit a groupchat Вийти з групи - Set title... Встановити заголовок… - - - Group title - Заголовок групи - - - - You can also set this by clicking the chat form name. -Title: - Ви також можете встановити його натиснувши на назву форми в чаті. -Заголовок: - - - - IdentityForm - - Identity - Ідентифікація - - - Call active - popup title - Дзвінок активний - - - You can't switch profiles while a call is active! - popup text - Ви не можете перемикати профіль під час активного дзвінка! - - - Rename "%1" - renaming a profile - Перейменувати «%1» - - - Profile already exists - rename confirm title - Профіль вже існує - - - A profile named "%1" already exists. Do you want to erase it? - rename confirm text - Профіль із назвою «%1» вже існує. Бажаєте стерти його? - - - Export profile - save dialog title - Експорт профілю - - - Tox save file (*.tox) - save dialog filter - Файл збереження Tox (*.tox) - - - Failed to remove file - Не вдалось вилучити файл - - - The file you chose to overwrite could not be removed first. - Неможливо вилучити файл, який ви обрали для перезапису. - - - Failed to copy file - На вдалось скопіювати файл - - - The file you chose could not be written to. - Неможливо записати в файл, який ви обрали. - - - Profile currently loaded - current profile deletion warning title - Поточний профіль завантажено - - - This profile is currently in use. Please load a different profile before deleting this one. - current profile deletion warning text - Даний профіль зараз використовується. Завантажте інший, парад вилученням поточного профілю. - - - Deletion imminent! - deletion confirmation title - Небезпечне вилучення! - - - Are you sure you want to delete this profile? -Associated friend information and chat logs will be deleted as well. - deletion confirmation text - Дійсно вилучити даний профіль? -Пов'язана інформація про друзів та історія спілкування також буде вилучена. - - - Import profile - import dialog title - Імпортувати профіль - - - Tox save file (*.tox) - import dialog filter - Файл збереження Tox (*.tox) - - - Ignoring non-Tox file - popup title - Ігнорування не Tox файлу - - - Warning: you've chosen a file that is not a Tox save file; ignoring. - popup text - Увага: вказаний вами файл не є файлом збереження Tox; ігнорую. - - - Profile already exists - import confirm title - Профіль вже існує - - - A profile named "%1" already exists. Do you want to erase it? - import confirm text - Профіль із назвою «%1» вже існує. Бажаєте стерти його? - IdentitySettings - Public Information Публічна інформація - Name - Ім'я - - - Status - Статус - - - Tox ID Tox ID - - This bunch of characters tells other Tox clients how to contact you. Share it with your friends to communicate. Tox ID tooltip - + Цей набір символів дозволяє клієнтам Tox зв'язатись з Вами. Для комунікації поділіться ним з своїм друзями. - Your Tox ID (click to copy) Ваш Tox ID (клацніть аби скопіювати) - - QRCODE - QR код + Profile + Профіль + + + <p><a href="file:///Dir_Path"><span style=" text-decoration: NONE; color:#000000;">Current profile location: Dir_Path</span></a></p> + <p><a href="file:///Dir_Path"><span style=" text-decoration: NONE; color:#000000;">Поточне місцезнаходження файлів профілю: Dir_Path</span></a></p> + + + Rename profile. + tooltip for renaming profile button + Перейменувати профіль. + + + Delete profile. + delete profile button tooltip + Видалити профіль. + + + Go back to the login screen + tooltip for logout button + Повернутись до екрану входу + + + Logout + import profile button + Вийти з облікового запису + + + Remove password + Видалити пароль + + + Change password + Змінити пароль - This QR code contains your Tox ID. You may share this with your friends as well. Цей QR код містить ваш Tox ID. Ви можете ділитися ним зі своїми друзями. - Save image Зберегти зображення - Copy image Копіювати зображення - - Profiles - Профілі - - - - Available profiles: - Доступні профілі: - - - - Currently selected profile. - toolTip for currently set profile - - - - - Load selected profile and switch to it. - tooltip for loading profile button - - - - - Load - load profile button - Завантажити - - - Switching profiles is disabled during calls - tooltip - Перемикання профілю заблоковано під час дзвінків - - - Rename rename profile button Перейменувати - - Rename selected profile. - tooltip for renaming profile button - Перейменування вибраного профілю. - - - Export export profile button Експорт - Allows you to export your Tox profile to a file. Profile does not contain your history. tooltip for profile exporting button - + Дозволяє Вами експортувати ваш профіль Tox в файл. Профіль не містить Вашу історію переписки. - Name: Ім'я: - Status: Статус: - - Delete selected profile. - delete profile button tooltip - Видалення вибраного профілю. - - - Delete delete profile button Вилучити - - This is useful to remain safe on public computers - delete profile button tooltip - Це стає в нагоді, при користуванні публічними комп'ютерами - - - - Import a profile - import profile button - Імпортувати профіль - - - - Import Tox profile from a .tox file. - tooltip for importing profile button - Імпортувати профіль з .tox файлу. - - - - Create new Tox ID and switch to it. - tooltip for creating new Tox ID button - - - - - New Tox ID - new profile button - Новий Tox ID - - - - InputPasswordDialog - - Password Dialog - Пароль - - - Input password: - Введіть пароль: - LoadHistoryDialog - Load History Dialog Історія - Load history from: Завантажити історію від: + + LoginScreen + + Username: + Ім'я користувача: + + + Password: + Пароль: + + + Confirm: + Підтвердження: + + + Password strength: %p% + Надійність пароля: %p% + + + Create Profile + Створити профіль + + + If the profile does not have a password, qTox can skip the login screen + Якщо пароль профілю не задано, qTox може пропускати екран входу + + + Load automatically + "Завантажувати" is exact translation of English "Load", which is a synonym for "Download" in Ukrainian. +So I think in this case more appropriate is "Входити автоматично", which means "Log in automatically". + Завантажувати автоматично + + + Load + "Завантажити" is exact translation of English "Load", which is a synonym for "Download" in Ukrainian. +So I think in this case more appropriate is "Увійти", which means "Log in". + Завантажити + + + New Profile + I think that more appropriate is "Новий обліковий запис", but this string is too long. + Новий профіль + + + Load Profile + I think that more appropriate is "Завантажити обліковий запис", but this string is too long. + Завантажити профіль + + + Couldn't create a new profile + Неможливо створити новий профіль + + + The username must not be empty. + Ім'я користувача не може бути пустим. + + + The password must be at least 6 characters long. + Пароль повинен містити щонайменше 6 символів. + + + The passwords you've entered are different. +Please make sure to enter same password twice. + Паролі, які Ви ввели, не співпадають. +Переконайтесь, що ввели однаковий пароль двічі. + + + A profile with this name already exists. + Профіль з таким іменем уже існує. + + + Unknown error: Couldn't create a new profile. +If you encountered this error, please report it. + Невідома помилка: Неможливо створити новий профіль. Якщо Ви зустріли цю помилку, будь ласка, повідомте про це. + + + Password protected profile can't be loaded automatically. + Профіль, захищений паролем, не може бути завантажений автоматично. + + + Couldn't load profile + Неможливо завантажити профіль + + + There is no selected profile. + +You may want to create one. + Не обрано жодного профілю. + +Можливо, Ви б хотіли створити його. + + + Couldn't load this profile + Неможливо завантажити даний профіль + + + This profile is already in use. + Цей профіль вже використовується. + + + Profile already in use. Close other clients. + Профіль вже використовується. Закрийте інші клієнти. + + + Wrong password. + Неправильний пароль. + + MainWindow - Your name Ваше ім'я - Your status Ваш статус - + ... + + + Add friends Додати друзів - Create a group chat Створити груповий чат - View completed file transfers Переглянути завершені передачі файлів - Change your settings Змінити параметри - Close Закрити - - NetCamView - - - Tox video - Tox Відео - - Nexus - Images (%1) filetype filter Зображення (%1) + + View + OS X Menu bar + Вигляд + + + Window + OS X Menu bar + Вікно + + + Minimize + OS X Menu bar + Мінімізувати + + + Bring All to Front + OS X Menu bar + + + + Exit Fullscreen + Вимкнути повноекранний режим + + + Enter Fullscreen + Увімкнути повноекранний режим + + + + NotificationEdgeWidget + + Unread message(s) + + %n непрочитане повідомлення + %n непрочитаних повідомлень + %n непрочитаних повідомлень + + PrivacyForm - Privacy Приватність - - Please set your new chat history password. - Встановіть новий пароль для історії чату. + Confirmation + Підтвердження - - It appears you have an unused encrypted chat history; if the password matches, it will be added to your current history. - Здається, у вас вже є зашифрована історія чату; якщо пароль співпаде, вона буде додана до поточної історії. - - - - Use data file password - pushbutton text - Введіть пароль файлу даних - - - - Successfully decrypted old chat history - popup title - Стара історія чату успішно розшифрована - - - - You have succesfully decrypted the old chat history, and it has been added to your current history and re-encrypted. - popup text - Стара історія була успішно розшифрована, додана до поточної історії та знову зашифрована. - - - - - Old encrypted chat history - popup title - Стара зашифрована історія - - - - There is currently an unused encrypted chat history, but the password you just entered doesn't match. - -If you don't care about the old history, you may delete it and use the password you just entered. -Otherwise, hit Cancel to try again. - This happens when enabling encryption after previously "Disabling History" - - - - - - - - Delete - Вилучити - - - - - - - - Cancel - Скасувати - - - - Are you absolutely sure you want to lose the unused encrypted chat history? - secondary popup - Ви точно впевнені, що хочете втратити невикористовувану та зашифровану історію чату? - - - - - Old encrypted chat history - title - Стара зашифрована історія - - - - Would you like to decrypt your chat history? -Otherwise it will be deleted. - Ви хочете розшифрувати історію чату? -Інакше вона буде видалена. - - - - - Decrypt - Розшифрувати - - - - Are you sure you want to lose your entire chat history? - Ви впевнені, що хочете втратити всю історію чату? - - - - Please set your new data file password. - Встановіть новий пароль для файлу даних. - - - - Use chat history password - pushbutton text - Введіть пароль історії чату - - - - Decrypt your data file - title - Розшифрувати файл даних - - - - Would you like to decrypt your data file? - Ви хочете розшифрувати ваш файл даних? - - - Encrypted log - Зашифрований звіт - - - You already have history log file encrypted with different password -Do you want to delete old history file? - Ви вже маєте зашифрований файл історії іншим паролем -Бажаєте вилучити старий файл історії? + Do you want to permanently delete all chat history? + PrivacySettings - Typing Notification - Увімкнути сповіщення про набір - - - Your friends will be able to see when you are typing. tooltip for typing notifications setting Ваші друзі зможуть побачити, коли ви друкуєте. - - Send Typing Notifications - Надсилати сповіщення про набір + Send typing notifications + Відправляти сповіщення набирання повідомлення + + + Keep chat history + Зберігати історію переписки + + + NoSpam is part of your Tox ID. +If you are being spammed with friend requests, you should change your NoSpam. +People will be unable to add you with your old ID, but you will keep your current friends. + toolTip for nospam + NoSpam - це частина Вашого Tox ID. +Якщо Ви отримуєте багато небажаних запитів дружби, то Вам потрібно змінити NoSpam. +Люди не зможуть додавати Вас за вашим старим ID, але ваші поточні друзі збережуться. + + + NoSpam + NoSpam + + + NoSpam is a part of your ID that can be changed at will. +If you are getting spammed with friend requests, change the NoSpam. + NoSpam - це частина Вашого ID, що може бути змінена за бажанням. +Якщо Вас спамлять запитами дружби, змініть NoSpam. + + + Generate random NoSpam + Згенерувати випадковий NoSpam - Chat history keeping is still in development. Save format changes are possible, which may result in data loss. toolTip for Keep History setting - - - - - Keep chat history (mostly stable) - Зберігати історію чату - - - - Local file encryption - Шифрування локальних файлів - - - - All Tox communications over the internet are encrypted, and this cannot be disabled. However, you may optionally password protect your local Tox files. - Всі комунікації через Tox в інтернеті зашифровані і це неможливо змінити. Ви також можете зашифрувати локальні Tox файли. - - - - Encrypt Tox data file - Шифрувати файл даних Tox - - - - - Change password - Змінити пароль - - - - Encrypt chat history - Шифрувати історію чату - - - - Nospam is part of your Tox ID. -It is there to help you change your Tox ID when you feel like you are getting too much spam friend requests. -When you change nospam, your current contacts still can communicate with you, -but new contacts need to know your new Tox ID to be able to add you. - toolTip for nospam - - - - Keep History (unstable) - Лишати історію (нестабільна функція) - - - Encryption - Шифрування - - - Encrypt Tox datafile - Шифрувати файл даних Tox - - - Encrypt History - Шифрувати історію - - - - Nospam - Nospam - - - HHHHHHHH - HHHHHHHH - - - - Generate random nospam - Генерувати випадковий «nospam» + Зберігання історії переписки поки що в розробці. +Можлива зміна формату зберігання, що може призвести до втрати даних. ProfileForm - Choose a profile picture Оберіть зображення для профілю - - - Error Помилка - Unable to open this file - Неможливо відкрити цей файл - - - Unable to read this image - Неможливо прочитати це зображення - - - Unable to open this file. Неможливо відкрити цей файл. - Unable to read this image. Неможливо прочитати це зображення. - The supplied image is too large. Please use another image. Зображення завелике. Виберіть інше, будь ласка. - - Call active - popup title - Дзвінок активний - - - - You can't switch profiles while a call is active! - popup text - Ви не можете перемикати профіль під час активного дзвінка! - - - Rename "%1" renaming a profile Перейменувати «%1» - + Current profile: + Поточний профіль: + + + Remove + Видалити + + Profile already exists - rename confirm title + rename failure title Профіль вже існує - - A profile named "%1" already exists. Do you want to erase it? + A profile named "%1" already exists. rename confirm text - Профіль "%1" вже існує. Ви хочете його стерти? + Профіль з іменем користувача "%1" вже існує. - - Profile already exists + Failed to rename rename failed title - Профіль вже існує + Помилка перейменування - - A profile named "%1" already exists and is in use. - Профіль "%1" вже існує та використовується. + Couldn't rename the profile to "%1" + Неможливо перейменувати профіль в "%1" - Export profile save dialog title Експорт профілю - Tox save file (*.tox) save dialog filter Файл Tox (*.tox) - - Location not writable Title of permissions popup - Немає прав на запис + Немає прав на запис - - You do not have permission to write that location. Choose another, or cancel the save dialog. text of permissions popup - Ви не маєте прав на запис за цим розташуванням. Оберіть інше місце призначення, або скасуйте передачу. + Ви не маєте прав на запис за цим розташуванням. Оберіть інше місце призначення, або скасуйте передачу. - - Failed to copy file На вдалось скопіювати файл - - The file you chose could not be written to. Неможливо записати в файл, який ви обрали. - - Profile currently loaded - current profile deletion warning title - Цей профіль зараз використовується - - - - This profile is currently in use. Please load a different profile before deleting this one. - current profile deletion warning text - Даний профіль зараз використовується. Завантажте інший, перед вилученням поточного профілю. - - - - Deletion imminent! + Really delete profile? deletion confirmation title - Небезпечне вилучення! + Ви впевнені? + + + Nothing to remove + Немає що видаляти + + + Your profile does not have a password! + Ваш обліковий запис не захищений паролем! + + + Really delete password? + deletion confirmation title + Ви впевнені? + + + Are you sure you want to delete your password? + deletion confirmation text + Ви дійсно бажаєте видалити Ваш пароль? + + + Please enter a new password. + Введіть новий пароль, будь ласка. + + + User Profile + Профіль користувача + + + This bunch of characters tells other Tox clients how to contact you. +Share it with your friends to communicate. + Цей набір символів дозволяє клієнтам Tox зв'язатись з Вами. Для комунікації поділіться ним з своїм друзями. - Are you sure you want to delete this profile? deletion confirmation text Ви впевнені, що хочете видалити цей профіль? - - Import profile - import dialog title - Імпортувати профіль - - - - Tox save file (*.tox) - import dialog filter - Файл Tox (*.tox) - - - - Ignoring non-Tox file - popup title - Ігнорування не Tox файлу - - - - Warning: you've chosen a file that is not a Tox save file; ignoring. - popup text - - - - - Profile already exists - import confirm title - Профіль вже існує - - - - A profile named "%1" already exists. Do you want to erase it? - import confirm text - Профіль із назвою "%1" вже існує. Бажаєте стерти його? - - - Save save qr image Збереження - Save QrCode (*.png) save dialog filter Зберегти Qr код (*.png) @@ -2402,284 +1768,307 @@ Please use another image. QObject - Tox me maybe? - Default message in Tox URI friend requests. Write something appropriate! - Може поспілкуємось? - - - Ignoring non-Tox file popup title Ігнорування не Tox файлу - Warning: you've chosen a file that is not a Tox save file; ignoring. popup text Увага: Вказаний Вами файл не є файлом збереження Tox; він буде проігнорований. - Profile already exists import confirm title Профіль вже існує - A profile named "%1" already exists. Do you want to erase it? import confirm text Профіль із назвою «%1» вже існує. Бажаєте перезаписати його? - Profile imported Профіль імпортовано - %1.tox was successfully imported %1.tox успішно імпортовано - + Version %1, %2 + Версія %1, %2 + + Update The title of a message box Оновити - An update is available, do you want to download it now? It will be installed when qTox restarts. Доступне оновлення, бажаєте завантажити його зараз? Оновлення буде встановлено після перезапуску qTox. - Tox URI to parse Tox URI для розбору - Starts new instance and loads specified profile. - + Запускає новий екземпляр і завантажує вказаний профіль. - profile профіль - Default Типовий - Blue Синій - Olive Оливковий - Red Червоний - Violet Фіолетовий - Incoming call... Вхідний дзвінок... - Resizing Змінити розмір - %1 here! Tox me maybe? Default message in Tox URI friend requests. Write something appropriate! - + That means "Hi, I'm %1! Please, add me to you contact list. +It's difficult to translate "Tox me maybe" because in Ukrainian noun can't mean a verb (like "call" for noun and verb in English) + Привіт, я %1! Додай мене в свій список контактів, будь ласка. + - - Load chat history... - Завантажити історію чату... + Incorrect response + Некоректна відповідь - - User Profile - Профіль користувача + No password in response + У відповіді відсутній пароль + + + Server doesn't support Toxme + Сервер не підтримує Toxme + + + You must send POST requests to /api + Ви повинні відправити POST-запит до /api + + + Please try again using a HTTPS connection + Спробуйте ще раз, використовуючи HTTPS-з'єднання, будь ласка + + + I was unable to read your encrypted payload + Я не міг прочитати Ваш зашифрований трафік + + + You're making too many requests. Wait an hour and try again + Ви відправляєте забагато запитів. Зачекайте годинку та спробуйте ще раз + + + This name is already in use + Це ім'я вже використовується + + + This Tox ID is already registered under another name + Цей Tox ID вже зареєстровано під іншим іменем + + + Please don't use a space in your name + Будь ласка, не використвуйте пробіли в Вашому імені + + + Password incorrect + Невірний пароль + + + You can't use this name + Ви не можете використати це ім'я + + + Name not found + Ім'я не знайдено + + + Tox ID not sent + Tox ID не надіслано + + + Lookup failed because the server replied with invalid data + Пошук завершився невдало, тому що сервер надіслав некоректні дані + + + That user does not exist + Такого користувача не існує + + + Internal lookup error. Please file a bug + Внутрішня помилка пошуку. Будь ласка, повідомте про помилку + + + Unknown error (%1) + Невідома помилка (%1) + + + Error + Помилка + + + qTox couldn't open your chat logs, they will be disabled. + qTox не може відкрити ваші чат логи, їх буде вимкнено. + + + None + No camera device set + Відсутній + + + Desktop + Desktop as a camera input for screen sharing + I think in this case more appropriate is "Екран" which means "Screen" + Робочий стіл + + + + RemoveFriendDialog + + Remove friend + Вилучити з друзів + + + <html><head/><body><p>Are you sure you want to remove <span style=" font-weight:600;">&lt;name&gt;</span> from your contacts list?</p></body></html> + <html><head/><body><p>Ви дійсно хочете видалити <span style=" font-weight:600;">&lt;name&gt;</span> з вашого списку контактів?</p></body></html> + + + Also remove chat history + Також видалити історію переписки + + + Remove + Видалити ScreenshotGrabber - - Click and drag to select a region. Press <b>Escape</b> to cancel. + Click and drag to select a region. Press <b>Space</b> to hide/show qTox window, or <b>Escape</b> to cancel. Help text shown when no region has been selected yet - Натисніть і потяніть для вибору регіону. Натисніть <b>Escape</b> для скасування. + Клікніть та перетягніть вказівник миші, щоб обрати область. Натисніть <b>Space</b> щоб відобразити/приховати вікно qTox, або <b>Escape</b> для скасування. - - Press <b>Enter</b> to send a screenshot of the selected region or select a new region. Press <b>Escape</b> to cancel. + Press <b>Enter</b> to send a screenshot of the selection, <b>Space</b> to hide/show qTox window, or <b>Escape</b> to cancel. Help text shown when a region has been selected - Натисність <b>Enter</b> для того, щоб відіслати знімок вибраного регіону екрана. Натисніть <b>Escape</b> для скасування. + Натисніть <b>Enter</b> щоб надіслати знімок вибраної області, <b>Space</b> щоб відобразити/приховати вікно qTox, або <b>Escape</b> для скасування. SetPasswordDialog - Type Password - Наберіть пароль - - - Repeat Password - Повторіть пароль - - - Set your password Встановіть свій пароль - - Repeat password - Повторіть пароль + Confirm: + Підтвердження: - - Type password - Введіть пароль + Password: + Пароль: - - Password strength - Якість паролю + Password strength: %p% + Надійність пароля: %p% - - - The passwords don't match. - Введені паролі не співпадають. + The password is too short + Пароль занадто короткий + + + The password doesn't match. + Паролі не співпадають. Settings - - Choose a profile - Оберіть профіль - - - - Please choose which identity to use - Оберіть користувача для використання + Circle #%1 + Коло №%1 ToxDNS - The connection timed out The DNS gives the Tox ID associated to toxme.se addresses Час очікування з'єднання вийшов - This address does not exist The DNS gives the Tox ID associated to toxme.se addresses Даної адреси не існує - Error while looking up DNS The DNS gives the Tox ID associated to toxme.se addresses Помилка під час перегляду DNS - No text record found Error with the DNS Не виявлено текстового запису - Unexpected number of values in text record Error with the DNS Неочікуване число значень в текстових записах - - - The version of Tox DNS used by this server is not supported - Error with the DNS - Версія Tox DNS даного серверу не підтримується - - - - The DNS lookup does not contain any Tox ID - Error with the DNS - Відповідь DNS не містить жодного Tox ID - - - - - The DNS lookup does not contain a valid Tox ID - Error with the DNS - Відповідь DNS не містить жодного коректного Tox ID - - - - - It appears that qTox has to use the old tox1 protocol to access DNS record of your friend's Tox ID. -Unfortunately tox1 is not secure, and you are at risk of someone hijacking what is sent between you and ToxDNS service. -Should tox1 be used anyway? -If unsure, press “No”, so that request to ToxDNS service will not be made using unsecure protocol. - Схоже на те, що qTox має використати старий протокол tox1 для доступу до DNS запису про ID вашого Tox друга. -На жаль, tox1 не є надійним і хтось може викрасти переслані між вами і ToxDNS сервісом дані. -Ви все ж хочете використовувати tox1? -Якщо ви не певні - відповідайте "Ні" - так при запиті до ToxDNS не буде використовуватись ненадійний протокол. - ToxURIDialog - Add a friend Title of the window to add a friend through Tox URI Додати друга - Do you want to add %1 as a friend? Бажаєте додати %1 як друга? - User ID: ID користувача: - Friend request message: Повідомлення запиту: - Send Send a friend request Надіслати - Cancel Don't send a friend request Скасувати @@ -2688,212 +2077,202 @@ If unsure, press “No”, so that request to ToxDNS service will not be made us Widget - Online В мережі - Away - Відійшов - - - Busy - Зайнятий - - - - &Quit - &Вийти - - - Change status to: - Змінити статус на: - - - Online Button to set your status to 'Online' В мережі - Away Button to set your status to 'Away' Відійшов - Busy Button to set your status to 'Busy' Зайнятий - Choose a profile - Оберіть профіль - - - Please choose which identity to use - Оберіть ідентифікатор для використання - - - Choose a profile picture - Оберіть зображення для профілю - - - Error - Помилка - - - Unable to open this file - Неможливо відкрити цей файл - - - Unable to read this image - Неможливо прочитати це зображення - - - This image is too big - Зображення завелике - - - - Toxcore failed to start, the application will terminate after you close this message. - Помилка запуску ядра tox, програма буде завершена після закриття цього повідомлення. - - - toxcore failed to start with your proxy settings. qTox cannot run; please modify your settings and restart. popup text Помилка запуску ядра tox із поточними параметрами проксі. qTox не працює; змініть параметри і перезапустіть. - - Add friend Додати друга - + Add new circle... + Додати нове коло... + + + By Name + За іменем + + + By Activity + За активністю + + All Всі контакти - Offline Не в мережі - Friends Друзі - Groups Групи - Search Contacts Пошук контактів - + Logout + Tray action menu to logout user + Вихід з облікового запису + + + Exit + Tray action menu to exit tox + Вихід + + + Filter... + Фільтр... + + + File + Файл + + + Edit + Редагувати + + + Contacts + Контакти + + + Change Status + Змінити статус + + + Edit Profile + Редагувати профіль + + + Log out + Вихід з облікового запису + + + Add Contact... + Додати контакт... + + + Next Conversation + Наступна бесіда + + + Previous Conversation + Попередня бесіда + + File transfers Передачі файлів - Executable file popup title Виконуваний файл - You have asked qTox to open an executable file. Executable files can potentially damage your computer. Are you sure want to open this file? popup text Ви намагаєтеся відкрити виконуваний файл. Виконувані файли можуть нанести шкоди вашому комп’ютеру. Ви все ще хочете відкрити цей файл? - Settings Параметри - Profile Профіль - Couldn't request friendship Не вдалось надіслати запит на дружбу - + Status + Статус + + + toxcore failed to start, the application will terminate after you close this message. + Неможливо запустити toxcore, додаток завершить роботу, коли Ви закриєте це повідомлення. + + + Your name + Ваше ім'я + + + Your status + Ваш статус + + away contact status Відійшов - busy contact status Зайнятий - offline contact status Поза мережею - online contact status В мережі - %1 is now %2 e.g. "Dubslow is now online" %1 тепер вже відомий як %2 - - Remove history - Видалити історію - - - - Do you want to remove history as well? - Ви хочете видалити історію також? - - - Group invite popup title Групове запрошення - %1 has invited you to a groupchat. Would you like to join? popup text %1 запросив вас до групового чату. Приєднаєтеся? - <Unknown> Placeholder when we don't know someone's name in a group chat <Невідомо> - %1 has set the title to %2 %1 встановив тему %2 - Message failed to send Не вдалось відправити повідомлення From 0ee59848128e6fb5ce9eda51ce0f6627f546b16f Mon Sep 17 00:00:00 2001 From: minj <4mr.minj@gmail.com> Date: Sun, 7 Feb 2016 16:34:23 +0200 Subject: [PATCH 197/210] update Lithuanian translation --- translations/lt.ts | 148 ++++++++++++++++++++++++++++++++------------- 1 file changed, 106 insertions(+), 42 deletions(-) diff --git a/translations/lt.ts b/translations/lt.ts index 3886cb8b0..7259cefa9 100644 --- a/translations/lt.ts +++ b/translations/lt.ts @@ -30,14 +30,6 @@ Audio Settings Garso įrenginiai - - Microphone - Įrašymas - - - Playback - Išvestis - Use slider to set volume of your speakers. Šliaužikliu nustatykite garsiakalbių garsumą. @@ -46,26 +38,30 @@ Playback device Išvesties įrenginys + + Volume + Garsumas + + + ... + ... + Capture device Įrašymo įrenginys + + Gain + Garsumas + Filter audio Filtruoti garso signalą - - 0 - 0 - Filter sound from your microphone, so that people hearing you would get better sound. Filtruoti mikrofono garsą, kad žmonės Jus geriau girdėtų. - - 100 - 100 - Use slider to set volume of your microphone. Šliaužikliu nustatykite mikrofono garsumą. @@ -137,26 +133,6 @@ Jei Jūsų interneto ryšys yra per prastas, turėsite keblumų su vaizdo skambu License Licencija - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; color:#000000;">Copyright © 2014-2015 by The qTox Project</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu';">qTox is a Qt-based graphical interface for Tox.</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';">qTox is libre software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';">qTox is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. </span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu';">You should have received a copy of the GNU General Public License along with this program. If not, see </span><a href="https://www.gnu.org/copyleft/gpl.html"><span style=" font-family:'Ubuntu'; text-decoration: underline; color:#007af4;">https://www.gnu.org/copyleft/gpl.html</span></a><span style=" font-family:'Ubuntu';">.</span></p></body></html> - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style= "font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; color:#000000;">Autorių teisės: qTox projektas, 2014-2015.</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu';">qTox – Tox protokolu veikianti programa su Qt grafine aplinka.</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';">qTox yra atvira programinė įranga: galite ją platinti ir (arba) modifikuoti pagal GNU atvirosios programinės įrangos licencijos (GPL), kurią parengė Laisvosios programinės įrangos fondas (FSF), trečiąją (ar bet kurią vėlesnę) versiją.</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';">Tikimės, kad qTox bus Jums naudingas, bet nesuteikiame JOKIOS GARANTIJOS, įskaitant PERKAMUMO ar TINKAMUMO KOKIAM NORS TIKSLUI. Detalesnė informacija pateikta GPL licencijoje. </span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu';">GPL licencijos kopiją turėjote gauti kartu su šia programine įranga. Priešingu atveju, apsilankykite </span><a href="https://www.gnu.org/copyleft/gpl.html"><span style=" font-family:'Ubuntu'; text-decoration: underline; color:#007af4;">https://www.gnu.org/copyleft/gpl.html</span></a><span style=" font-family:'Ubuntu';">.</span></p></body></html> - toxcore version: $TOXCOREVERSION toxcore versija: $TOXCOREVERSION @@ -169,6 +145,18 @@ p, li { white-space: pre-wrap; } Commit hash: <a href="https://github.com/tux3/qTox/commit/$GIT_VERSION">$GIT_VERSION</a> Atnaujinimo maiša (<i>hash</i>): <a href="https://github.com/tux3/qTox/commit/$GIT_VERSION">$GIT_VERSION</a> + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Noto Sans'; font-size:12pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:10pt; color:#000000;">Autorių teisės: qTox projektas, 2014-2015.</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:10pt;">qTox – Tox protokolu veikianti programa su Qt grafine aplinka.</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:10pt;">qTox yra atvira programinė įranga: galite ją platinti ir (arba) modifikuoti pagal GNU atvirosios programinės įrangos licencijos (GPL), kurią parengė Laisvosios programinės įrangos fondas (FSF), trečiąją (ar bet kurią vėlesnę) versiją.</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:10pt;">Tikimės, kad qTox bus Jums naudingas, bet nesuteikiame JOKIOS GARANTIJOS, įskaitant PERKAMUMO ar TINKAMUMO KOKIAM NORS TIKSLUI. Detalesnė informacija pateikta GPL licencijoje. </span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:10pt;">GPL licencijos kopiją turėjote gauti kartu su šia programine įranga. Priešingu atveju, apsilankykite </span><a href="https://www.gnu.org/copyleft/gpl.html"><span style=" font-family:'Ubuntu'; font-size:10pt; text-decoration: underline; color:#007af4;">https://www.gnu.org/copyleft/gpl.html</span></a><span style=" font-family:'Ubuntu'; font-size:10pt;">.</span></p></body></html> + + Authors Kūrėjai @@ -261,6 +249,12 @@ p, li { white-space: pre-wrap; } Tox ID of the person you're sending a friend request to Tox ID + + qTox needs to use the Tox DNS, but can't do it through a proxy. + Ignore the proxy and connect to the Internet directly? + qTox naudoja Tox DNS, bet tai neįmanoma per įgaliotąjį (proxy) serverį. + Ignoruoti įgaliotąjį serverį ir jungtis prie interneto tiesiogiai? + either 76 hexadecimal characters or name@example.com Tox ID format description @@ -293,12 +287,6 @@ p, li { white-space: pre-wrap; } When trying to add your own Tox ID as friend Negalite naudoti savo Tox ID! - - qTox needs to use the Tox DNS, but can't do it through a proxy. -Ignore the proxy and connect to the Internet directly? - qTox naudoja Tox DNS, bet tai neįmanoma per įgaliotąjį (proxy) serverį. -Ignoruoti įgaliotąjį serverį ir jungtis prie interneto tiesiogiai? - This Tox ID does not exist DNS error @@ -1454,6 +1442,10 @@ If you encountered this error, please report it. Neatpažinta klaida: nepavyko sukurti profilio. Prašome pranešti apie šią klaidą. + + Password protected profile can't be loaded automatically. + Slaptažodžiu apsaugoto profilio atidaryti automatiškai nepavyko. + Couldn't load profile Nepavyko prisijungti @@ -1874,6 +1866,78 @@ Ji bus įdiegta paleidus qTox iš naujo. qTox couldn't open your chat logs, they will be disabled. qTox nepavyko atidaryti pokalbių žurnalo, todėl jis buvo išjungtas. + + Incorrect response + Neteisingas atsakas + + + No password in response + Atsake trūksta slaptažodžio + + + Server doesn't support Toxme + Serveris nepalaiko Toxme funkcijos + + + You must send POST requests to /api + Reikia siųsti POST užklausas į /api + + + Please try again using a HTTPS connection + Bandykite per naujo naudodami HTTPS ryšį + + + I was unable to read your encrypted payload + Nepavyko perskaityti užšifruotų duomenų + + + You're making too many requests. Wait an hour and try again + Per daug užklausų. Pabandykite dar sykį po valandos + + + This name is already in use + Vardas jau užimtas + + + This Tox ID is already registered under another name + Šis Tox ID jau užregistruotas kitu vardu + + + Please don't use a space in your name + Vardas turi būti be tarpų + + + Password incorrect + Neteisingas slaptažodis + + + You can't use this name + Šio vardo naudoti negalima + + + Name not found + Tokio vardo nėra + + + Tox ID not sent + Tox ID neišsiųstas + + + Lookup failed because the server replied with invalid data + Užklausa nepavyko, nes serverio atsakas nesuprantamas + + + That user does not exist + Šio naudotojo nėra + + + Internal lookup error. Please file a bug + Vidinė klaida. Praneškite apie šį įvykį programuotojams + + + Unknown error (%1) + Nežinoma klaida (%1) + RemoveFriendDialog From a2d130f804661bdc208317f864e801767780c694 Mon Sep 17 00:00:00 2001 From: SeventhSonOfASeventhSon Date: Mon, 8 Feb 2016 16:24:52 +0000 Subject: [PATCH 198/210] Fixed grammatical errors --- CONTRIBUTING.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e74104c4b..f5eea4069 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,9 +2,9 @@ ### Must read * If you aren't sure, you can ask on the [**IRC channel**](https://webchat.freenode.net/?channels=qtox) or read our [**wiki**](https://github.com/tux3/qTox/wiki) first. -* Do a quick **search**. Others might already reported the issue. +* Do a quick **search**. Others might have already reported the issue. * Write in **English**! -* Provide **version** information: (You can find version numbers at menu `Settings → About`) +* Provide **version** information: (You can find version numbers in menu `Settings → About`) ``` qTox: Commit hash: @@ -14,12 +14,12 @@ OS version: ``` * Provide **steps** to reproduce the problem, it will be easier to pinpoint the fault. -* **Screenshots**! A screenshot is worth a thousand words. just upload it. [(How?)](https://help.github.com/articles/file-attachments-on-issues-and-pull-requests) +* **Screenshots**! A screenshot is worth a thousand words. Just upload it. [(How?)](https://help.github.com/articles/file-attachments-on-issues-and-pull-requests) ### Good to know -* **Patience**. The dev team is small and resource limited. Devs finding their free time, analyzing the problem and fixing the issue, it all takes time. :clock3: -* If you can code, why not become a **contributor** by fixing the issue and open a pull request? :wink: -* Harsh words or threats won't help your situation. What's worse, your complain will (very likely) to be **ignored**. :fearful: +* **Patience**. The dev team is small and resource limited. Devs have to find time, analyze the problem and fix the issue, it all takes time. :clock3: +* If you can code, why not become a **contributor** by fixing the issue and opening a pull request? :wink: +* Harsh words or threats won't help your situation. What's worse, your complaint will (very likely) be **ignored**. :fearful: # Opening a pull request @@ -29,9 +29,9 @@ OS version: * Keep the title **short** and provide a **clear** description about what your pull request does. * Provide **screenshots** for UI related changes. * Keep your git commit history **clean** and **precise**. Commits like `xxx fixup` should not appear. -* If your commit fix a reported issue (for example #4134), add the following message to the commit `Fixes #4134.`. Example [here](https://github.com/tux3/qTox/commit/87160526d5bafcee7869d6741a06045e13d731d5). +* If your commit fixes a reported issue (for example #4134), add the following message to the commit `Fixes #4134.`. [Here is an example](https://github.com/tux3/qTox/commit/87160526d5bafcee7869d6741a06045e13d731d5). ### Good to know -* **Search** pull request history! Others might already implemented your idea and is waiting to be merged (or got rejected already). Save your precious time by doing a search first. -* When resolving merge conflicts, do `git rebase `, don't do `git pull`. Then you can start fixing the conflicts. Here is a good explanation: [link](https://www.atlassian.com/git/tutorials/merging-vs-rebasing). +* **Search** the pull request history! Others might have already implemented your idea and it could be waiting to be merged (or have been rejected already). Save your precious time by doing a search first. +* When resolving merge conflicts, do `git rebase `, don't do `git pull`. Then you can start fixing the conflicts. [Here is a good explanation](https://www.atlassian.com/git/tutorials/merging-vs-rebasing). From 857dfbcd4c1ecdab2b35c5bee8974bdcdef99558 Mon Sep 17 00:00:00 2001 From: Vincas Dargis Date: Sun, 14 Feb 2016 17:20:11 +0200 Subject: [PATCH 199/210] Open downloaded image with mouse click on thumbnail --- src/chatlog/content/filetransferwidget.cpp | 20 +++++++++++++------- src/chatlog/content/filetransferwidget.h | 1 + src/chatlog/content/filetransferwidget.ui | 21 ++++++++++++++------- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/chatlog/content/filetransferwidget.cpp b/src/chatlog/content/filetransferwidget.cpp index 84d4f902c..a9950dc32 100644 --- a/src/chatlog/content/filetransferwidget.cpp +++ b/src/chatlog/content/filetransferwidget.cpp @@ -53,7 +53,7 @@ FileTransferWidget::FileTransferWidget(QWidget *parent, ToxFile file) // hide the QWidget background (background-color: transparent doesn't seem to work) setAttribute(Qt::WA_TranslucentBackground, true); - ui->previewLabel->hide(); + ui->previewButton->hide(); ui->filenameLabel->setText(file.fileName); ui->progressBar->setValue(0); ui->fileSizeLabel->setText(getHumanReadableSize(file.filesize)); @@ -86,6 +86,7 @@ FileTransferWidget::FileTransferWidget(QWidget *parent, ToxFile file) connect(Core::getInstance(), &Core::fileTransferBrokenUnbroken, this, &FileTransferWidget::fileTransferBrokenUnbroken); connect(ui->topButton, &QPushButton::clicked, this, &FileTransferWidget::onTopButtonClicked); connect(ui->bottomButton, &QPushButton::clicked, this, &FileTransferWidget::onBottomButtonClicked); + connect(ui->previewButton, &QPushButton::clicked, this, &FileTransferWidget::onPreviewButtonClicked); setupButtons(); @@ -482,7 +483,7 @@ void FileTransferWidget::handleButton(QPushButton *btn) } } - if (btn->objectName() == "ok") + if (btn->objectName() == "ok" || btn->objectName() == "previewButton") { Widget::confirmExecutableOpen(QFileInfo(fileInfo.filePath)); } @@ -501,13 +502,13 @@ void FileTransferWidget::showPreview(const QString &filename) if (previewExtensions.contains(QFileInfo(filename).suffix())) { - const int size = qMax(ui->previewLabel->width(), ui->previewLabel->height()); + const int size = qMax(ui->previewButton->width(), ui->previewButton->height()); QPixmap pmap = QPixmap(filename).scaled(QSize(size, size), Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); - ui->previewLabel->setPixmap(pmap); - ui->previewLabel->show(); - ui->previewLabel->setCursor(Qt::PointingHandCursor); + ui->previewButton->setIcon(QIcon(pmap)); + ui->previewButton->setIconSize(pmap.size()); + ui->previewButton->show(); // Show mouseover preview, but make sure it's not larger than 50% of the screen width/height QRect desktopSize = QApplication::desktop()->screenGeometry(); QImage image = QImage(filename).scaled(0.5 * desktopSize.width(), @@ -518,7 +519,7 @@ void FileTransferWidget::showPreview(const QString &filename) buffer.open(QIODevice::WriteOnly); image.save(&buffer, "PNG"); buffer.close(); - ui->previewLabel->setToolTip(""); + ui->previewButton->setToolTip(""); } } @@ -531,3 +532,8 @@ void FileTransferWidget::onBottomButtonClicked() { handleButton(ui->bottomButton); } + +void FileTransferWidget::onPreviewButtonClicked() +{ + handleButton(ui->previewButton); +} diff --git a/src/chatlog/content/filetransferwidget.h b/src/chatlog/content/filetransferwidget.h index 439336df8..7ecb0ef8f 100644 --- a/src/chatlog/content/filetransferwidget.h +++ b/src/chatlog/content/filetransferwidget.h @@ -70,6 +70,7 @@ protected: private slots: void onTopButtonClicked(); void onBottomButtonClicked(); + void onPreviewButtonClicked(); private: Ui::FileTransferWidget *ui; diff --git a/src/chatlog/content/filetransferwidget.ui b/src/chatlog/content/filetransferwidget.ui index 290d79035..869da8e12 100644 --- a/src/chatlog/content/filetransferwidget.ui +++ b/src/chatlog/content/filetransferwidget.ui @@ -270,7 +270,7 @@ - + 0 @@ -289,14 +289,21 @@ 60 - - QFrame::Box + + PointingHandCursor - - 2 + + + :/ui/fileTransferInstance/no.svg:/ui/fileTransferInstance/no.svg - - [preview] + + + 32 + 18 + + + + true From dba6ebe262cbdce7bcab024ef4d3f0e41d826dc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaur=20M=C3=A4nnamaa?= Date: Wed, 17 Feb 2016 03:46:55 +0200 Subject: [PATCH 200/210] Added Estonian translation --- res.qrc | 1 + src/widget/form/settings/generalform.cpp | 2 + translations/et.ts | 2282 ++++++++++++++++++++++ translations/i18n.pri | 1 + 4 files changed, 2286 insertions(+) create mode 100644 translations/et.ts diff --git a/res.qrc b/res.qrc index 51f2706bb..5d9940cb7 100644 --- a/res.qrc +++ b/res.qrc @@ -47,6 +47,7 @@ translations/de.qm translations/el.qm translations/es.qm + translations/et.qm translations/fi.qm translations/fr.qm translations/hr.qm diff --git a/src/widget/form/settings/generalform.cpp b/src/widget/form/settings/generalform.cpp index 8d373b5fe..ca2f3ac4b 100644 --- a/src/widget/form/settings/generalform.cpp +++ b/src/widget/form/settings/generalform.cpp @@ -41,6 +41,7 @@ static QStringList locales = {"bg", "cs", "de", + "et", "el", "en", "es", @@ -64,6 +65,7 @@ static QStringList locales = {"bg", static QStringList langs = {"Български", "Čeština", "Deutsch", + "Eesti", "Ελληνικά", "English", "Español", diff --git a/translations/et.ts b/translations/et.ts new file mode 100644 index 000000000..b8585fb8f --- /dev/null +++ b/translations/et.ts @@ -0,0 +1,2282 @@ + + + + + AVForm + + %1x%2 + %1x%2 + + + Default resolution + Vaikelahutus + + + at %1 FPS + sagedusega %1 FPS + + + None + Puudub + + + Audio/Video + Heli/Video + + + + AVSettings + + Audio Settings + Heliseaded + + + Playback device + Mahamängiv seade + + + Volume + Helitugevus + + + Use slider to set volume of your speakers. + Kasuta liugurit, et seada kõlarite helitaset. + + + ... + ... + + + Capture device + Salvestav seade + + + Gain + Võimendus + + + Use slider to set volume of your microphone. + Kasuta liugurit, et seada mikrofoni võimendust. + + + Filter sound from your microphone, so that people hearing you would get better sound. + Lase mikrofoni sisend läbi filtri, et sind kuulvad inimesed kogeksid paremat heli. + + + Filter audio + Helisisend läbi filtri + + + Video Settings + Videoseaded + + + Video device + Videoseade + + + Set resolution of your camera. +The higher values, the better video quality your friends may get. +Note though that with better video quality there is needed better internet connection. +Sometimes your connection may not be good enough to handle higher video quality, +which may lead to problems with video calls. + Määra oma kaamera lahutus. +Mida kõrgemad on väärtused, seda kõrgem pilt võib sinu sõpradeni jõuda. +Pea siiski meeles, et kvaliteetsem pilt eeldab ka kiiremat internetiühendust. +Vahel võib sinu ühendus olla hea videopildi edastamiseks liialt vilets, +mis omakorda võib tekitada probleeme videokõnede pidamisel. + + + Resolution + Lahutus + + + Rescan devices + Otsi seadmeid + + + + AboutForm + + Qt version: + Qt versioon: + + + Restart qTox to install version %1 + Taaskäivita qTox, et paigaldada versioon %1 + + + qTox is downloading update %1 + %1 is the version of the update + qTox laeb alla uuendust versiooninumbriga %1 + + + About + Programmist lähemalt + + + + AboutSettings + + Version + Versioon + + + toxcore version: $TOXCOREVERSION + toxcore'i versioon: $TOXCOREVERSION + + + Qt version: + Qt versioon: + + + Commit hash: <a href="https://github.com/tux3/qTox/commit/$GIT_VERSION">$GIT_VERSION</a> + Commit räsi: <a href="https://github.com/tux3/qTox/commit/$GIT_VERSION">$GIT_VERSION</a> + + + You are using qTox version $GIT_DESCRIBE. + Kasutad qToxi versiooni $GIT_DESCRIBE. + + + Downloading update: %p% + Laen uuendust: %p% + + + License + Litsents + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Noto Sans'; font-size:12pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:10pt; color:#000000;">Copyright © 2014-2015 by The qTox Project</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:10pt;">qTox is a Qt-based graphical interface for Tox.</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:10pt;">qTox is libre software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:10pt;">qTox is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. </span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:10pt;">You should have received a copy of the GNU General Public License along with this program. If not, see </span><a href="https://www.gnu.org/copyleft/gpl.html"><span style=" font-family:'Ubuntu'; font-size:10pt; text-decoration: underline; color:#007af4;">https://www.gnu.org/copyleft/gpl.html</span></a><span style=" font-family:'Ubuntu'; font-size:10pt;">.</span></p></body></html> + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Noto Sans'; font-size:12pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:10pt; color:#000000;">Autoriõigused © 2014-2015 The qTox Project</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:10pt;">qTox on Qt-põhine graafiline kasutajaliides Tox protokollile.</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:10pt;">qTox on vaba tarkvara: seda võib levitada ja/või muuta vastavalt GNU üldisele Avalikule Litsentsile (originaali nimetus GNU General Public Licence), mille on sätestanud Free Software Foundation. Käesolevale programmile kohaldub litsentsi 3. või (teie vabal valikul) mistahes muu sellest uuem versioon.</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:10pt;">qToxi levitatakse lootuses, et see on kasulik, ent ilma mistahes garantiita; isegi ilma kaudse garantiita MÜÜGIKÕLBULIKKUSE või MINGIKS OTSTARBEKS SOBIMISE kohta. Täiendava teabe saamiseks vaadake GNU Üldist Avalikku Litsentsi.</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:10pt;">Te pidanuks koos selle programmiga saama ka koopia GNU Üldisest Avalikust Litsentsist. Kui Te koopiat ei saanud, vaadake </span><a href="https://www.gnu.org/copyleft/gpl.html"><span style=" font-family:'Ubuntu'; font-size:10pt; text-decoration: underline; color:#007af4;">https://www.gnu.org/copyleft/gpl.html</span></a><span style=" font-family:'Ubuntu'; font-size:10pt;">.</span></p></body></html> + + + Authors + Autorid + + + <html><head/><body><p>Original author: <a href="https://github.com/tux3"><span style=" text-decoration: underline; color:#0000ff;">tux3</span></a></p><p>See a full list of <a href="https://github.com/tux3/qTox/graphs/contributors"><span style=" text-decoration: underline; color:#0000ff;">contributors</span></a> at Github</p></body></html> + <html><head/><body><p>Algversiooni autor: <a href="https://github.com/tux3"><span style=" text-decoration: underline; color:#0000ff;">tux3</span></a></p><p>Vaata ka <a href="https://github.com/tux3/qTox/graphs/contributors"><span style=" text-decoration: underline; color:#0000ff;">kaastööliste täielikku nimekirja</span></a> keskkonnas nimega Github</p></body></html> + + + Known Issues + Teadaolevad probleemid + + + <html><head/><body><p>A list of all known issues may be found at our <a href="https://github.com/tux3/qTox/issues"><span style=" text-decoration: underline; color:#0000ff;">bug-tracker</span></a> at Github. If you discover a bug or security vulnerability within qTox, please report it according to the guidelines in our <a href="https://github.com/tux3/qTox/wiki/Writing-Useful-Bug-Reports"><span style=" text-decoration: underline; color:#0000ff;">Writing Useful Bug Reports</span></a> wiki article.</p></body></html> + <html><head/><body><p>Kõiki teadaolevaid probleeme saab näha meie <a href="https://github.com/tux3/qTox/issues"><span style=" text-decoration: underline; color:#0000ff;">vigade jälgimise süsteemis,</span></a> mis asub keskkonnas nimega Github. Kui märkad, et qTox sisaldab mõnd viga või lausa turvaauku, siis anna sellest palun teada, lähtudes meie <a href="https://github.com/tux3/qTox/wiki/Writing-Useful-Bug-Reports"><span style=" text-decoration: underline; color:#0000ff;">asjalike veakirjelduste kirjutamise</span></a> teemalisest wiki artiklist.</p></body></html> + + + + AboutUser + + Dialog + Aken + + + username + kasutajanimi + + + status message + olekuteade + + + Public key: + Avalik võti: + + + Used aliases: + Pruugitud hüüdnimed: + + + HISTORY OF ALIASES + HÜÜDNIMEDE AJALUGU + + + Default directory to save files: + Failide vaikekaust: + + + Auto accept for this contact is disabled + Kontakti failide automaatne vastuvõtmine on keelatud + + + Auto accept files + Võta failid automaatselt vastu + + + Remove history (operation can not be undone!) + Eemalda ajalugu (toimingut ei saa hiljem tühistada) + + + Notes + Märkused + + + You can save comment about this contact here. + Siia saad selle kontakti kohta kommentaare kirjutada. + + + Choose an auto accept directory + popup title + Vali kaust, kuhu automaatselt vastuvõetavad failid laetakse + + + History removed + Ajalugu kustutati + + + Chat history with %1 removed! + Kasutajaga %1 peetud vestluste ajalugu on kustutatud! + + + + AddFriendForm + + qTox needs to use the Tox DNS, but can't do it through a proxy. + Ignore the proxy and connect to the Internet directly? + qTox peab kasutama Tox DNS teenust, ent ei saa seda läbi puhverserveri teha. + Kas minna puhverserverist mööda ja ürituda ühenduda internetiga otse? + + + Couldn't add friend + Sõbra lisamine ebaõnnestus + + + This Tox ID does not exist + DNS error + Sellist Tox ID-d pole olemas + + + You can't add yourself as a friend! + When trying to add your own Tox ID as friend + Ennast pole võimalik sõbraks lisada! + + + Tox ID + Tox ID of the person you're sending a friend request to + Tox ID + + + either 76 hexadecimal characters or name@example.com + Tox ID format description + kas 76 kuueteistkümnendsüsteemi märki või nimi@mingiaadress.com + + + Invalid Tox ID format + Vigane Tox ID vorming + + + Add Friends + Lisa sõpru + + + Message + The message you send in friend requests + Teade + + + Send friend request + Saada sõbrakutse + + + %1 here! Tox me maybe? + Default message in friend requests if the field is left blank. Write something appropriate! + %1 siin! Ehk liitud minuga Tox keskkonnas? + + + + AdvancedForm + + Advanced + Edasijõudnud + + + + AdvancedSettings + + Save settings to the working directory instead of the usual conf dir + describes makeToxPortable checkbox + Salvesta seaded vaikekausta asemel töökausta + + + Make Tox portable + Muuda Tox teisaldatavaks + + + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">IMPORTANT NOTE</span></p><p><span style=" color:#ff0000;">Unless you </span><span style=" font-weight:600; color:#ff0000;">really</span><span style=" color:#ff0000;"> know what you are doing, please do </span><span style=" font-weight:600; color:#ff0000;">not</span><span style=" color:#ff0000;"> change anything here. Changes made here may lead to problems with qTox, and even to loss of your data, e.g. history.</span></p></body></html> + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">OLULINE MÄRKUS</span></p><p><span style=" color:#ff0000;">Kui sa </span><span style=" font-weight:600; color:#ff0000;">päris kindlalt</span><span style=" color:#ff0000;"> ei tea, mida sa teed, siis palun </span><span style=" font-weight:600; color:#ff0000;">ära</span><span style=" color:#ff0000;"> muuda siin midagi. Siin tehtud muudatused võivad põhjustada probleeme qToxi töös ja viia isegi andmete, näiteks ajaloo, kadumiseni.</span></p></body></html> + + + Reset to default settings + Taasta vaikeseaded + + + + Android + + Form + Aken + + + qTox + qTox + qTox + + + Someone + Keegi + + + Someone else + Keegi teine + + + Groupbot + Grupirobot + + + That guy who I don't remember adding + See sell, kelle lisamine mulle ei meenu + + + NASA manager + NASA juht + + + Lorem + Lorem + + + Ipsum + Ipsum + + + Dolor + Dolor + + + + ChatForm + + Send a file + Saada fail + + + Unable to open + Avamine luhtus + + + qTox wasn't able to open %1 + qTox ei suutnud avada faili %1 + + + Bad idea + See on vilets mõte + + + You're trying to send a special (sequential) file, that's not going to work! + Üritad saata erilist faili (sequential file), see ei lähe läbi! + + + Accept video call + Võta videokõne vastu + + + Accept audio call + Võta audiokõne vastu + + + %1 calling + %1 helistab + + + End video call + Lõpeta videokõne + + + End audio call + Lõpeta audiokõne + + + Mute microphone + Vaigista mikrofon + + + Mute call + Vaigista kõne + + + Cancel video call + Katkesta videokõne + + + Cancel audio call + Katkesta audiokõne + + + Calling %1 + Helistan kasutajale %1 + + + Start audio call + Alusta audiokõnet + + + Start video call + Alusta videokõnet + + + Unmute microphone + Lülita mikrofon sisse + + + Unmute call + konteksti peaks täpsustama + Lülita kõne heli sisse + + + Failed to send file "%1" + Faili "%1" saatmine luhtus + + + Failed to open temporary file + Temporary file for screenshot + Ei suutnud avada ajutist faili + + + qTox wasn't able to save the screenshot + qTox ei suutnud ekraanitõmmist salvestada + + + Call with %1 ended. %2 + Kõne kasutajaga %1 lõppes. %2 + + + Call duration: + Kõne kestvus: + + + Load chat history... + mitmuse kasutamine on siin ilmselt loogilisem + Lae vestluste ajalugu... + + + + ChatLog + + pending + ootel + + + Copy + Kopeeri + + + Select all + Vali kõik + + + + ChatTextEdit + + Type your message here... + Kirjuta siia oma teade... + + + + CircleWidget + + Rename circle + Menu for renaming a circle + Nimeta suhtlusring ümber + + + Remove circle + Menu for removing a circle + Eemalda suhtlusring + + + Open all in new window + Ava kõik uues aknas + + + + Core + + Toxing on qTox + Toxi kasutatakse läbi rakenduse nimega qTox + + + You need to write a message with your request + Pead oma kutsele ka teate lisama + + + Your message is too long! + Sinu teade on liialt pikk! + + + Friend is already added + Sõber on juba lisatud + + + /me offers friendship. + peaks tõlkima? + /me pakub sõprust. + + + /me offers friendship, "%1" + peaks tõlkima? + /me pakub sõprust, "%1" + + + Encrypted chat history + Krüpteeritud vestluste ajalugu + + + No encrypted chat history file found, or it was corrupted. +History will be disabled! + Krüpteeritud vestluste ajalugu ei leitud või on vastav fail kahjustada saanud. +Logi ei peeta! + + + Please enter the password for the chat history for the profile "%1". + used in load() when no hist pw set + Palun sisesta profiili "%1" vestluste ajaloo salasõna. + + + The previous password is incorrect; please try again: + used on retries in load() + Sisestatud salasõna oli vale. Palun proovi uuesti: + + + +Disabling chat history now will leave the encrypted history intact (but not usable); if you later remember the password, you may re-enable encryption from the Privacy tab with the correct password to use the history. + part of history password dialog + +Vestluste ajaloo logimise väljalülitamine ei hävita krüpteeritud ajalugu, ent samas ei ole seda võimalik ka kasutada. Kui parool hiljem meenub, saab krüpteerimise privaatsuse nimelise saki alt jälle sisse lülitada, sisestades seal õige salasõna. + + + The chat history password failed. Please try another? + used only when pw set before load() doesn't work + Vestluste ajaloo salasõna oli vale. Proovid ehk uuesti? + + + Disable chat history + Lülita vestluste logimine välja + + + + FileTransferWidget + + Form + Aken + + + 10Mb + 10Mb + + + 0kb/s + 0kb/s + + + ETA:10:10 + EPA:10:10 + + + Filename + Faili nimi + + + [preview] + [eelvaade] + + + Waiting to send... + file transfer widget + Ootan, et saata... + + + Accept to receive this file + file transfer widget + Nõustu, et faili vastu võtta + + + Location not writable + Title of permissions popup + Asukohta ei saa kirjutada + + + You do not have permission to write that location. Choose another, or cancel the save dialog. + text of permissions popup + Sul ei ole sellesse asukohta kirjutamiseks õigusi. Vali mõni muu või katkesta salvestamine. + + + Paused + file transfer widget + Pausil + + + Resuming... + file transfer widget + Jätkan... + + + Open file + Ava fail + + + Open file directory + Ava faili sisaldav kaust + + + Pause transfer + Pane ülekanne pausile + + + Cancel transfer + Katkesta ülekanne + + + Resume transfer + Jätka ülekannet + + + Accept transfer + Nõustu ülekandega + + + Save a file + Title of the file saving dialog + Salvesta fail + + + + FilesForm + + Transferred Files + "Headline" of the window + Ülekantud failid + + + Downloads + Allalaadimised + + + Uploads + Üleslaadimised + + + + FriendListWidget + + Today + Category for sorting friends by activity + Täna + + + Yesterday + Category for sorting friends by activity + Eile + + + Last 7 days + Category for sorting friends by activity + Viimase 7 päeva jooksul + + + This month + Category for sorting friends by activity + Sel kuul + + + Older than 6 Months + Category for sorting friends by activity + Enam kui 6 kuu eest + + + Unknown + Category for sorting friends by activity + Teadmata + + + + FriendRequestDialog + + Friend request + Title of the window to aceept/deny a friend request + Sõbrakutse + + + Someone wants to make friends with you + Keegi tahab sinu sõbraks hakata + + + User ID: + Kasutaja ID: + + + Friend request message: + Sõbrakutsele lisatud teade: + + + Accept + Accept a friend request + Nõustu + + + Reject + Reject a friend request + Keeldu + + + + FriendWidget + + Open chat in new window + Ava vestlus uues aknas + + + Remove chat from this window + Haagi vestlus sellest aknast lahti + + + Invite to group + Menu to invite a friend to a groupchat + Kutsu gruppi + + + Move to circle... + Menu to move a friend into a different circle + Liiguta suhtlusringi... + + + To new circle + Uude suhtlusringi + + + Remove from circle '%1' + Eemalda suhtlusringist nimega %1 + + + Move to circle "%1" + Liiguta suhtlusringi nimega %1 + + + Set alias... + Sea hüüdnimi... + + + Auto accept files from this friend + context menu entry + Võta selle sõbra failid automaatselt vastu + + + Remove friend + Menu to remove the friend from our friendlist + Eemalda sõber + + + Show details + Näita üksikasju + + + Choose an auto accept directory + popup title + Vali kaust, kuhu automaatselt vastuvõetavad failid paigutatakse + + + New message + Uus sõnum + + + Online + Vestlusvalmis + + + Away + Eemal + + + Busy + Hõivatud + + + Offline + Ühendamata + + + + GUI + + Enter your password + Sisesta oma salasõna + + + Decrypt + Dekrüpteeri + + + You must enter a non-empty password: + Pead sisestama salasõna: + + + + GeneralForm + + None + Puudub + + + Choose an auto accept directory + popup title + Vali kaust, kuhu automaatselt vastuvõetavad failid laetakse + + + Call active + popup title + Kõne käib + + + You can't disconnect while a call is active! + popup text + Sa ei saa võrgust lahkuda, kui kõne käib! + + + General + Üldine + + + + GeneralSettings + + General Settings + Üldseaded + + + The translation may not load until qTox restarts. + Tõlke aktiveerimiseks tuleb qTox võib-olla uuesti käivitada. + + + Language: + Keel: + + + Start qTox on operating system startup (current profile). + Käivita qTox koos operatsioonisüsteemiga (kasutades käesolevat profiili). + + + Autostart + Automaatkäivitus + + + Check for updates on startup + Kontrolli käivitudes uuenduste olemasolu + + + Enable light tray icon. + toolTip for light icon setting + Kasuta süsteemisalves heledat ikooni. + + + Light icon + Hele ikoon + + + Show system tray icon + Kuva süsteemisalve ikooni + + + qTox will start minimized in tray. + toolTip for Start in tray setting + qTox on käivitudes nähtav vaid süsteemisalves. + + + Start in tray + Käivita süsteemisalves + + + After pressing minimize (_) qTox will minimize itself to tray, +instead of system taskbar. + toolTip for minimize to tray setting + Pärast akna vähendamise nupu (_) vajutamist ei taandu qTox mitte tegumiribale, +vaid süsteemisalve. + + + Minimize to tray + Vähenda süsteemisalve + + + After pressing close (X) qTox will minimize to tray, +instead of closing itself. + toolTip for close to tray setting + Pärast sulgemisnupu (X) vajutamist taandub qTox süsteemisalve, mitte ei sulgu. + + + Close to tray + Sulgemisel taandu süsteemisalve + + + Your status is changed to Away after set period of inactivity. + Sinu olekuks märgitakse pärast määratud aja möödumist "Eemal". + + + Auto away after (0 to disable): + Märgi olekuks "eemal", kui olen eemal (eiramiseks kirjuta 0): + + + Set to 0 to disable + Funktsiooni väljalülitamiseks sea väärtuseks 0 + + + Set where files will be saved. + Määra, kuhu failid salvestada. + + + Default directory to save files: + Vaikekaust failide salvestamiseks: + + + You can set this on a per-friend basis by right clicking them. + autoaccept cb tooltip + Sõbral paremklõpsu tehes saab seda seadistust iga kontakti puhul eraldi muuta. + + + Autoaccept files + Nõustu automaatselt failide vastuvõtmisega + + + Chat + Vestlus + + + On new message: + Uue sõnumi vastuvõtmisel: + + + Play a sound when you recieve message. + toolTip for Notify sound setting + Mängi sõnumi vastuvõtmisel heli. + + + Play sound + Mängi heli + + + Open qTox's window when you receive a new message and no window is open yet. + tooltip for Show window setting + Ava qToxi aken, kui saabub uus sõnum ja akent pole veel avatud. + + + Open window + Ava aken + + + Focus qTox when you receive message. + toolTip for Focus window setting + Sõnumi saabumisel sea fookus qToxi aknale. + + + Focus window + Sea fookus aknale + + + Show contacts' status changes + Näita muutusi kontaktide olekus + + + Always notify about new messages in groupchats. + toolTip for Group chat always notify + Grupivestlustes vastuvõetud uutest sõnumitest antakse alati teada. + + + Group chats always notify + Grupivestluste puhul teavita alati + + + If checked, groupchats will be placed at the top of the friends list, otherwise, they'll be placed below online friends. + toolTip for groupchat positioning + Kui see valik on aktiivne, pannakse grupivestlused sõbranimekirja tippu, vastasel juhul asetatakse need sisselogitud sõprade järele. + + + Place groupchats at top of friend list + Aseta grupivestlused sõbranimekirja algusesse + + + Messages you are trying to send to your friends when they are not online +will be sent to them when they appear online to you. + toolTip for Faux offline messaging setting + Ehk leidub mingi täpsem tõlgendus, peab täpsustama konteksti (st usutavasti siiski ei ole vaja vestlusvalmis olekut, vaid piisab mistahes nähtavast võrku ilmumisest) + Sõnumid, mida üritad saata ühendamata olekus sõpradele, toimetatakse nele kohale, +kui nad sulle nähtavaks muutuvad. + + + Faux offline messaging + Sõnumite edastamine ühendamata olekus sõpradele + + + Your contact list will be shown in compact mode. + toolTip for compact layout setting + Sinu kontaktide nimekirja kuvatakse kompaktsel kujul. + + + Compact contact list + Kompaktne kontaktide nimekiri + + + Multiple windows mode + Mitme akna tugi + + + Open each chat in an individual window + Ava iga vestlus eraldi aknas + + + Theme + Teema + + + Use emoticons + Kasuta emotikone + + + Smiley Pack: + Text on smiley pack label + Emotikonipakk: + + + Emoticon size: + Emotikoni suurus: + + + px + px + + + Style: + Stiil: + + + Theme color: + Teema värv: + + + Timestamp format: + Ajatempli vorming: + + + Date format: + Kuupäeva vorming: + + + Connection Settings + Ühenduse seaded + + + Enable IPv6 (recommended) + Text on a checkbox to enable IPv6 + Toeta IPv6 protokolli (soovitatav) + + + Disabling this allows, e.g., toxing over Tor. It adds load to the Tox network however, so uncheck only when necessary. + force tcp checkbox tooltip + Selle väljalülitamine võimaldab näiteks kasutada toxi üle Tor võrgu. +Samas koormab väljalülitamine Toxi võrku, seega lülita välja vaid vajaduse korral. + + + Enable UDP (recommended) + Text on checkbox to disable UDP + Toeta UDP protokolli + + + Proxy type: + Puhverserveri tüüp: + + + Address: + Text on proxy addr label + Aadress: + + + Port: + Text on proxy port label + Port: + + + None + Puudub + + + SOCKS5 + SOCKS5 + + + HTTP + HTTP + + + Reconnect + reconnect button + Ühendu uuesti + + + + GenericChatForm + + Save chat log + Salvesta vestluse logi + + + Not sent + Saatmata + + + Cleared + Eemaldatud + + + Start audio call + Alusta audiokõnet + + + Accept audio call + Võta audiokõne vastu + + + End audio call + Lõpeta audiokõne + + + Start video call + Alusta videokõnet + + + Accept video call + Võta videokõne vastu + + + End video call + Lõpeta videokõne + + + Send message + Saada sõnum + + + Smileys + Emotikonid + + + Send file(s) + Saada fail(e) + + + Send a screenshot + Saada kuvatõmmis + + + Clear displayed messages + Eemalda kuvatud teated + + + + GenericNetCamView + + Tox video + Tox video + + + Show Messages + Kuva sõnumeid + + + Hide Messages + Peida sõnumid + + + + GroupChatForm + + 1 user in chat + Number of users in chat + Vestluses osaleb 1 kasutaja + + + %1 users in chat + Number of users in chat + Vestluses osaleb %1 kasutajat + + + Start audio call + Alusta audiokõnet + + + Mute microphone + Vaigista mikrofon + + + Unmute microphone + Lülita mikrofon sisse + + + Mute call + Vaigista kõne + + + Unmute call + Lülita kõne heli sisse + + + End audio call + Lõpeta audiokõne + + + + GroupWidget + + Open chat in new window + Ava vestlus uues aknas + + + Remove chat from this window + Haagi vestlus sellest aknast lahti + + + Set title... + Sea pealkiri... + + + Quit group + Menu to quit a groupchat + Lahku grupivestlusest + + + 1 user in chat + Vestluses osaleb 1 kasutaja + + + %1 users in chat + Vestluses osaleb %1 kasutajat + + + + IdentitySettings + + Public Information + Avalik teave + + + Name: + Nimi: + + + Status: + Olekuteade: + + + Tox ID + Tox ID + + + This bunch of characters tells other Tox clients how to contact you. +Share it with your friends to communicate. + Tox ID tooltip + See märgijada annab teistele Tox võrgu liikmetele teada, kuidas sinuga ühendust saada. +Sõpradega suhtlemiseks jaga seda nendega. + + + Your Tox ID (click to copy) + Sinu Tox ID (klõpsa, et lõikemälusse kopeerida) + + + This QR code contains your Tox ID. You may share this with your friends as well. + See QR kood sisaldab sinu Tox ID-d. Sa võid ka seda sõpradega jagada. + + + Save image + Salvesta pilt + + + Copy image + Kopeeri pilt lõikemällu + + + Profile + Profiil + + + <p><a href="file:///Dir_Path"><span style=" text-decoration: NONE; color:#000000;">Current profile location: Dir_Path</span></a></p> + <p><a href="file:///Dir_Path"><span style=" text-decoration: NONE; color:#000000;">Käesoleva profiili asukoht: Dir_Path</span></a></p> + + + Rename profile. + tooltip for renaming profile button + Nimeta profiil ümber. + + + Rename + rename profile button + Nimeta ümber + + + Delete profile. + delete profile button tooltip + Kustuta profiil. + + + Delete + delete profile button + Kustuta + + + Allows you to export your Tox profile to a file. +Profile does not contain your history. + tooltip for profile exporting button + Võimaldab kopeerida sinu Toxi profiili faili. +Profiil ei sisalda vestluste ajalugu. + + + Export + export profile button + Ekspordi + + + Go back to the login screen + tooltip for logout button + Mine tagasi sisselogimise aknasse + + + Logout + import profile button + Logi välja + + + Remove password + Eemalda salasõna + + + Change password + Muuda salasõna + + + + LoadHistoryDialog + + Load History Dialog + Vestluste ajaloo laadimise aken + + + Load history from: + Lae vestluste ajalugu kp-st: + + + + LoginScreen + + Username: + Kasutajanimi: + + + Password: + Salasõna: + + + Confirm: + Korda salasõna: + + + Password strength: %p% + Salasõna tugevus: %p% + + + Create Profile + Loo profiil + + + If the profile does not have a password, qTox can skip the login screen + Kui profiil pole salasõnaga kaitstud, võib qTox sisselogimise aknast mööda minna, kui seda soovid + + + Load automatically + Lae automaatselt + + + Load + Lae + + + New Profile + Uus profiil + + + Load Profile + Lae profiil + + + Couldn't create a new profile + Uue profiili loomine ebaõnnestus + + + The username must not be empty. + Kasutajanimi ei tohi olla tühi. + + + The password must be at least 6 characters long. + Salasõna peab olema vähemalt 6 märki pikk. + + + The passwords you've entered are different. +Please make sure to enter same password twice. + Sisestatud salasõnad ei kattu. +Palun veendu, et sisestad mõlemal korral sama salasõna. + + + A profile with this name already exists. + Selle nimega profiil on juba olemas. + + + Unknown error: Couldn't create a new profile. +If you encountered this error, please report it. + Tundmatu viga: Uue profiili loomine luhtus. +Palun teavitage meid sellest veast. + + + Password protected profile can't be loaded automatically. + Salasõnaga kaitstud profiili ei saa automaatselt laadida. + + + Couldn't load profile + Profiili laadimine luhtus + + + There is no selected profile. + +You may want to create one. + Profiili pole valitud. + +Võimalik, et peaksid selle looma. + + + Couldn't load this profile + Selle profiili laadimine luhtus + + + This profile is already in use. + Seda profiili juba kasutatakse. + + + Profile already in use. Close other clients. + Profiili juba kasutatakse. Sulgege muud seda kasutavad rakendused. + + + Wrong password. + Vale salasõna. + + + + MainWindow + + Your name + Sinu nimi + + + Your status + Olekuteade + + + ... + ... + + + Add friends + Lisa sõpru + + + Create a group chat + Loo grupivestllus + + + View completed file transfers + Kuva lõpetatud failiülekandeid + + + Change your settings + Muuda oma seadeid + + + Close + Sulge + + + + Nexus + + Images (%1) + filetype filter + Pildid (%1) + + + View + OS X Menu bar + Vaade + + + Window + OS X Menu bar + Aken + + + Minimize + OS X Menu bar + Vähenda + + + Bring All to Front + OS X Menu bar + Too kõik esile + + + Exit Fullscreen + Ära kuva üle kogu ekraani + + + Enter Fullscreen + Kuva üle kogu ekraani + + + + NotificationEdgeWidget + + Unread message(s) + Parandada + + Lugemata sõnum + Lugemata sõnumit + + + + + PrivacyForm + + Confirmation + Kinnitus + + + Do you want to permanently delete all chat history? + Kas soovite vestluste ajalugu jäädavalt kustutada? + + + Privacy + Privaatsus + + + + PrivacySettings + + Your friends will be able to see when you are typing. + tooltip for typing notifications setting + Sinu sõbrad näevad, kui sa kirjutad. + + + Send typing notifications + Saada kirjutamise kohta signaal + + + Chat history keeping is still in development. +Save format changes are possible, which may result in data loss. + toolTip for Keep History setting + Vestluste ajaloo logimine on veel arendatav funktsioon. +Võimalik, et salvestamise vorming muutub, mis võib omakorda kaasa tuua andmekao. + + + Keep chat history + Säilita vestluste ajalugu + + + NoSpam is part of your Tox ID. +If you are being spammed with friend requests, you should change your NoSpam. +People will be unable to add you with your old ID, but you will keep your current friends. + toolTip for nospam + NoSpam kuulub sinu ID juurde. +Kui saad veidraid sõbrakutseid, peaksid NoSpam väärtust muutma. +Inimesed ei saa sind seejärel enam sinu vana ID-d kasutades sõbraks lisada, ent sinu praegused kontaktid säilivad. + + + NoSpam + NoSpam + + + NoSpam is a part of your ID that can be changed at will. +If you are getting spammed with friend requests, change the NoSpam. + NoSpam on osa sinu ID stringist, mida saab soovi korral muuta. +Kui saad hulgaliselt soovimatuid sõbrakutseid, muuda seda väärtust. + + + Generate random NoSpam + Loo juhuslik NoSpam + + + + ProfileForm + + Current profile: + Käesolev profiil: + + + Remove + Eemalda + + + Choose a profile picture + Vali profiilipilt + + + Error + Viga + + + Unable to open this file. + Ei suutnud seda faili avada. + + + Unable to read this image. + Ei suuda seda pilti lugeda. + + + The supplied image is too large. +Please use another image. + Pakutud pilt on liialt suur. +Palun kasuta teist pilti. + + + Rename "%1" + renaming a profile + Nimeta "%1" ümber + + + Profile already exists + rename failure title + Profiil on juba olemas + + + A profile named "%1" already exists. + rename confirm text + Profiil "%1" on juba olemas. + + + Failed to rename + rename failed title + Ümbernimetamine luhtus + + + Couldn't rename the profile to "%1" + Ei suutnud profiili kujule "%1" ümber nimetada + + + Export profile + save dialog title + Ekspordi profiil + + + Tox save file (*.tox) + save dialog filter + Tox profiili fail (*.tox) + + + Location not writable + Title of permissions popup + Asukoht pole kirjutatav + + + You do not have permission to write that location. Choose another, or cancel the save dialog. + text of permissions popup + Sul ei ole sellesse asukohta kirjutamiseks õigusi. Vali mõni muu või katkesta salvestamine. + + + Failed to copy file + Faili kopeerimine luhtus + + + The file you chose could not be written to. + Faili, mille sa valisid, ei ole võimalik kirjutada. + + + Really delete profile? + deletion confirmation title + Kas soovid tõesti profiili kustutada? + + + Are you sure you want to delete this profile? + deletion confirmation text + Oled kindel, et soovid seda profiili kustutada? + + + Save + save qr image + Salvesta + + + Save QrCode (*.png) + save dialog filter + Salvesta Qr kood (*.png) + + + Nothing to remove + Pole midagi eemaldada + + + Your profile does not have a password! + Sinu profiil pole salasõnaga kaitstud! + + + Really delete password? + deletion confirmation title + Soovid tõesti salasõna eemaldada? + + + Are you sure you want to delete your password? + deletion confirmation text + Oled sa kindel, et soovid oma salasõna eemaldada? + + + Please enter a new password. + Palun sisesta uus salasõna. + + + User Profile + Kasutaja profiil + + + This bunch of characters tells other Tox clients how to contact you. +Share it with your friends to communicate. + See märgijada annab teistele Tox võrgu liikmetele teada, kuidas sinuga ühendust saada. +Sõpradega suhtlemiseks jaga seda nendega. + + + + QObject + + Resizing + Suuruse muutmine + + + Tox URI to parse + Toxi URI, mida kasutada + + + Starts new instance and loads specified profile. + Pole parim tõlge + Käivitab uue üksuse ja laeb määratud profiili. + + + profile + profiil + + + An update is available, do you want to download it now? +It will be installed when qTox restarts. + Saadaval on uuendus, kas soovid seda praegu alla laadida? +See paigaldatakse qToxi taaskäivitamisel. + + + Version %1, %2 + Versioon %1, %2 + + + Update + The title of a message box + Uuendus + + + Incorrect response + Sobimatu vastus + + + No password in response + Vastus ei sisalda salasõna + + + Server doesn't support Toxme + Serveril puudub Toxme tugi + + + You must send POST requests to /api + POST päringud tuleb saata asukohta /api + + + Please try again using a HTTPS connection + Palun proovi uuesti, kasutades HTTPS ühendust + + + I was unable to read your encrypted payload + Ei suutnud edastada sisulist osa krüpteeritud andmetest + + + You're making too many requests. Wait an hour and try again + Teed liiga palju päringuid. Oota tunnike ja proovi uuesti + + + This name is already in use + See nimi on juba kasutuses + + + This Tox ID is already registered under another name + See Tox ID on juba teise nime all registreeritud + + + Please don't use a space in your name + Palun ära kasuta oma nimes tühikut + + + Password incorrect + Salasõna on vale + + + You can't use this name + Sa ei saa seda nime kasutada + + + Name not found + Nime ei leitud + + + Tox ID not sent + Tox ID-d ei saadetud + + + Lookup failed because the server replied with invalid data + Otsing nurjus, kuna server vastas sobimatute andmetega + + + That user does not exist + Seda kasutajat pole olemas + + + Internal lookup error. Please file a bug + Süsteemi töös esines otsimisel viga. Palun kirjutage selle kohta vearaport + + + Unknown error (%1) + Tundmatu viga (%1) + + + %1 here! Tox me maybe? + Default message in Tox URI friend requests. Write something appropriate! + %1 siin! Ehk liitud minuga Tox keskkonnas? + + + Error + Viga + + + qTox couldn't open your chat logs, they will be disabled. + qTox ei suutnud sinu vestluste logisid avada, need deaktiveeritakse. + + + Ignoring non-Tox file + popup title + Eiran faili, mis pole Tox vormingus + + + Warning: you've chosen a file that is not a Tox save file; ignoring. + popup text + Hoiatus: oled valinud faili, mis ei ole tox fail. Seda eiratakse. + + + Profile already exists + import confirm title + Profiil on juba olemas + + + A profile named "%1" already exists. Do you want to erase it? + import confirm text + Profiil nimega "%1" on juba olemas. Soovid seda kustutada? + + + Profile imported + Profiil imporditi + + + %1.tox was successfully imported + %1.tox imporditi edukalt + + + None + No camera device set + Määramata + + + Desktop + Desktop as a camera input for screen sharing + Töölaud + + + Default + Vaikimisi + + + Blue + Sinine + + + Olive + Oliivikarva + + + Red + Punane + + + Violet + Violetne + + + Incoming call... + Sissetulev kõne... + + + + RemoveFriendDialog + + Remove friend + Eemalda sõber + + + <html><head/><body><p>Are you sure you want to remove <span style=" font-weight:600;">&lt;name&gt;</span> from your contacts list?</p></body></html> + <html><head/><body><p>Oled kindel, et soovid <span style=" font-weight:600;">&lt;name&gt;</span> oma kontaktide nimekirjast eemaldada?</p></body></html> + + + Also remove chat history + Kustuta ka vestluste ajalugu + + + Remove + Eemalda + + + + ScreenshotGrabber + + Click and drag to select a region. Press <b>Space</b> to hide/show qTox window, or <b>Escape</b> to cancel. + Help text shown when no region has been selected yet + Ala valaimiseks klõpsa ja lohista. Vajuta <b>tühikut</b>, et kuvada/peita qToxi akent või <b>Escape</b> klahvi, et katkestada. + + + Press <b>Enter</b> to send a screenshot of the selection, <b>Space</b> to hide/show qTox window, or <b>Escape</b> to cancel. + Help text shown when a region has been selected + Vajuta <b>Enter</b> klahvi, et valitud alast kuvatõmmist saata, <b>tühikut</b>, et peita/kuvada qToxi akent või <b>Escape</b> klahvi, et katkestada. + + + + SetPasswordDialog + + Set your password + Sea salasõna + + + Confirm: + Korda salasõna: + + + Password: + Salasõna: + + + Password strength: %p% + Salasõna tugevus: %p% + + + The password is too short + Salasõna on liialt lühike + + + The password doesn't match. + Salasõnad ei kattu. + + + + Settings + + Circle #%1 + Suhtlusring #%1 + + + + ToxDNS + + The connection timed out + The DNS gives the Tox ID associated to toxme.se addresses + Ühendus aegus + + + This address does not exist + The DNS gives the Tox ID associated to toxme.se addresses + Seda aadressi pole olemas + + + Error while looking up DNS + The DNS gives the Tox ID associated to toxme.se addresses + Viga DNS kirje lahendamisel + + + No text record found + Error with the DNS + Tekstikirjet ei leitud + + + Unexpected number of values in text record + Error with the DNS + Tekstikirjes on sobimatu arv väärtusi + + + + ToxURIDialog + + Add a friend + Title of the window to add a friend through Tox URI + Lisa sõber + + + Do you want to add %1 as a friend? + Soovid sa %1 sõbraks lisada? + + + User ID: + Kasutaja ID: + + + Friend request message: + Sõbrakutsele lisatav teade: + + + Send + Send a friend request + Saada + + + Cancel + Don't send a friend request + Katkesta + + + + Widget + + Status + Olek + + + toxcore failed to start, the application will terminate after you close this message. + toxcore ei käivitunud. Kui selle teate sulgete, rakendus sulgub. + + + toxcore failed to start with your proxy settings. qTox cannot run; please modify your settings and restart. + popup text + toxcore ei suutnud sinu puhverserveri seadetega käivituda. qTox ei saa töötada; palun korrigeeri seadistust ja taaskäivita rakendus. + + + Executable file + popup title + Käivitatav fail + + + You have asked qTox to open an executable file. Executable files can potentially damage your computer. Are you sure want to open this file? + popup text + Oled palunud qToxil avada käivitatava faili. Sellised failid võivad teoreetiliselt sinu arvutit kahjustada. Kas oled kindel, et soovid faili avada? + + + Your name + Sinu nimi + + + Your status + Olekuteade + + + Couldn't request friendship + Ei suutnud sõbrustamispalvet edastada + + + away + contact status + eemal + + + busy + contact status + hõivatud + + + offline + contact status + ühendamata + + + online + contact status + Vestlusvalmis + + + %1 is now %2 + e.g. "Dubslow is now online" + %1 on nüüd %2 + + + Add friend + Lisa sõber + + + File transfers + Failiülekanded + + + Settings + Seaded + + + Profile + Profiil + + + Group invite + popup title + Kutse gruppi + + + %1 has invited you to a groupchat. Would you like to join? + popup text + %1 kutsus sind grupivestlusesse. Kas soovid liituda? + + + <Unknown> + Placeholder when we don't know someone's name in a group chat + <Tundmatu> + + + %1 has set the title to %2 + %1 seadis pealkirjaks %2 + + + Message failed to send + Sõnumi saatmine luhtus + + + Add new circle... + Lisa uus suhtlusring... + + + By Name + Nime järgi + + + By Activity + Tegevuse järgi + + + All + Kõik + + + Online + Vestlusvalmis + + + Offline + Ühendamata + + + Friends + Sõbrad + + + Groups + Grupid + + + Search Contacts + Otsi kontaktide seast + + + Online + Button to set your status to 'Online' + Vestlusvalmis + + + Away + Button to set your status to 'Away' + Eemal + + + Busy + Button to set your status to 'Busy' + Hõivatud + + + Logout + Tray action menu to logout user + Logi välja + + + Exit + Tray action menu to exit tox + Sulge + + + Filter... + Filtreeri... + + + File + Fail + + + Edit + Redigeeri + + + Contacts + Kontaktid + + + Change Status + Muuda olekut + + + Edit Profile + Muuda profiili + + + Log out + Logi välja + + + Add Contact... + Lisa kontakt... + + + Next Conversation + Järgmine vestlus + + + Previous Conversation + Eelmine vestlus + + + diff --git a/translations/i18n.pri b/translations/i18n.pri index a76986326..8d5ab7d0f 100644 --- a/translations/i18n.pri +++ b/translations/i18n.pri @@ -5,6 +5,7 @@ TRANSLATIONS = translations/es.ts \ translations/bg.ts \ translations/de.ts \ translations/el.ts \ + translations/et.ts \ translations/fi.ts \ translations/fr.ts \ translations/hr.ts \ From ef608e13616c980a713488f22397ed3c3f98ba25 Mon Sep 17 00:00:00 2001 From: RowenStipe Date: Thu, 18 Feb 2016 14:28:46 -0500 Subject: [PATCH 201/210] Condensed a little bit and fixed function name --- osx/qTox-Mac-Deployer-ULTIMATE.sh | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/osx/qTox-Mac-Deployer-ULTIMATE.sh b/osx/qTox-Mac-Deployer-ULTIMATE.sh index c5a09fd18..c84acaa3d 100755 --- a/osx/qTox-Mac-Deployer-ULTIMATE.sh +++ b/osx/qTox-Mac-Deployer-ULTIMATE.sh @@ -24,20 +24,16 @@ # Your home DIR really (Most of this happens in it) {DONT USE: ~ } if [[ $TRAVIS = true ]]; then #travis check MAIN_DIR="${TRAVIS_BUILD_DIR}" + QTOX_DIR="${MAIN_DIR}" else MAIN_DIR="/Users/${USER}" + QTOX_DIR="${MAIN_DIR}/qTox" fi QT_DIR="/usr/local/Cellar/qt5" # Folder name of QT install VER="${QT_DIR}/5.5.1_2" # Potential future proffing for version testing QMAKE="${VER}/bin/qmake" # Don't change MACDEPLOYQT="${VER}/bin/macdeployqt" # Don't change -if [[ $TRAVIS = true ]]; then #travis check - QTOX_DIR="${MAIN_DIR}" -else - QTOX_DIR="${MAIN_DIR}/qTox" # Change to Git location -fi - TOXCORE_DIR="${MAIN_DIR}/toxcore" # Change to Git location FA_DIR="${MAIN_DIR}/filter_audio" @@ -178,7 +174,7 @@ function update() { git pull read -r -p "Did Toxcore update from git? [y/N] " response if [[ $response =~ ^([yY][eE][sS]|[yY])$ ]]; then - build-toxcore + build_toxcore else fcho "Moving on!" fi From 839582cbed698373021dd6063494de53fdf502da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Twyz=E2=84=A2?= Date: Sun, 21 Feb 2016 12:53:26 +0100 Subject: [PATCH 202/210] Updated Italian translation --- translations/it.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/translations/it.ts b/translations/it.ts index 1380c688f..035d0300a 100644 --- a/translations/it.ts +++ b/translations/it.ts @@ -244,7 +244,7 @@ p, li { white-space: pre-wrap; } Remove history (operation can not be undone!) - Rimuovi la cronologia (questa operazione non può essere cancellata!) + Rimuovi la cronologia (questa operazione non può essere annullata!) Notes @@ -252,7 +252,7 @@ p, li { white-space: pre-wrap; } You can save comment about this contact here. - È possibile salvare un commento su questo contatto qui. + È possibile salvare un commento per questo contatto. Choose an auto accept directory @@ -1710,7 +1710,7 @@ I profili non contengono la cronologia messaggi. Load history from: - Carica cronologia chat del giorno: + Carica cronologia chat dal giorno: From 719e137582f45c09908090946d198d8115bf93d1 Mon Sep 17 00:00:00 2001 From: Corey Sheldon Date: Mon, 22 Feb 2016 05:48:55 -0500 Subject: [PATCH 203/210] Updated sqlcipher compile instructions for Fedora --- INSTALL.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/INSTALL.md b/INSTALL.md index a2d071816..06c746849 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -380,6 +380,7 @@ sudo make install If you are not using Fedora, skip this section, and go directly to compiling [**toxcore**](#toxcore-compiling). ```bash +This method Auto detects whether to statically or Dynamically link per your system configs. git clone https://github.com/sqlcipher/sqlcipher cd sqlcipher autoreconf -if @@ -387,6 +388,24 @@ autoreconf -if make -j$(nproc) sudo make install cd .. + + +Conversely, if you wish to explictly statically or dynamically link sqlcipher use: + +Statically Linked: +cd sqlpcipher +$ ./configure --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC" \ + LDFLAGS="/opt/local/lib/libcrypto.a" +$ make +$ sudo make install +cd .. + +Dynamically Linked: +cd sqlcipher$ ./configure --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC" \ + LDFLAGS="-lcrypto" +$ make +$ sudo make install +cd .. ```` ### toxcore compiling From b98e8c745a8a37c2116f087bb5bf215de485d926 Mon Sep 17 00:00:00 2001 From: Corey Sheldon Date: Thu, 25 Feb 2016 19:38:25 -0500 Subject: [PATCH 204/210] Updated sqlcipher compile instructions for Fedora (Take #2) - Cleaned up the code blocks - Removed unneeded whitespace throughout previous commit --- INSTALL.md | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index 06c746849..ad9012cb7 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -366,9 +366,8 @@ The script will automatically download and install `toxcore` and `libfilteraudio ``` If you've used script, you can skip directly to [compiling qTox](#compile-qtox). - If you want to compile and install it manually: -```bash +``` git clone https://github.com/irungentoo/filter_audio cd filter_audio make -j$(nproc) @@ -379,8 +378,8 @@ sudo make install If you are not using Fedora, skip this section, and go directly to compiling [**toxcore**](#toxcore-compiling). -```bash -This method Auto detects whether to statically or Dynamically link per your system configs. +This method Auto detects whether to statically or Dynamically link per your system configs. +``` git clone https://github.com/sqlcipher/sqlcipher cd sqlcipher autoreconf -if @@ -388,25 +387,30 @@ autoreconf -if make -j$(nproc) sudo make install cd .. +``` +If you wish to explictly statically or dynamically link sqlcipher use: - -Conversely, if you wish to explictly statically or dynamically link sqlcipher use: - -Statically Linked: +#### Statically Linked: +``` +git clone https://github.com/sqlcipher/sqlcipher cd sqlpcipher -$ ./configure --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC" \ +./configure --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC" \ LDFLAGS="/opt/local/lib/libcrypto.a" -$ make -$ sudo make install +make +sudo make install cd .. +``` -Dynamically Linked: -cd sqlcipher$ ./configure --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC" \ +#### Dynamically Linked: +``` +git clone https://github.com/sqlcipher/sqlcipher +cd sqlcipher +./configure --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC" \ LDFLAGS="-lcrypto" -$ make -$ sudo make install +make +sudo make install cd .. -```` +``` ### toxcore compiling From 17f13459b6be0b7797e9db60765c154d5979bf9d Mon Sep 17 00:00:00 2001 From: sudden6 Date: Sat, 27 Feb 2016 12:40:36 +0100 Subject: [PATCH 205/210] disable filteraudio, because it makes audio quality worse --- src/widget/form/settings/avform.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/widget/form/settings/avform.cpp b/src/widget/form/settings/avform.cpp index 849eaa3f2..2d3135d72 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -46,13 +46,16 @@ AVForm::AVForm() : bodyUI->btnPlayTestSound->setToolTip( tr("Play a test sound while changing the output volume.")); - #ifdef QTOX_FILTER_AUDIO bodyUI->filterAudio->setChecked(Settings::getInstance().getFilterAudio()); #else bodyUI->filterAudio->setDisabled(true); #endif + // temporary remove audio filtering, because it makes audio quality worse + Settings::getInstance().setFilterAudio(false); + bodyUI->filterAudio->hide(); + auto qcbxIndexChangedStr = (void(QComboBox::*)(const QString&)) &QComboBox::currentIndexChanged; auto qcbxIndexChangedInt = (void(QComboBox::*)(int)) &QComboBox::currentIndexChanged; connect(bodyUI->inDevCombobox, qcbxIndexChangedStr, this, &AVForm::onInDevChanged); From e5cc004edf97a718b893f5f31f3c1a2ea4e64202 Mon Sep 17 00:00:00 2001 From: sudden6 Date: Sat, 27 Feb 2016 14:51:30 +0100 Subject: [PATCH 206/210] Revert "disable filteraudio, because it makes audio quality worse" This reverts commit 17f13459b6be0b7797e9db60765c154d5979bf9d. --- src/widget/form/settings/avform.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/widget/form/settings/avform.cpp b/src/widget/form/settings/avform.cpp index 2d3135d72..849eaa3f2 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -46,16 +46,13 @@ AVForm::AVForm() : bodyUI->btnPlayTestSound->setToolTip( tr("Play a test sound while changing the output volume.")); + #ifdef QTOX_FILTER_AUDIO bodyUI->filterAudio->setChecked(Settings::getInstance().getFilterAudio()); #else bodyUI->filterAudio->setDisabled(true); #endif - // temporary remove audio filtering, because it makes audio quality worse - Settings::getInstance().setFilterAudio(false); - bodyUI->filterAudio->hide(); - auto qcbxIndexChangedStr = (void(QComboBox::*)(const QString&)) &QComboBox::currentIndexChanged; auto qcbxIndexChangedInt = (void(QComboBox::*)(int)) &QComboBox::currentIndexChanged; connect(bodyUI->inDevCombobox, qcbxIndexChangedStr, this, &AVForm::onInDevChanged); From 685d91f0a355b0a2757d75b6edd67b688261e486 Mon Sep 17 00:00:00 2001 From: sudden6 Date: Sat, 27 Feb 2016 14:59:21 +0100 Subject: [PATCH 207/210] Completely remove filteraudio checkbox from the ui --- src/persistence/settings.cpp | 3 +- src/widget/form/settings/avform.cpp | 15 +---- src/widget/form/settings/avsettings.ui | 80 +++++++++++--------------- 3 files changed, 38 insertions(+), 60 deletions(-) diff --git a/src/persistence/settings.cpp b/src/persistence/settings.cpp index e5dd2dc86..73e6d6cc1 100644 --- a/src/persistence/settings.cpp +++ b/src/persistence/settings.cpp @@ -1239,7 +1239,8 @@ void Settings::setOutVolume(int volume) bool Settings::getFilterAudio() const { QMutexLocker locker{&bigLock}; - return filterAudio; + // temporary disable filteraudio, as it doesn't work as expected + return false; } void Settings::setFilterAudio(bool newValue) diff --git a/src/widget/form/settings/avform.cpp b/src/widget/form/settings/avform.cpp index 849eaa3f2..ab40173b4 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -47,20 +47,12 @@ AVForm::AVForm() : bodyUI->btnPlayTestSound->setToolTip( tr("Play a test sound while changing the output volume.")); -#ifdef QTOX_FILTER_AUDIO - bodyUI->filterAudio->setChecked(Settings::getInstance().getFilterAudio()); -#else - bodyUI->filterAudio->setDisabled(true); -#endif - auto qcbxIndexChangedStr = (void(QComboBox::*)(const QString&)) &QComboBox::currentIndexChanged; auto qcbxIndexChangedInt = (void(QComboBox::*)(int)) &QComboBox::currentIndexChanged; connect(bodyUI->inDevCombobox, qcbxIndexChangedStr, this, &AVForm::onInDevChanged); connect(bodyUI->outDevCombobox, qcbxIndexChangedStr, this, &AVForm::onOutDevChanged); connect(bodyUI->videoDevCombobox, qcbxIndexChangedInt, this, &AVForm::onVideoDevChanged); connect(bodyUI->videoModescomboBox, qcbxIndexChangedInt, this, &AVForm::onVideoModesIndexChanged); - - connect(bodyUI->filterAudio, &QCheckBox::toggled, this, &AVForm::onFilterAudioToggled); connect(bodyUI->rescanButton, &QPushButton::clicked, this, [=]() { getAudioInDevices(); @@ -87,11 +79,6 @@ AVForm::AVForm() : cb->setFocusPolicy(Qt::StrongFocus); } - for (QCheckBox *cb : findChildren()) // this one is to allow scrolling on checkboxes - { - cb->installEventFilter(this); - } - Translator::registerHandler(std::bind(&AVForm::retranslateUi, this), this); } @@ -415,7 +402,7 @@ void AVForm::killVideoSurface() bool AVForm::eventFilter(QObject *o, QEvent *e) { if ((e->type() == QEvent::Wheel) && - (qobject_cast(o) || qobject_cast(o) || qobject_cast(o) || qobject_cast(o))) + (qobject_cast(o) || qobject_cast(o) || qobject_cast(o))) { e->ignore(); return true; diff --git a/src/widget/form/settings/avsettings.ui b/src/widget/form/settings/avsettings.ui index ee2cada0a..187f6f391 100644 --- a/src/widget/form/settings/avsettings.ui +++ b/src/widget/form/settings/avsettings.ui @@ -30,8 +30,8 @@ 0 0 - 830 - 495 + 824 + 489 @@ -41,27 +41,13 @@ Audio Settings - - - - Playback device - - - - - - - Volume - - - - - + + - Use slider to set volume of your speakers. + Use slider to set volume of your microphone. 100 @@ -71,6 +57,23 @@ + + + + Gain + + + + + + + + + + Playback device + + + @@ -85,27 +88,10 @@ - - - - Capture device - - - - - - - - - - Gain - - - - - + + - Use slider to set volume of your microphone. + Use slider to set volume of your speakers. 100 @@ -115,13 +101,17 @@ - - - - Filter sound from your microphone, so that people hearing you would get better sound. - + + - Filter audio + Capture device + + + + + + + Volume From e5e4d561c95cfaaa116999c5bcb592afd679cbf1 Mon Sep 17 00:00:00 2001 From: Zetok Zalbavar Date: Thu, 25 Feb 2016 06:48:36 +0000 Subject: [PATCH 208/210] fix(osx-script): remove unnecessary usage of `sudo` Neither toxcore or filter_audio require `sudo` to be installed under `libs/`. --- osx/qTox-Mac-Deployer-ULTIMATE.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osx/qTox-Mac-Deployer-ULTIMATE.sh b/osx/qTox-Mac-Deployer-ULTIMATE.sh index 49b4bc183..927536407 100755 --- a/osx/qTox-Mac-Deployer-ULTIMATE.sh +++ b/osx/qTox-Mac-Deployer-ULTIMATE.sh @@ -77,7 +77,7 @@ function build_toxcore() { fcho "Compiling toxcore." make > /dev/null || exit 1 fcho "Installing toxcore." - sudo make install > /dev/null || exit 1 + make install > /dev/null || exit 1 } function install() { @@ -144,7 +144,7 @@ function install() { cd $FA_DIR fi fcho "Installing filter_audio." - sudo make install PREFIX="${LIB_INSTALL_PREFIX}" + make install PREFIX="${LIB_INSTALL_PREFIX}" # toxcore build if [[ $TRAVIS = true ]]; then #travis check From ffa0c2136e5f2ebc7bc5edb53b3fb065624dc908 Mon Sep 17 00:00:00 2001 From: "Vittorio G (VittGam)" Date: Sun, 28 Feb 2016 16:24:50 +0100 Subject: [PATCH 209/210] Fix toxURI parsing. It was always eating two characters more than needed. A toxURI passed to handleToxURI always starts with "tox:", it's checked in the handleToxURI callers. So here we need to remove that prefix, that's long 4 characters and not 6. The previous code was meant to handle tox:// and tox: cases, but the tox:// case is invalid and should not be handled (see #2118). Fixes: d6a0910fc8098ecb37d7f7fdfcdd2592adaac0ad ("fix uri parsing and tox URI detection, closes #2118") --- src/net/toxuri.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/net/toxuri.cpp b/src/net/toxuri.cpp index d4c8714cb..934e44486 100644 --- a/src/net/toxuri.cpp +++ b/src/net/toxuri.cpp @@ -57,11 +57,7 @@ bool handleToxURI(const QString &toxURI) while (!core->isReady()) qApp->processEvents(); - QString toxaddr; - if (toxURI.startsWith("tox:")) - toxaddr = toxURI.mid(6); - else - toxaddr = toxURI.mid(4); + QString toxaddr = toxURI.mid(4); QString toxId = Toxme::lookup(toxaddr).toString(); if (toxId.isEmpty()) From 318de322bffcbac088ee9c36966d83ce40e9f87a Mon Sep 17 00:00:00 2001 From: tux3 Date: Fri, 11 Mar 2016 23:27:32 +0100 Subject: [PATCH 210/210] Fix #2849 Make the auto-updater aware of portable mode --- updater/main.cpp | 7 ++- updater/settings.cpp | 135 +++++++++++++++++++++++++++++++++++++++++++ updater/settings.h | 29 ++++++++++ updater/updater.pro | 6 +- updater/widget.cpp | 121 ++++---------------------------------- updater/widget.h | 10 +--- 6 files changed, 185 insertions(+), 123 deletions(-) create mode 100755 updater/settings.cpp create mode 100755 updater/settings.h diff --git a/updater/main.cpp b/updater/main.cpp index 68067a60b..82e635681 100644 --- a/updater/main.cpp +++ b/updater/main.cpp @@ -19,6 +19,7 @@ #include "widget.h" +#include "settings.h" #include #include #include @@ -77,10 +78,10 @@ int main(int argc, char *argv[]) { qInstallMessageHandler(logMessageHandler); QApplication a(argc, argv); + Settings s; logFileStream.reset(new QTextStream); - logFileFile.reset(new QFile(QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + QDir::separator() - + "AppData" + QDir::separator() + "Roaming" + QDir::separator() + "tox")+QDir::separator()+"qtox.log")); + logFileFile.reset(new QFile(s.getSettingsDirPath()+"qtox.log")); if (logFileFile->open(QIODevice::Append)) { logFileStream->setDevice(logFileFile.get()); @@ -97,7 +98,7 @@ int main(int argc, char *argv[]) GetUserNameA(buf, &bufsize); qDebug() << "Updater running as user" << buf; - Widget w; + Widget w(s); w.show(); return a.exec(); diff --git a/updater/settings.cpp b/updater/settings.cpp new file mode 100755 index 000000000..670bc20a8 --- /dev/null +++ b/updater/settings.cpp @@ -0,0 +1,135 @@ +#include "settings.h" +#include +#include +#include +#include +#include + +#ifdef Q_OS_WIN +#ifdef _WIN32_WINNT +#undef _WIN32_WINNT +#endif +#define _WIN32_WINNT 0x0600 // Vista for SHGetKnownFolderPath +#include +#include +#include +#include +#endif + +Settings::Settings() +{ + portable = false; + QFile portableSettings(SETTINGS_FILE); + if (portableSettings.exists()) + { + QSettings ps(SETTINGS_FILE, QSettings::IniFormat); + ps.beginGroup("General"); + portable = ps.value("makeToxPortable", false).toBool(); + } + qDebug() << "Portable: "< + +#ifdef Q_OS_WIN +#include +#endif + +class Settings +{ +public: + Settings(); + ~Settings(); + + QString getSettingsDirPath() const; ///< The returned path ends with a directory separator +#ifdef Q_OS_WIN + HANDLE getPrimaryToken() const; ///< Used to impersonnate the unelevated user +#endif + +private: + bool portable; + static constexpr const char* SETTINGS_FILE = "qtox.ini"; +#ifdef Q_OS_WIN + HANDLE hPrimaryToken; +#endif +}; + +#endif // SETTINGS_H diff --git a/updater/updater.pro b/updater/updater.pro index c52a12459..b6e8b99d7 100644 --- a/updater/updater.pro +++ b/updater/updater.pro @@ -18,11 +18,13 @@ QMAKE_CXXFLAGS += -fno-exceptions SOURCES += main.cpp\ widget.cpp \ update.cpp \ - serialize.cpp + serialize.cpp \ + settings.cpp HEADERS += widget.h \ update.h \ - serialize.h + serialize.h \ + settings.h FORMS += widget.ui diff --git a/updater/widget.cpp b/updater/widget.cpp index 4ea315f69..6e90e6717 100644 --- a/updater/widget.cpp +++ b/updater/widget.cpp @@ -50,9 +50,10 @@ const QString QTOX_PATH; #endif const QString SETTINGS_FILE = "settings.ini"; -Widget::Widget(QWidget *parent) : - QWidget(parent), - ui(new Ui::Widget) +Widget::Widget(const Settings &s) : + QWidget(nullptr), + ui(new Ui::Widget), + settings{s} { ui->setupUi(this); @@ -60,66 +61,11 @@ Widget::Widget(QWidget *parent) : if (!supported) fatalError(tr("The qTox updater is not supported on this platform.")); -#ifdef Q_OS_WIN - // Get a primary unelevated token of the actual user - hPrimaryToken = nullptr; - HANDLE hShellProcess = nullptr, hShellProcessToken = nullptr; - const DWORD dwTokenRights = TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_ASSIGN_PRIMARY - | TOKEN_DUPLICATE | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID; - DWORD dwPID = 0; - HWND hwnd = nullptr; - DWORD dwLastErr = 0; - - // Enable SeIncreaseQuotaPrivilege - HANDLE hProcessToken = NULL; - if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hProcessToken)) - goto unelevateFail; - TOKEN_PRIVILEGES tkp; - tkp.PrivilegeCount = 1; - LookupPrivilegeValueW(NULL, SE_INCREASE_QUOTA_NAME, &tkp.Privileges[0].Luid); - tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - AdjustTokenPrivileges(hProcessToken, FALSE, &tkp, 0, NULL, NULL); - dwLastErr = GetLastError(); - CloseHandle(hProcessToken); - if (ERROR_SUCCESS != dwLastErr) - goto unelevateFail; - - // Get a primary copy of the desktop shell's token, - // we're assuming the shell is running as the actual user - hwnd = GetShellWindow(); - if (!hwnd) - goto unelevateFail; - GetWindowThreadProcessId(hwnd, &dwPID); - if (!dwPID) - goto unelevateFail; - hShellProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPID); - if (!hShellProcess) - goto unelevateFail; - if (!OpenProcessToken(hShellProcess, TOKEN_DUPLICATE, &hShellProcessToken)) - goto unelevateFail; - - // Duplicate the shell's process token to get a primary token. - // Based on experimentation, this is the minimal set of rights required for CreateProcessWithTokenW (contrary to current documentation). - if (!DuplicateTokenEx(hShellProcessToken, dwTokenRights, NULL, SecurityImpersonation, TokenPrimary, &hPrimaryToken)) - goto unelevateFail; - - qDebug() << "Unelevated primary access token acquired"; - goto unelevateCleanup; -unelevateFail: - qWarning() << "Unelevate failed, couldn't get access token"; -unelevateCleanup: - CloseHandle(hShellProcessToken); - CloseHandle(hShellProcess); -#endif - QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection); } Widget::~Widget() { -#ifdef Q_OS_WIN - CloseHandle(hPrimaryToken); -#endif delete ui; } @@ -141,7 +87,7 @@ void Widget::fatalError(QString message) void Widget::deleteUpdate() { - QDir updateDir(getSettingsDirPath()+"/update/"); + QDir updateDir(settings.getSettingsDirPath()+"/update/"); updateDir.removeRecursively(); } @@ -164,7 +110,9 @@ void Widget::startQToxAndExit() GetProcAddress(advapi32H, "CreateProcessWithTokenW"); if ((unelevateOk = (CreateProcessWithTokenWH != nullptr))) { - if (!CreateProcessWithTokenWH(hPrimaryToken, 0, QTOX_PATH.toStdWString().c_str(), 0, 0, 0, 0, &si, &pi)) + if (!CreateProcessWithTokenWH(settings.getPrimaryToken(), 0, + QTOX_PATH.toStdWString().c_str(), 0, 0, 0, + QApplication::applicationDirPath().toStdWString().c_str(), &si, &pi)) unelevateOk = false; } } @@ -196,60 +144,11 @@ void Widget::restoreBackups() QFile(file+".bak").rename(file); } -QString Widget::getSettingsDirPath() -{ - if (isToxPortableEnabled()) - return "."; - -#ifdef Q_OS_WIN - wchar_t* path; - bool isOld = false; // If true, we can't unelevate and just return the path for our current home - - auto shell32H = LoadLibrary(TEXT("shell32.dll")); - if (!(isOld = (shell32H == nullptr))) - { - auto SHGetKnownFolderPathH = (decltype(&SHGetKnownFolderPath)) - GetProcAddress(shell32H, "SHGetKnownFolderPath"); - if (!(isOld = (SHGetKnownFolderPathH == nullptr))) - SHGetKnownFolderPathH(FOLDERID_RoamingAppData, 0, hPrimaryToken, &path); - } - - if (isOld) - { - return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + QDir::separator() - + "AppData" + QDir::separator() + "Roaming" + QDir::separator() + "tox" + QDir::separator()); - } - else - { - QString pathStr = QString::fromStdWString(path); - pathStr.replace("\\", "/"); - return pathStr + "/tox"; - } -#else - return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QDir::separator() + "tox"); -#endif -} - -bool Widget::isToxPortableEnabled() -{ - QFile portableSettings(SETTINGS_FILE); - if (portableSettings.exists()) - { - QSettings ps(SETTINGS_FILE, QSettings::IniFormat); - ps.beginGroup("General"); - return ps.value("makeToxPortable", false).toBool(); - } - else - { - return false; - } -} - void Widget::update() { /// 1. Find and parse the update (0-5%) // Check that the dir exists - QString updateDirStr = getSettingsDirPath()+"/update/"; + QString updateDirStr = settings.getSettingsDirPath()+"/update/"; QDir updateDir(updateDirStr); if (!updateDir.exists()) fatalError(tr("No update found.")); @@ -259,7 +158,7 @@ void Widget::update() // Check that we have a flist and that every file on the diff exists QFile updateFlistFile(updateDirStr+"flist"); if (!updateFlistFile.open(QIODevice::ReadOnly)) - fatalError(tr("The update is incomplete.")); + fatalError(tr("The update is incomplete!")); QByteArray updateFlistData = updateFlistFile.readAll(); updateFlistFile.close(); diff --git a/updater/widget.h b/updater/widget.h index 155291ea5..f9368faac 100644 --- a/updater/widget.h +++ b/updater/widget.h @@ -21,6 +21,7 @@ #ifndef WIDGET_H #define WIDGET_H +#include "settings.h" #include #ifdef Q_OS_WIN @@ -36,15 +37,13 @@ class Widget : public QWidget Q_OBJECT public: - explicit Widget(QWidget *parent = 0); + explicit Widget(const Settings& s); ~Widget(); // Utilities void deleteBackups(); void restoreBackups(); void setProgress(int value); - QString getSettingsDirPath(); - bool isToxPortableEnabled(); // Noreturn void fatalError(QString message); ///< Calls deleteUpdate and startQToxAndExit @@ -58,10 +57,7 @@ public slots: private: Ui::Widget *ui; QStringList backups; - -#ifdef Q_OS_WIN - HANDLE hPrimaryToken; -#endif + const Settings& settings; }; #endif // WIDGET_H