kepka/Telegram/SourceFiles/platform/linux/main_window_linux.cpp

221 lines
6.9 KiB
C++

//
// This file is part of Kepka,
// an unofficial desktop version of Telegram messaging app,
// see https://github.com/procxx/kepka
//
// Kepka is free 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.
//
// It 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.
//
// In addition, as a special exception, the copyright holders give permission
// to link the code of portions of this program with the OpenSSL library.
//
// Full license: https://github.com/procxx/kepka/blob/master/LICENSE
// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx
//
#include "platform/linux/main_window_linux.h"
#include "app.h"
#include "application.h"
#include "facades.h"
#include "lang/lang_keys.h"
#include "mainwindow.h"
#include "messenger.h"
#include "platform/platform_notifications_manager.h"
#include "storage/localstorage.h"
#include "styles/style_window.h"
namespace Platform {
namespace {
qint32 _trayIconSize = 22;
bool _trayIconMuted = true;
qint32 _trayIconCount = 0;
QImage _trayIconImageBack, _trayIconImage;
#define QT_RED 0
#define QT_GREEN 1
#define QT_BLUE 2
#define QT_ALPHA 3
QImage _trayIconImageGen() {
qint32 counter = App::histories().unreadBadge(),
counterSlice = (counter >= 1000) ? (1000 + (counter % 100)) : counter;
bool muted = App::histories().unreadOnlyMuted();
if (_trayIconImage.isNull() || _trayIconImage.width() != _trayIconSize || muted != _trayIconMuted ||
counterSlice != _trayIconCount) {
if (_trayIconImageBack.isNull() || _trayIconImageBack.width() != _trayIconSize) {
_trayIconImageBack = Messenger::Instance().logo().scaled(_trayIconSize, _trayIconSize,
Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
_trayIconImageBack = _trayIconImageBack.convertToFormat(QImage::Format_ARGB32);
int w = _trayIconImageBack.width(), h = _trayIconImageBack.height(),
perline = _trayIconImageBack.bytesPerLine();
uchar *bytes = _trayIconImageBack.bits();
for (qint32 y = 0; y < h; ++y) {
for (qint32 x = 0; x < w; ++x) {
qint32 srcoff = y * perline + x * 4;
bytes[srcoff + QT_RED] = qMax(bytes[srcoff + QT_RED], uchar(224));
bytes[srcoff + QT_GREEN] = qMax(bytes[srcoff + QT_GREEN], uchar(165));
bytes[srcoff + QT_BLUE] = qMax(bytes[srcoff + QT_BLUE], uchar(44));
}
}
}
_trayIconImage = _trayIconImageBack;
if (counter > 0) {
QPainter p(&_trayIconImage);
qint32 layerSize = -16;
if (_trayIconSize >= 48) {
layerSize = -32;
} else if (_trayIconSize >= 36) {
layerSize = -24;
} else if (_trayIconSize >= 32) {
layerSize = -20;
}
auto &bg = (muted ? st::trayCounterBgMute : st::trayCounterBg);
auto &fg = st::trayCounterFg;
auto layer = App::wnd()->iconWithCounter(layerSize, counter, bg, fg, false);
p.drawImage(_trayIconImage.width() - layer.width() - 1, _trayIconImage.height() - layer.height() - 1,
layer);
}
}
return _trayIconImage;
}
QString _trayIconImageFile() {
qint32 counter = App::histories().unreadBadge(),
counterSlice = (counter >= 1000) ? (1000 + (counter % 100)) : counter;
bool muted = App::histories().unreadOnlyMuted();
QString name = cWorkingDir() +
qsl("tdata/ticons/ico%1_%2_%3.png").arg(muted ? "mute" : "").arg(_trayIconSize).arg(counterSlice);
QFileInfo info(name);
if (info.exists()) return name;
QImage img = _trayIconImageGen();
if (img.save(name, "PNG")) return name;
QDir dir(info.absoluteDir());
if (!dir.exists()) {
dir.mkpath(dir.absolutePath());
if (img.save(name, "PNG")) return name;
}
return QString();
}
} // namespace
bool MainWindow::hasTrayIcon() const {
return trayIcon;
}
void MainWindow::psSetupTrayIcon() {
if (!trayIcon) {
trayIcon = new QSystemTrayIcon(this);
QIcon icon;
QFileInfo iconFile(_trayIconImageFile());
if (iconFile.exists()) {
QByteArray path = QFile::encodeName(iconFile.absoluteFilePath());
icon = QIcon(path.constData());
} else {
icon = Window::CreateIcon();
}
trayIcon->setIcon(icon);
trayIcon->setToolTip(str_const_toString(AppName));
connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this,
SLOT(toggleTray(QSystemTrayIcon::ActivationReason)), Qt::UniqueConnection);
// This is very important for native notifications via libnotify!
// Some notification servers compose several notifications with a "Reply"
// action into one and after that a click on "Reply" button does not call
// the specified callback from any of the sent notification - libnotify
// just ignores ibus messages, but Qt tray icon at least emits this signal.
connect(trayIcon, SIGNAL(messageClicked()), this, SLOT(showFromTray()));
App::wnd()->updateTrayMenu();
}
updateIconCounters();
trayIcon->show();
}
void MainWindow::workmodeUpdated(DBIWorkMode mode) {
if (!cSupportTray()) return;
if (mode == dbiwmWindowOnly) {
if (trayIcon) {
trayIcon->setContextMenu(0);
trayIcon->deleteLater();
}
trayIcon = 0;
} else {
psSetupTrayIcon();
}
}
void MainWindow::unreadCounterChangedHook() {
setWindowTitle(titleText());
updateIconCounters();
}
void MainWindow::updateIconCounters() {
updateWindowIcon();
if (trayIcon) {
QIcon icon;
QFileInfo iconFile(_trayIconImageFile());
if (iconFile.exists()) {
QByteArray path = QFile::encodeName(iconFile.absoluteFilePath());
icon = QIcon(path.constData());
} else {
qint32 counter = App::histories().unreadBadge();
bool muted = App::histories().unreadOnlyMuted();
auto &bg = (muted ? st::trayCounterBgMute : st::trayCounterBg);
auto &fg = st::trayCounterFg;
icon.addPixmap(App::pixmapFromImageInPlace(iconWithCounter(16, counter, bg, fg, true)));
icon.addPixmap(App::pixmapFromImageInPlace(iconWithCounter(32, counter, bg, fg, true)));
}
trayIcon->setIcon(icon);
}
}
void MainWindow::psCreateTrayIcon() {
LOG(("Tray Icon: Using Qt tray icon, available: %1").arg(Logs::b(QSystemTrayIcon::isSystemTrayAvailable())));
cSetSupportTray(QSystemTrayIcon::isSystemTrayAvailable());
return;
}
void MainWindow::psFirstShow() {
psCreateTrayIcon();
show();
if (cWindowPos().maximized) {
DEBUG_LOG(("Window Pos: First show, setting maximized."));
setWindowState(Qt::WindowMaximized);
}
if ((cLaunchMode() == LaunchModeAutoStart && cStartMinimized()) || cStartInTray()) {
setWindowState(Qt::WindowMinimized);
if (Global::WorkMode().value() == dbiwmTrayOnly || Global::WorkMode().value() == dbiwmWindowAndTray) {
hide();
} else {
show();
}
} else {
show();
}
setPositionInited();
}
} // namespace Platform