new online / offline status update, notify delayed if other clients are active

This commit is contained in:
John Preston 2015-01-26 16:04:41 +03:00
parent 9cfaab6baf
commit dde1a5a6eb
20 changed files with 281 additions and 316 deletions

View File

@ -173,7 +173,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_settings_check_now" = "Check for updates";
"lng_settings_update_checking" = "Checking for updates..";
"lng_settings_latest_installed" = "Latest version is installed";
"lng_settings_downloading" = "Downloading update {ready} / {total} Mb..";
"lng_settings_downloading" = "Downloading update {ready} / {total} MB..";
"lng_settings_update_ready" = "New version is ready";
"lng_settings_update_now" = "Restart Now";
"lng_settings_update_fail" = "Update check failed :(";
@ -457,7 +457,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
// Wnd specific
"lng_wnd_choose_program_menu" = "Choose default program...";
"lng_wnd_choose_program_menu" = "Choose Default Program...";
// Mac specific

View File

@ -123,6 +123,7 @@ namespace App {
MainWidget *m(main());
if (m) m->destroyData();
MTP::authed(0);
cSetOtherOnline(0);
histories().clear();
globalNotifyAllPtr = UnknownNotifySettings;
globalNotifyUsersPtr = UnknownNotifySettings;

View File

@ -382,6 +382,7 @@ void Application::onWriteUserConfig() {
void Application::onAppStateChanged(Qt::ApplicationState state) {
checkLocalTime();
if (window) window->updateIsActive((state == Qt::ApplicationActive) ? cOnlineFocusTimeout() : cOfflineBlurTimeout());
}
void Application::killDownloadSessions() {
@ -707,9 +708,7 @@ void Application::startApp() {
}
}
// if (!cLangErrors().isEmpty()) {
// window->showLayer(new ConfirmBox("Custom lang failed :(\n\nError: " + cLangErrors(), true, lang(lng_close)));
// }
window->updateIsActive(cOnlineFocusTimeout());
}
void Application::socketDisconnected() {

View File

@ -131,6 +131,8 @@ private:
ClientSockets clients;
bool closing;
uint64 lastActionTime;
void execExternal(const QString &cmd);
Window *window;

View File

@ -260,7 +260,6 @@ enum {
MemoryForImageCache = 64 * 1024 * 1024, // after 64mb of unpacked images we try to clear some memory
NotifyWindowsCount = 3, // 3 desktop notifies at the same time
NotifyWaitTimeout = 1200, // 1.2 seconds timeout before notification
NotifySettingSaveTimeout = 1000, // wait 1 second before saving notify setting to server
UpdateChunk = 100 * 1024, // 100kb parts when downloading the update
IdleMsecs = 60 * 1000, // after 60secs without user input we think we are idle

View File

@ -2341,10 +2341,10 @@ void HistoryPhoto::draw(QPainter &p, const HistoryItem *parent, bool selected, i
QString formatSizeText(qint64 size) {
if (size >= 1024 * 1024) { // more than 1 mb
qint64 sizeTenthMb = (size * 10 / (1024 * 1024));
return QString::number(sizeTenthMb / 10) + '.' + QString::number(sizeTenthMb % 10) + qsl("Mb");
return QString::number(sizeTenthMb / 10) + '.' + QString::number(sizeTenthMb % 10) + qsl("MB");
}
qint64 sizeTenthKb = (size * 10 / 1024);
return QString::number(sizeTenthKb / 10) + '.' + QString::number(sizeTenthKb % 10) + qsl("Kb");
return QString::number(sizeTenthKb / 10) + '.' + QString::number(sizeTenthKb % 10) + qsl("KB");
}
QString formatDownloadText(qint64 ready, qint64 total) {
@ -2353,12 +2353,12 @@ QString formatDownloadText(qint64 ready, qint64 total) {
qint64 readyTenthMb = (ready * 10 / (1024 * 1024)), totalTenthMb = (total * 10 / (1024 * 1024));
readyStr = QString::number(readyTenthMb / 10) + '.' + QString::number(readyTenthMb % 10);
totalStr = QString::number(totalTenthMb / 10) + '.' + QString::number(totalTenthMb % 10);
mb = qsl("Mb");
mb = qsl("MB");
} else {
qint64 readyKb = (ready / 1024), totalKb = (total / 1024);
readyStr = QString::number(readyKb);
totalStr = QString::number(totalKb);
mb = qsl("Kb");
mb = qsl("KB");
}
return lng_save_downloaded(lt_ready, readyStr, lt_total, totalStr, lt_mb, mb);
}

View File

@ -350,16 +350,18 @@ MainWidget *TopBarWidget::main() {
MainWidget::MainWidget(Window *window) : QWidget(window), _started(0), failedObjId(0), _dialogsWidth(st::dlgMinWidth),
dialogs(this), history(this), profile(0), overview(0), _topBar(this), _forwardConfirm(0), hider(0), _mediaType(this), _mediaTypeMask(0),
updPts(0), updDate(0), updQts(-1), updSeq(0), updInited(false), onlineRequest(0), _failDifferenceTimeout(1), _lastUpdateTime(0) {
updPts(0), updDate(0), updQts(-1), updSeq(0), updInited(false), _onlineRequest(0), _lastWasOnline(false), _lastSetOnline(0), _isIdle(false),
_failDifferenceTimeout(1), _lastUpdateTime(0) {
setGeometry(QRect(0, st::titleHeight, App::wnd()->width(), App::wnd()->height() - st::titleHeight));
connect(window, SIGNAL(resized(const QSize &)), this, SLOT(onParentResize(const QSize &)));
connect(&dialogs, SIGNAL(cancelled()), this, SLOT(dialogsCancelled()));
connect(&history, SIGNAL(cancelled()), &dialogs, SLOT(activate()));
connect(this, SIGNAL(peerPhotoChanged(PeerData *)), this, SIGNAL(dialogsUpdated()));
connect(this, SIGNAL(peerPhotoChanged(PeerData*)), this, SIGNAL(dialogsUpdated()));
connect(&noUpdatesTimer, SIGNAL(timeout()), this, SLOT(getDifference()));
connect(&onlineTimer, SIGNAL(timeout()), this, SLOT(setOnline()));
connect(&onlineUpdater, SIGNAL(timeout()), this, SLOT(updateOnlineDisplay()));
connect(&_onlineTimer, SIGNAL(timeout()), this, SLOT(updateOnline()));
connect(&_onlineUpdater, SIGNAL(timeout()), this, SLOT(updateOnlineDisplay()));
connect(&_idleFinishTimer, SIGNAL(timeout()), this, SLOT(checkIdleFinish()));
connect(&_bySeqTimer, SIGNAL(timeout()), this, SLOT(getDifference()));
connect(&_failDifferenceTimer, SIGNAL(timeout()), this, SLOT(getDifferenceForce()));
connect(this, SIGNAL(peerUpdated(PeerData*)), &history, SLOT(peerUpdated(PeerData*)));
@ -1272,6 +1274,10 @@ bool MainWidget::serviceHistoryFail(const RPCError &error) {
return false;
}
bool MainWidget::isIdle() const {
return _isIdle;
}
void MainWidget::setInnerFocus() {
if (hider || !history.peer()) {
if (hider && hider->wasOffered()) {
@ -2082,7 +2088,7 @@ void MainWidget::gotState(const MTPupdates_State &state) {
updInited = true;
dialogs.loadDialogs();
setOnline();
updateOnline();
}
void MainWidget::gotDifference(const MTPupdates_Difference &diff) {
@ -2173,6 +2179,7 @@ void MainWidget::getDifference() {
void MainWidget::start(const MTPUser &user) {
MTP::authed(user.c_userSelf().vid.v);
cSetOtherOnline(0);
App::initMedia();
App::feedUsers(MTP_vector<MTPUser>(1, user));
App::app()->startUpdateCheck();
@ -2398,7 +2405,7 @@ void MainWidget::destroyData() {
}
void MainWidget::updateOnlineDisplayIn(int32 msecs) {
onlineUpdater.start(msecs);
_onlineUpdater.start(msecs);
}
void MainWidget::addNewContact(int32 uid, bool show) {
@ -2408,13 +2415,21 @@ void MainWidget::addNewContact(int32 uid, bool show) {
}
bool MainWidget::isActive() const {
return isVisible() && !animating();
return !_isIdle && isVisible() && !animating();
}
bool MainWidget::historyIsActive() const {
return isActive() && !profile && !overview && history.isActive();
}
bool MainWidget::lastWasOnline() const {
return _lastWasOnline;
}
uint64 MainWidget::lastSetOnline() const {
return _lastSetOnline;
}
int32 MainWidget::dlgsWidth() const {
return dialogs.width();
}
@ -2428,28 +2443,52 @@ MainWidget::~MainWidget() {
if (App::wnd()) App::wnd()->noMain(this);
}
void MainWidget::setOnline(int windowState) {
if (onlineRequest) {
MTP::cancel(onlineRequest);
onlineRequest = 0;
void MainWidget::updateOnline(bool gotOtherOffline) {
bool isOnline = App::wnd()->isActive();
int updateIn = cOnlineUpdatePeriod();
if (isOnline) {
uint64 idle = psIdleTime();
if (idle >= cOfflineIdleTimeout()) {
isOnline = false;
if (!_isIdle) {
_isIdle = true;
_idleFinishTimer.start(900);
}
} else {
updateIn = qMin(updateIn, int(cOfflineIdleTimeout() - idle));
}
}
onlineTimer.stop();
bool isOnline = App::wnd()->psIsOnline(windowState);
if (isOnline || windowState >= 0) {
onlineRequest = MTP::send(MTPaccount_UpdateStatus(MTP_bool(!isOnline)));
LOG(("App Info: Updating Online!"));
uint64 ms = getms(true);
if (isOnline != _lastWasOnline || (isOnline && _lastSetOnline + cOnlineUpdatePeriod() <= ms) || (isOnline && gotOtherOffline)) {
if (_onlineRequest) {
MTP::cancel(_onlineRequest);
_onlineRequest = 0;
}
_lastWasOnline = isOnline;
_lastSetOnline = ms;
_onlineRequest = MTP::send(MTPaccount_UpdateStatus(MTP_bool(!isOnline)));
if (App::self()) App::self()->onlineTill = unixtime() + (isOnline ? (cOnlineUpdatePeriod() / 1000) : -1);
_lastSetOnline = getms(true);
updateOnlineDisplay();
} else if (isOnline) {
updateIn = _lastSetOnline + cOnlineUpdatePeriod() - ms;
}
if (App::self()) App::self()->onlineTill = unixtime() + (isOnline ? 60 : -1);
if (profile) {
profile->updateOnlineDisplayTimer();
} else {
history.updateOnlineDisplayTimer();
}
onlineTimer.start(55000);
_onlineTimer.start(updateIn);
}
void MainWidget::mainStateChanged(Qt::WindowState state) {
setOnline(state);
void MainWidget::checkIdleFinish() {
if (psIdleTime() < cOfflineIdleTimeout()) {
_idleFinishTimer.stop();
_isIdle = false;
updateOnline();
if (App::wnd()) App::wnd()->checkHistoryActivation();
} else {
_idleFinishTimer.start(900);
}
}
void MainWidget::updateReceived(const mtpPrime *from, const mtpPrime *end) {
@ -2669,24 +2708,30 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
case mtpc_updateUserStatus: {
const MTPDupdateUserStatus &d(update.c_updateUserStatus());
if (d.vuser_id.v == MTP::authedId() && (d.vstatus.type() == mtpc_userStatusOffline || d.vstatus.type() == mtpc_userStatusEmpty)) {
setOnline();
} else {
UserData *user = App::userLoaded(d.vuser_id.v);
if (user) {
switch (d.vstatus.type()) {
case mtpc_userStatusEmpty: user->onlineTill = 0; break;
case mtpc_userStatusRecently:
if (user->onlineTill > -10) { // don't modify pseudo-online
user->onlineTill = -2;
}
break;
case mtpc_userStatusLastWeek: user->onlineTill = -3; break;
case mtpc_userStatusLastMonth: user->onlineTill = -4; break;
case mtpc_userStatusOffline: user->onlineTill = d.vstatus.c_userStatusOffline().vwas_online.v; break;
case mtpc_userStatusOnline: user->onlineTill = d.vstatus.c_userStatusOnline().vexpires.v; break;
UserData *user = App::userLoaded(d.vuser_id.v);
if (user) {
switch (d.vstatus.type()) {
case mtpc_userStatusEmpty: user->onlineTill = 0; break;
case mtpc_userStatusRecently:
if (user->onlineTill > -10) { // don't modify pseudo-online
user->onlineTill = -2;
}
if (App::main()) App::main()->peerUpdated(user);
break;
case mtpc_userStatusLastWeek: user->onlineTill = -3; break;
case mtpc_userStatusLastMonth: user->onlineTill = -4; break;
case mtpc_userStatusOffline: user->onlineTill = d.vstatus.c_userStatusOffline().vwas_online.v; break;
case mtpc_userStatusOnline: user->onlineTill = d.vstatus.c_userStatusOnline().vexpires.v; break;
}
if (App::main()) App::main()->peerUpdated(user);
}
if (d.vuser_id.v == MTP::authedId()) {
if (d.vstatus.type() == mtpc_userStatusOffline || d.vstatus.type() == mtpc_userStatusEmpty) {
updateOnline(true);
if (d.vstatus.type() == mtpc_userStatusOffline) {
cSetOtherOnline(d.vstatus.c_userStatusOffline().vwas_online.v);
}
} else if (d.vstatus.type() == mtpc_userStatusOnline) {
cSetOtherOnline(d.vstatus.c_userStatusOnline().vexpires.v);
}
}
} break;

View File

@ -242,6 +242,8 @@ public:
bool isActive() const;
bool historyIsActive() const;
bool lastWasOnline() const;
uint64 lastSetOnline() const;
int32 dlgsWidth() const;
@ -312,6 +314,8 @@ public:
void serviceHistoryDone(const MTPmessages_Messages &msgs);
bool serviceHistoryFail(const RPCError &error);
bool isIdle() const;
~MainWidget();
signals:
@ -344,8 +348,8 @@ public slots:
void getDifference();
void getDifferenceForce();
void setOnline(int windowState = -1);
void mainStateChanged(Qt::WindowState state);
void updateOnline(bool gotOtherOffline = false);
void checkIdleFinish();
void updateOnlineDisplay();
void showPeer(quint64 peer, qint32 msgId = 0, bool back = false, bool force = false); // PeerId, MsgId
@ -423,9 +427,11 @@ private:
bool updInited;
SingleTimer noUpdatesTimer;
mtpRequestId onlineRequest;
SingleTimer onlineTimer;
SingleTimer onlineUpdater;
mtpRequestId _onlineRequest;
SingleTimer _onlineTimer, _onlineUpdater, _idleFinishTimer;
bool _lastWasOnline;
uint64 _lastSetOnline;
bool _isIdle;
QSet<PeerData*> updateNotifySettingPeers;
SingleTimer updateNotifySettingTimer;

View File

@ -445,9 +445,6 @@ namespace {
PsMainWindow::PsMainWindow(QWidget *parent) : QMainWindow(parent),
posInited(false), trayIcon(0), trayIconMenu(0), icon256(qsl(":/gui/art/icon256.png")), iconbig256(icon256), wndIcon(QPixmap::fromImage(icon256, Qt::ColorOnly)), _psCheckStatusIconLeft(100), _psLastIndicatorUpdate(0) {
connect(&psIdleTimer, SIGNAL(timeout()), this, SLOT(psIdleTimeout()));
psIdleTimer.setSingleShot(false);
connect(&_psCheckStatusIconTimer, SIGNAL(timeout()), this, SLOT(psStatusIconCheck()));
_psCheckStatusIconTimer.setSingleShot(false);
@ -455,15 +452,6 @@ posInited(false), trayIcon(0), trayIconMenu(0), icon256(qsl(":/gui/art/icon256.p
_psUpdateIndicatorTimer.setSingleShot(true);
}
void PsMainWindow::psNotIdle() const {
psIdleTimer.stop();
if (psIdle) {
psIdle = false;
if (App::main()) App::main()->setOnline();
if (App::wnd()) App::wnd()->checkHistoryActivation();
}
}
bool PsMainWindow::psHasTrayIcon() const {
return trayIcon || ((useAppIndicator || (useStatusIcon && trayIconChecked)) && (cWorkMode() != dbiwmWindowOnly));
}
@ -476,50 +464,9 @@ void PsMainWindow::psStatusIconCheck() {
}
}
void PsMainWindow::psIdleTimeout() {
int64 idleTime = 0;//objc_idleTime();
if (idleTime >= 0) {
if (idleTime <= IdleMsecs) {
psNotIdle();
}
} else { // error
psNotIdle();
}
}
void PsMainWindow::psShowTrayMenu() {
}
bool PsMainWindow::psIsOnline(int state) const {
if (state < 0) state = this->windowState();
if (state & Qt::WindowMinimized) {
return false;
} else if (!isVisible()) {
return false;
}
int64 idleTime = 0;//objc_idleTime();
LOG(("App Info: idle time %1").arg(idleTime));
if (idleTime >= 0) {
if (idleTime > IdleMsecs) {
if (!psIdle) {
psIdle = true;
psIdleTimer.start(900);
}
return false;
} else {
psNotIdle();
}
} else { // error
psNotIdle();
}
return true;
}
bool PsMainWindow::psIsActive(int state) const {
if (state < 0) state = this->windowState();
return isActiveWindow() && isVisible() && !(state & Qt::WindowMinimized) && !psIdle;
}
void PsMainWindow::psRefreshTaskbarIcon() {
}
@ -657,8 +604,6 @@ void PsMainWindow::psInitFrameless() {
if (frameless) {
//setWindowFlags(Qt::FramelessWindowHint);
}
connect(windowHandle(), SIGNAL(windowStateChanged(Qt::WindowState)), this, SLOT(psStateChanged(Qt::WindowState)));
}
void PsMainWindow::psSavePosition(Qt::WindowState state) {
@ -708,12 +653,6 @@ void PsMainWindow::psUpdatedPosition() {
psUpdatedPositionTimer.start(SaveWindowPositionTimeout);
}
void PsMainWindow::psStateChanged(Qt::WindowState state) {
psUpdateSysMenu(state);
psUpdateMargins();
psSavePosition(state);
}
void PsMainWindow::psCreateTrayIcon() {
if (useAppIndicator) {
DEBUG_LOG(("Trying to create AppIndicator"));
@ -1361,6 +1300,17 @@ PsUpdateDownloader::~PsUpdateDownloader() {
reply = 0;
}
namespace {
uint64 _lastUserAction = 0;
}
void psUserActionDone() {
_lastUserAction = getms(true);
}
uint64 psIdleTime() {
return getms(true) - _lastUserAction;
}
QStringList psInitLogs() {
return _initLogs;

View File

@ -53,9 +53,6 @@ public:
void psFlash();
void psNotifySettingGot();
bool psIsActive(int state = -1) const;
bool psIsOnline(int state) const;
void psUpdateWorkmode();
void psRefreshTaskbarIcon();
@ -77,10 +74,8 @@ public:
public slots:
void psStateChanged(Qt::WindowState state);
void psUpdateDelegate();
void psSavePosition(Qt::WindowState state = Qt::WindowActive);
void psIdleTimeout();
void psShowTrayMenu();
void psStatusIconCheck();
@ -88,7 +83,6 @@ public slots:
protected:
void psNotIdle() const;
bool psHasTrayIcon() const;
bool posInited;
@ -105,9 +99,6 @@ protected:
private:
void psCreateTrayIcon();
mutable bool psIdle;
mutable QTimer psIdleTimer;
QTimer _psCheckStatusIconTimer;
int _psCheckStatusIconLeft;
@ -175,6 +166,9 @@ private:
};
void psUserActionDone();
uint64 psIdleTime();
QStringList psInitLogs();
void psClearInitLogs();

View File

@ -78,67 +78,15 @@ psLogout(0), psUndo(0), psRedo(0), psCut(0), psCopy(0), psPaste(0), psDelete(0),
QImage tray(qsl(":/gui/art/osxtray.png"));
trayImg = tray.copy(0, cRetina() ? 0 : tray.width() / 2, tray.width() / (cRetina() ? 2 : 4), tray.width() / (cRetina() ? 2 : 4));
trayImgSel = tray.copy(tray.width() / (cRetina() ? 2 : 4), cRetina() ? 0 : tray.width() / 2, tray.width() / (cRetina() ? 2 : 4), tray.width() / (cRetina() ? 2 : 4));
connect(&psIdleTimer, SIGNAL(timeout()), this, SLOT(psIdleTimeout()));
psIdleTimer.setSingleShot(false);
}
void PsMainWindow::psNotIdle() const {
psIdleTimer.stop();
if (psIdle) {
psIdle = false;
if (App::main()) App::main()->setOnline();
if (App::wnd()) App::wnd()->checkHistoryActivation();
}
}
QImage PsMainWindow::psTrayIcon(bool selected) const {
return selected ? trayImgSel : trayImg;
}
void PsMainWindow::psIdleTimeout() {
int64 idleTime = objc_idleTime();
if (idleTime >= 0) {
if (idleTime <= IdleMsecs) {
psNotIdle();
}
} else { // error
psNotIdle();
}
}
void PsMainWindow::psShowTrayMenu() {
}
bool PsMainWindow::psIsOnline(int state) const {
if (state < 0) state = this->windowState();
if (state & Qt::WindowMinimized) {
return false;
} else if (!isVisible()) {
return false;
}
int64 idleTime = objc_idleTime();
LOG(("App Info: idle time %1").arg(idleTime));
if (idleTime >= 0) {
if (idleTime > IdleMsecs) {
if (!psIdle) {
psIdle = true;
psIdleTimer.start(900);
}
return false;
} else {
psNotIdle();
}
} else { // error
psNotIdle();
}
return true;
}
bool PsMainWindow::psIsActive(int state) const {
if (state < 0) state = this->windowState();
return isActiveWindow() && isVisible() && !(state & Qt::WindowMinimized) && !psIdle;
}
void PsMainWindow::psRefreshTaskbarIcon() {
}
@ -280,8 +228,6 @@ void PsMainWindow::psInitFrameless() {
if (frameless) {
//setWindowFlags(Qt::FramelessWindowHint);
}
connect(windowHandle(), SIGNAL(windowStateChanged(Qt::WindowState)), this, SLOT(psStateChanged(Qt::WindowState)));
}
void PsMainWindow::psSavePosition(Qt::WindowState state) {
@ -331,15 +277,6 @@ void PsMainWindow::psUpdatedPosition() {
psUpdatedPositionTimer.start(SaveWindowPositionTimeout);
}
void PsMainWindow::psStateChanged(Qt::WindowState state) {
psUpdateSysMenu(state);
psUpdateMargins();
// if (state == Qt::WindowMinimized && GetWindowLong(ps_hWnd, GWL_HWNDPARENT)) {
// App::wnd()->minimizeToTray();
// }
psSavePosition(state);
}
void PsMainWindow::psFirstShow() {
finished = false;
@ -492,7 +429,7 @@ void PsMainWindow::psMacUpdateMenu() {
_forceDisabled(psContacts, !isLogged);
_forceDisabled(psAddContact, !isLogged);
_forceDisabled(psNewGroup, !isLogged);
_forceDisabled(psShowTelegram, psIsActive());
_forceDisabled(psShowTelegram, App::wnd()->isActive(false));
}
void PsMainWindow::psFlash() {
@ -980,6 +917,18 @@ PsUpdateDownloader::~PsUpdateDownloader() {
reply = 0;
}
namespace {
uint64 _lastUserAction = 0;
}
void psUserActionDone() {
_lastUserAction = getms(true);
}
uint64 psIdleTime() {
int64 idleTime = 0;
return objc_idleTime(idleTime) ? idleTime : (getms(true) - _lastUserAction);
}
QStringList psInitLogs() {
return _initLogs;

View File

@ -64,9 +64,6 @@ public:
void psFlash();
bool psIsActive(int state = -1) const;
bool psIsOnline(int state) const;
void psUpdateWorkmode();
void psRefreshTaskbarIcon();
@ -90,7 +87,6 @@ public:
public slots:
void psStateChanged(Qt::WindowState state);
void psUpdateDelegate();
void psSavePosition(Qt::WindowState state = Qt::WindowActive);
void psIdleTimeout();
@ -199,6 +195,9 @@ private:
};
void psUserActionDone();
uint64 psIdleTime();
QStringList psInitLogs();
void psClearInitLogs();

View File

@ -57,7 +57,7 @@ void objc_activateWnd(WId winId);
void objc_debugShowAlert(const QString &str);
void objc_outputDebugString(const QString &str);
int64 objc_idleTime();
bool objc_idleTime(int64 &idleTime);
bool objc_showOpenWithMenu(int x, int y, const QString &file);

View File

@ -319,7 +319,7 @@ PsMacWindowPrivate::~PsMacWindowPrivate() {
delete data;
}
int64 objc_idleTime() { // taken from https://github.com/trueinteractions/tint/issues/53
bool objc_idleTime(int64 &idleTime) { // taken from https://github.com/trueinteractions/tint/issues/53
CFMutableDictionaryRef properties = 0;
CFTypeRef obj;
mach_port_t masterPort;
@ -331,7 +331,7 @@ int64 objc_idleTime() { // taken from https://github.com/trueinteractions/tint/i
/* Get IOHIDSystem */
IOServiceGetMatchingServices(masterPort, IOServiceMatching("IOHIDSystem"), &iter);
if (iter == 0) {
return -1;
return false;
} else {
curObj = IOIteratorNext(iter);
}
@ -339,7 +339,7 @@ int64 objc_idleTime() { // taken from https://github.com/trueinteractions/tint/i
obj = CFDictionaryGetValue(properties, CFSTR("HIDIdleTime"));
CFRetain(obj);
} else {
return -1;
return false;
}
uint64 err = ~0L, result = err;
@ -366,7 +366,10 @@ int64 objc_idleTime() { // taken from https://github.com/trueinteractions/tint/i
CFRelease((CFTypeRef)properties);
IOObjectRelease(curObj);
IOObjectRelease(iter);
return (result == err) ? -1 : int64(result);
if (result == err) return false;
idleTime = int64(result);
return true;
}
@interface OpenWithApp : NSObject {

View File

@ -885,71 +885,14 @@ namespace {
};
PsMainWindow::PsMainWindow(QWidget *parent) : QMainWindow(parent), ps_hWnd(0), ps_menu(0), icon256(qsl(":/gui/art/icon256.png")), iconbig256(qsl(":/gui/art/iconbig256.png")), wndIcon(QPixmap::fromImage(icon256, Qt::ColorOnly)),
ps_iconBig(0), ps_iconSmall(0), ps_iconOverlay(0), trayIcon(0), trayIconMenu(0), posInited(false), ps_tbHider_hWnd(createTaskbarHider()), psIdle(false) {
ps_iconBig(0), ps_iconSmall(0), ps_iconOverlay(0), trayIcon(0), trayIconMenu(0), posInited(false), ps_tbHider_hWnd(createTaskbarHider()) {
tbCreatedMsgId = RegisterWindowMessage(L"TaskbarButtonCreated");
connect(&psIdleTimer, SIGNAL(timeout()), this, SLOT(psIdleTimeout()));
psIdleTimer.setSingleShot(false);
}
void PsMainWindow::psNotIdle() const {
psIdleTimer.stop();
if (psIdle) {
psIdle = false;
if (App::main()) App::main()->setOnline();
if (App::wnd()) App::wnd()->checkHistoryActivation();
}
}
void PsMainWindow::psIdleTimeout() {
LASTINPUTINFO lii;
lii.cbSize = sizeof(LASTINPUTINFO);
BOOL res = GetLastInputInfo(&lii);
if (res) {
uint64 ticks = GetTickCount();
if (lii.dwTime >= ticks - IdleMsecs) {
psNotIdle();
}
} else { // error {
psNotIdle();
}
}
void PsMainWindow::psShowTrayMenu() {
trayIconMenu->popup(QCursor::pos());
}
bool PsMainWindow::psIsActive(int state) const {
if (state < 0) state = this->windowState();
return isActiveWindow() && isVisible() && !(state & Qt::WindowMinimized) && !psIdle;
}
bool PsMainWindow::psIsOnline(int windowState) const {
if (windowState < 0) windowState = this->windowState();
if (windowState & Qt::WindowMinimized) {
return false;
} else if (!isVisible()) {
return false;
}
LASTINPUTINFO lii;
lii.cbSize = sizeof(LASTINPUTINFO);
BOOL res = GetLastInputInfo(&lii);
if (res) {
uint64 ticks = GetTickCount();
if (lii.dwTime < ticks - IdleMsecs) {
if (!psIdle) {
psIdle = true;
psIdleTimer.start(900);
}
return false;
} else {
psNotIdle();
}
} else { // error
psNotIdle();
}
return true;
}
void PsMainWindow::psRefreshTaskbarIcon() {
QWidget *w = new QWidget(this);
w->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
@ -1136,7 +1079,6 @@ void PsMainWindow::psInitFrameless() {
// RegisterApplicationRestart(NULL, 0);
psInitSysMenu();
connect(windowHandle(), SIGNAL(windowStateChanged(Qt::WindowState)), this, SLOT(psStateChanged(Qt::WindowState)));
}
void PsMainWindow::psSavePosition(Qt::WindowState state) {
@ -1181,15 +1123,6 @@ void PsMainWindow::psUpdatedPosition() {
psUpdatedPositionTimer.start(SaveWindowPositionTimeout);
}
void PsMainWindow::psStateChanged(Qt::WindowState state) {
psUpdateSysMenu(state);
psUpdateMargins();
if (state == Qt::WindowMinimized && GetWindowLong(ps_hWnd, GWL_HWNDPARENT)) {
App::wnd()->minimizeToTray();
}
psSavePosition(state);
}
Q_DECLARE_METATYPE(QMargins);
void PsMainWindow::psFirstShow() {
_psShadowWindows.init(_shActive);
@ -1803,6 +1736,20 @@ namespace {
}
}
namespace {
uint64 _lastUserAction = 0;
}
void psUserActionDone() {
_lastUserAction = getms(true);
}
uint64 psIdleTime() {
LASTINPUTINFO lii;
lii.cbSize = sizeof(LASTINPUTINFO);
return GetLastInputInfo(&lii) ? (GetTickCount() - lii.dwTime) : (getms(true) - _lastUserAction);
}
QStringList psInitLogs() {
return _initLogs;
}

View File

@ -52,9 +52,6 @@ public:
void psFlash();
void psNotifySettingGot();
bool psIsActive(int state = -1) const;
bool psIsOnline(int windowState) const;
void psUpdateWorkmode();
void psRefreshTaskbarIcon();
@ -76,15 +73,12 @@ public:
public slots:
void psStateChanged(Qt::WindowState state);
void psUpdateDelegate();
void psSavePosition(Qt::WindowState state = Qt::WindowActive);
void psIdleTimeout();
void psShowTrayMenu();
protected:
void psNotIdle() const;
bool psHasTrayIcon() const {
return trayIcon;
}
@ -106,9 +100,6 @@ private:
HMENU ps_menu;
HICON ps_iconBig, ps_iconSmall, ps_iconOverlay;
mutable bool psIdle;
mutable QTimer psIdleTimer;
void psDestroyIcons();
};
@ -176,6 +167,9 @@ private:
};
void psUserActionDone();
uint64 psIdleTime();
QStringList psInitLogs();
void psClearInitLogs();

View File

@ -117,6 +117,16 @@ bool gContactsReceived = false;
bool gWideMode = true;
int gOnlineUpdatePeriod = 120000;
int gOfflineBlurTimeout = 5000;
int gOfflineIdleTimeout = 30000;
int gOnlineFocusTimeout = 1000;
int gOnlineCloudTimeout = 300000;
int gNotifyCloudDelay = 30000;
int gNotifyDefaultDelay = 1500;
int gOtherOnline = 0;
void settingsParseArgs(int argc, char *argv[]) {
if (cPlatform() == dbipMac) {
gCustomNotifies = false;

View File

@ -172,4 +172,14 @@ DeclareSetting(bool, ContactsReceived);
DeclareSetting(bool, WideMode);
DeclareSetting(int, OnlineUpdatePeriod);
DeclareSetting(int, OfflineBlurTimeout);
DeclareSetting(int, OfflineIdleTimeout);
DeclareSetting(int, OnlineFocusTimeout);
DeclareSetting(int, OnlineCloudTimeout);
DeclareSetting(int, NotifyCloudDelay);
DeclareSetting(int, NotifyDefaultDelay);
DeclareSetting(int, OtherOnline);
void settingsParseArgs(int argc, char *argv[]);

View File

@ -330,7 +330,7 @@ NotifyWindow::~NotifyWindow() {
}
Window::Window(QWidget *parent) : PsMainWindow(parent), _serviceHistoryRequest(0),
intro(0), main(0), settings(0), layerBG(0), _topWidget(0),
intro(0), main(0), settings(0), layerBG(0), _isActive(false), _topWidget(0),
_connecting(0), _clearManager(0), dragging(false), _inactivePress(false), _mediaView(0) {
icon16 = icon256.scaledToWidth(16, Qt::SmoothTransformation);
@ -356,6 +356,9 @@ _connecting(0), _clearManager(0), dragging(false), _inactivePress(false), _media
connect(&_inactiveTimer, SIGNAL(timeout()), this, SLOT(onInactiveTimer()));
connect(&notifyWaitTimer, SIGNAL(timeout()), this, SLOT(notifyFire()));
_isActiveTimer.setSingleShot(true);
connect(&_isActiveTimer, SIGNAL(timeout()), this, SLOT(updateIsActive()));
}
void Window::inactivePress(bool inactive) {
@ -375,12 +378,26 @@ void Window::onInactiveTimer() {
inactivePress(false);
}
void Window::stateChanged(Qt::WindowState state) {
psUserActionDone();
updateIsActive((state == Qt::WindowMinimized) ? cOfflineBlurTimeout() : cOnlineFocusTimeout());
psUpdateSysMenu(state);
psUpdateMargins();
if (state == Qt::WindowMinimized && cWorkMode() == dbiwmTrayOnly) {
App::wnd()->minimizeToTray();
}
psSavePosition(state);
}
void Window::init() {
psInitFrameless();
setWindowIcon(wndIcon);
App::app()->installEventFilter(this);
connect(windowHandle(), SIGNAL(activeChanged()), this, SLOT(checkHistoryActivation()));
connect(windowHandle(), SIGNAL(windowStateChanged(Qt::WindowState)), this, SLOT(stateChanged(Qt::WindowState)));
connect(windowHandle(), SIGNAL(activeChanged()), this, SLOT(checkHistoryActivation()));
QPalette p(palette());
p.setColor(QPalette::Window, st::wndBG->c);
@ -706,12 +723,12 @@ bool Window::layerShown() {
return !!layerBG || !!_topWidget;
}
bool Window::historyIsActive(int state) const {
return psIsActive(state) && main && main->historyIsActive() && (!settings || !settings->isVisible());
bool Window::historyIsActive() const {
return isActive(false) && main && main->historyIsActive() && (!settings || !settings->isVisible());
}
void Window::checkHistoryActivation(int state) {
if (main && MTP::authedId() && historyIsActive(state)) {
void Window::checkHistoryActivation() {
if (main && MTP::authedId() && historyIsActive()) {
main->historyWasRead();
}
QTimer::singleShot(1, this, SLOT(updateTrayMenu()));
@ -790,26 +807,37 @@ QRect Window::iconRect() const {
}
bool Window::eventFilter(QObject *obj, QEvent *evt) {
if (obj == App::app() && (evt->type() == QEvent::ApplicationActivate)) {
QTimer::singleShot(1, this, SLOT(checkHistoryActivation()));
} else if (obj == App::app() && (evt->type() == QEvent::FileOpen)) {
QString url = static_cast<QFileOpenEvent*>(evt)->url().toEncoded();
if (!url.trimmed().midRef(0, 5).compare(qsl("tg://"), Qt::CaseInsensitive)) {
cSetStartUrl(url);
if (!cStartUrl().isEmpty() && App::main() && App::self()) {
App::main()->openLocalUrl(cStartUrl());
cSetStartUrl(QString());
QEvent::Type t = evt->type();
if (t == QEvent::MouseButtonPress || t == QEvent::KeyPress || t == QEvent::TouchBegin) {
psUserActionDone();
} else if (t == QEvent::MouseMove) {
if (main && main->isIdle()) {
psUserActionDone();
main->checkIdleFinish();
}
}
if (obj == App::app()) {
if (t == QEvent::ApplicationActivate) {
psUserActionDone();
QTimer::singleShot(1, this, SLOT(checkHistoryActivation()));
} else if (t == QEvent::FileOpen) {
QString url = static_cast<QFileOpenEvent*>(evt)->url().toEncoded();
if (!url.trimmed().midRef(0, 5).compare(qsl("tg://"), Qt::CaseInsensitive)) {
cSetStartUrl(url);
if (!cStartUrl().isEmpty() && App::main() && App::self()) {
App::main()->openLocalUrl(cStartUrl());
cSetStartUrl(QString());
}
}
activate();
}
activate();
} else if (obj == this && evt->type() == QEvent::WindowStateChange) {
Qt::WindowState state = (windowState() & Qt::WindowMinimized) ? Qt::WindowMinimized : ((windowState() & Qt::WindowMaximized) ? Qt::WindowMaximized : ((windowState() & Qt::WindowFullScreen) ? Qt::WindowFullScreen : Qt::WindowNoState));
psStateChanged(state);
if (App::main()) {
App::main()->mainStateChanged(state);
} else if (obj == this) {
if (t == QEvent::WindowStateChange) {
Qt::WindowState state = (windowState() & Qt::WindowMinimized) ? Qt::WindowMinimized : ((windowState() & Qt::WindowMaximized) ? Qt::WindowMaximized : ((windowState() & Qt::WindowFullScreen) ? Qt::WindowFullScreen : Qt::WindowNoState));
stateChanged(state);
} else if (t == QEvent::Move || t == QEvent::Resize) {
psUpdatedPosition();
}
} else if (obj == this && (evt->type() == QEvent::Move || evt->type() == QEvent::Resize)) {
psUpdatedPosition();
}
return PsMainWindow::eventFilter(obj, evt);
}
@ -843,7 +871,7 @@ bool Window::minimizeToTray() {
cSetSeenTrayTooltip(true);
App::writeConfig();
}
if (App::main()) App::main()->setOnline(windowState());
updateIsActive(cOfflineBlurTimeout());
updateTrayMenu();
updateGlobalMenu();
return true;
@ -852,7 +880,7 @@ bool Window::minimizeToTray() {
void Window::updateTrayMenu(bool force) {
if (!trayIconMenu || (cPlatform() == dbipWindows && !force)) return;
bool active = psIsActive();
bool active = isActive(false);
if (cPlatform() == dbipWindows || cPlatform() == dbipMac) {
QAction *first = trayIconMenu->actions().at(0);
first->setText(lang(active ? lng_minimize_to_tray : lng_open_from_tray));
@ -911,6 +939,7 @@ void Window::activate() {
setVisible(true);
psActivateProcess();
activateWindow();
updateIsActive(cOnlineFocusTimeout());
if (wasHidden) {
if (main) {
main->windowShown();
@ -972,17 +1001,16 @@ void Window::showFromTray(QSystemTrayIcon::ActivationReason reason) {
QTimer::singleShot(1, this, SLOT(updateGlobalMenu()));
activate();
updateCounter();
if (App::main()) App::main()->setOnline(windowState());
}
}
void Window::toggleTray(QSystemTrayIcon::ActivationReason reason) {
if (cPlatform() == dbipMac && psIsActive()) return;
if (cPlatform() == dbipMac && isActive(false)) return;
if (reason == QSystemTrayIcon::Context) {
updateTrayMenu(true);
QTimer::singleShot(1, this, SLOT(psShowTrayMenu()));
} else {
if (psIsActive()) {
if (isActive(false)) {
minimizeToTray();
} else {
showFromTray(reason);
@ -1081,7 +1109,7 @@ void Window::quit() {
}
void Window::notifySchedule(History *history, MsgId msgId) {
if (App::quiting() || !history->currentNotification()) return;
if (App::quiting() || !history->currentNotification() || !main) return;
bool haveSetting = (history->peer->notify != UnknownNotifySettings);
if (haveSetting) {
@ -1093,24 +1121,35 @@ void Window::notifySchedule(History *history, MsgId msgId) {
App::wnd()->getNotifySetting(MTP_inputNotifyPeer(history->peer->input));
}
uint64 ms = getms(true) + NotifyWaitTimeout;
notifyWhenAlerts[history].insert(ms, NullType());
int delay = 100, t = unixtime();
uint64 ms = getms(true);
bool isOnline = main->lastWasOnline(), otherNotOld = ((cOtherOnline() * uint64(1000)) + cOnlineCloudTimeout() > t * uint64(1000));
bool otherLaterThanMe = (cOtherOnline() * uint64(1000) + (ms - main->lastSetOnline()) > t * uint64(1000));
if (!isOnline && otherNotOld && otherLaterThanMe) {
delay = cNotifyCloudDelay();
} else if (cOtherOnline() >= t) {
delay = cNotifyDefaultDelay();
}
uint64 when = getms(true) + delay;
notifyWhenAlerts[history].insert(when, NullType());
if (cDesktopNotify()) {
NotifyWhenMaps::iterator i = notifyWhenMaps.find(history);
if (i == notifyWhenMaps.end()) {
i = notifyWhenMaps.insert(history, NotifyWhenMap());
}
if (i.value().constFind(msgId) == i.value().cend()) {
i.value().insert(msgId, ms);
i.value().insert(msgId, when);
}
NotifyWaiters *addTo = haveSetting ? &notifyWaiters : &notifySettingWaiters;
if (addTo->constFind(history) == addTo->cend()) {
addTo->insert(history, NotifyWaiter(msgId, ms));
NotifyWaiters::const_iterator it = addTo->constFind(history);
if (it == addTo->cend() || it->when > when) {
addTo->insert(history, NotifyWaiter(msgId, when));
}
}
if (haveSetting) {
if (!notifyWaitTimer.isActive()) {
notifyWaitTimer.start(NotifyWaitTimeout);
if (!notifyWaitTimer.isActive() || notifyWaitTimer.remainingTime() > delay) {
notifyWaitTimer.start(delay);
}
}
}
@ -1279,7 +1318,6 @@ void Window::notifyShowNext(NotifyWindow *remove) {
psPlatformNotify(notifyItem);
}
uint64 ms = getms(true);
History *history = notifyItem->history();
history->skipNotification();
@ -1508,6 +1546,17 @@ void Window::changingMsgId(HistoryItem *row, MsgId newId) {
_mediaView->changingMsgId(row, newId);
}
bool Window::isActive(bool cached) const {
if (cached) return _isActive;
return isActiveWindow() && isVisible() && !(windowState() & Qt::WindowMinimized);
}
void Window::updateIsActive(int timeout) {
if (timeout) return _isActiveTimer.start(timeout);
_isActive = isActive(false);
if (main) main->updateOnline();
}
Window::~Window() {
notifyClearFast();
delete _clearManager;

View File

@ -180,7 +180,7 @@ public:
bool layerShown();
bool historyIsActive(int state = -1) const;
bool historyIsActive() const;
void activate();
@ -225,9 +225,14 @@ public:
void mediaOverviewUpdated(PeerData *peer);
void changingMsgId(HistoryItem *row, MsgId newId);
bool isActive(bool cached = true) const;
public slots:
void updateIsActive(int timeout = 0);
void stateChanged(Qt::WindowState state);
void checkHistoryActivation(int state = -1);
void checkHistoryActivation();
void updateCounter();
void showSettings();
@ -279,6 +284,9 @@ private:
SettingsWidget *settings;
BackgroundWidget *layerBG;
QTimer _isActiveTimer;
bool _isActive;
QWidget *_topWidget; // temp hack for CountrySelect
ConnectingWidget *_connecting;