Merge branch 'dev' into player

Conflicts:
	Telegram/SourceFiles/application.cpp
	Telegram/SourceFiles/core/utils.h
	Telegram/SourceFiles/localstorage.cpp
	Telegram/SourceFiles/pspecific_mac_p.mm
This commit is contained in:
John Preston 2016-10-08 12:10:33 +03:00
commit e616c39608
164 changed files with 6265 additions and 3911 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 89 KiB

View file

@ -68,7 +68,7 @@ semiboldButtonBlueText: #2b99d5;
wndMinHeight: 480px; wndMinHeight: 480px;
wndDefWidth: 800px; wndDefWidth: 800px;
wndDefHeight: 600px; wndDefHeight: 600px;
wndShadow: sprite(209px, 46px, 19px, 19px); wndShadow: icon {{ "window_shadow", windowShadowFg }};
wndShadowShift: 1px; wndShadowShift: 1px;
layerAlpha: 0.5; layerAlpha: 0.5;
@ -298,10 +298,11 @@ solidScroll: flatScroll {
duration: 150; duration: 150;
hiding: 0; hiding: 0;
} }
defaultDropdownShadow: icon {{ "dropdown_shadow", windowShadowFg }};
defaultPopupMenu: PopupMenu { defaultPopupMenu: PopupMenu {
skip: 5px; skip: 5px;
shadow: sprite(241px, 46px, 6px, 6px); shadow: defaultDropdownShadow;
shadowShift: 1px; shadowShift: 1px;
itemBg: white; itemBg: white;
@ -320,7 +321,7 @@ defaultPopupMenu: PopupMenu {
separatorWidth: 1px; separatorWidth: 1px;
separatorFg: #f1f1f1; separatorFg: #f1f1f1;
arrow: sprite(0px, 126px, 4px, 7px); arrow: icon {{ "dropdown_submenu_arrow", #373737 }};
duration: 120; duration: 120;
@ -689,7 +690,7 @@ btnIntroNext: flatButton(btnDefNext, btnDefBig) {
radius: buttonRadius; radius: buttonRadius;
} }
boxShadow: sprite(363px, 50px, 15px, 15px); boxShadow: icon {{ "box_shadow", windowShadowFg }};
boxShadowShift: 2px; boxShadowShift: 2px;
introCountry: countryInput { introCountry: countryInput {
@ -1213,12 +1214,12 @@ btnBotKbHide: iconedButton(btnAttachEmoji) {
downIcon: sprite(373px, 95px, 23px, 14px); downIcon: sprite(373px, 95px, 23px, 14px);
downIconPos: point(5px, 17px); downIconPos: point(5px, 17px);
} }
broadcastToggle: flatCheckbox { silentToggle: flatCheckbox {
textColor: black; textColor: black;
bgColor: white; bgColor: white;
disColor: black; disColor: black;
width: 34px; width: 33px;
height: 46px; height: 46px;
duration: 200; duration: 200;
bgFunc: transition(easeOutCirc); bgFunc: transition(easeOutCirc);
@ -1226,24 +1227,14 @@ broadcastToggle: flatCheckbox {
font: normalFont; font: normalFont;
imageRect: sprite(18px, 125px, 22px, 21px);
chkImageRect: sprite(40px, 125px, 22px, 21px);
overImageRect: sprite(40px, 104px, 22px, 21px);
chkOverImageRect: sprite(40px, 125px, 22px, 21px);
disImageRect: sprite(18px, 125px, 22px, 21px);
chkDisImageRect: sprite(18px, 125px, 22px, 21px);
imagePos: point(6px, 12px);
}
silentToggle: flatCheckbox(broadcastToggle) {
width: 33px;
imageRect: sprite(354px, 242px, 21px, 21px); imageRect: sprite(354px, 242px, 21px, 21px);
chkImageRect: sprite(354px, 221px, 21px, 21px); chkImageRect: sprite(354px, 221px, 21px, 21px);
overImageRect: sprite(375px, 242px, 21px, 21px); overImageRect: sprite(375px, 242px, 21px, 21px);
chkOverImageRect: sprite(375px, 221px, 21px, 21px); chkOverImageRect: sprite(375px, 221px, 21px, 21px);
disImageRect: sprite(354px, 242px, 21px, 21px); disImageRect: sprite(354px, 242px, 21px, 21px);
chkDisImageRect: sprite(354px, 221px, 21px, 21px); chkDisImageRect: sprite(354px, 221px, 21px, 21px);
imagePos: point(6px, 12px);
} }
btnRecordAudio: sprite(379px, 390px, 16px, 24px); btnRecordAudio: sprite(379px, 390px, 16px, 24px);
btnRecordAudioActive: sprite(379px, 366px, 16px, 24px); btnRecordAudioActive: sprite(379px, 366px, 16px, 24px);
@ -1411,15 +1402,7 @@ btnCancelSearch: iconedButton(btnAddContact) {
downIcon: sprite(188px, 43px, 18px, 18px); downIcon: sprite(188px, 43px, 18px, 18px);
} }
notifyBG: white; simpleClose: iconedButton(btnDefIconed) {
notifyBorder: #f1f1f1;
notifyBorderWidth: 1px;
notifySlowHide: 4000;
notifyPhotoSize: 62px;
notifyMacPhotoSize: 64px;
notifyPhotoPos: point(9px, 9px);
notifyClosePos: point(1px, 2px);
notifyClose: iconedButton(btnDefIconed) {
icon: sprite(167px, 130px, 10px, 10px); icon: sprite(167px, 130px, 10px, 10px);
iconPos: point(10px, 10px); iconPos: point(10px, 10px);
downIcon: sprite(167px, 130px, 10px, 10px); downIcon: sprite(167px, 130px, 10px, 10px);
@ -1428,17 +1411,6 @@ notifyClose: iconedButton(btnDefIconed) {
width: 30px; width: 30px;
height: 30px; height: 30px;
} }
notifyItemTop: 12px;
notifyTextLeft: 12px;
notifyTextTop: 7px;
notifySlowHideFunc: transition(easeInCirc);
notifyWaitShortHide: 0;
notifyWaitLongHide: 20000;
notifyFastAnim: 150;
notifyWidth: 316px;
notifyHeight: 80px;
notifyDeltaX: 6px;
notifyDeltaY: 7px;
boxPhotoPadding: margins(28px, 28px, 28px, 18px); boxPhotoPadding: margins(28px, 28px, 28px, 18px);
boxPhotoCompressedPadding: margins(0px, 2px, 0px, 22px); boxPhotoCompressedPadding: margins(0px, 2px, 0px, 22px);
@ -1540,17 +1512,15 @@ dropdownDef: dropdown {
borderColor: #ebebeb; borderColor: #ebebeb;
padding: margins(10px, 10px, 10px, 10px); padding: margins(10px, 10px, 10px, 10px);
shadow: sprite(241px, 46px, 6px, 6px); shadow: defaultDropdownShadow;
shadowShift: 1px; shadowShift: 1px;
duration: 150; duration: 150;
width: 0px; width: 0px;
} }
defaultInnerDropdownShadow: icon {{ "dropdown_shadow", windowShadowFg }};
defaultInnerDropdown: InnerDropdown { defaultInnerDropdown: InnerDropdown {
padding: margins(10px, 10px, 10px, 10px); padding: margins(10px, 10px, 10px, 10px);
shadow: defaultInnerDropdownShadow; shadow: defaultDropdownShadow;
shadowShift: 1px; shadowShift: 1px;
duration: 150; duration: 150;
@ -1840,7 +1810,7 @@ mvControlSize: 90px;
mvIconSize: size(60px, 56px); mvIconSize: size(60px, 56px);
mvDropdown: dropdown(dropdownDef) { mvDropdown: dropdown(dropdownDef) {
shadow: sprite(0px, 0px, 0px, 0px); shadow: icon {};
padding: margins(11px, 12px, 11px, 12px); padding: margins(11px, 12px, 11px, 12px);
border: 0px; border: 0px;
@ -1865,7 +1835,7 @@ mvButton: iconedButton(btnDefIconed) {
duration: 0; duration: 0;
} }
mvPopupMenu: PopupMenu(defaultPopupMenu) { mvPopupMenu: PopupMenu(defaultPopupMenu) {
shadow: sprite(0px, 0px, 0px, 0px); shadow: icon {};
itemBg: #383838; itemBg: #383838;
itemBgOver: #505050; itemBgOver: #505050;
@ -2044,7 +2014,7 @@ sessionInfoFont: msgFont;
sessionInfoColor: #888888; sessionInfoColor: #888888;
sessionTerminateTop: 30px; sessionTerminateTop: 30px;
sessionTerminateSkip: 18px; sessionTerminateSkip: 18px;
sessionTerminate: iconedButton(notifyClose) { sessionTerminate: iconedButton(simpleClose) {
iconPos: point(3px, 3px); iconPos: point(3px, 3px);
downIconPos: point(3px, 4px); downIconPos: point(3px, 4px);
width: 16px; width: 16px;
@ -2058,6 +2028,8 @@ webPageDescriptionFont: normalFont;
webPagePhotoSize: 100px; webPagePhotoSize: 100px;
webPagePhotoDelta: 8px; webPagePhotoDelta: 8px;
mediaPlayerSuppressDuration: 150;
botDescSkip: 8px; botDescSkip: 8px;
suppressAll: 0.2; suppressAll: 0.2;

View file

@ -233,7 +233,7 @@ dropdown {
borderColor: color; borderColor: color;
padding: margins; padding: margins;
shadow: sprite; shadow: icon;
shadowShift: pixels; shadowShift: pixels;
duration: int; duration: int;
@ -255,7 +255,7 @@ InnerDropdown {
PopupMenu { PopupMenu {
skip: pixels; skip: pixels;
shadow: sprite; shadow: icon;
shadowShift: pixels; shadowShift: pixels;
itemBg: color; itemBg: color;
@ -273,7 +273,7 @@ PopupMenu {
separatorWidth: pixels; separatorWidth: pixels;
separatorFg: color; separatorFg: color;
arrow: sprite; arrow: icon;
duration: int; duration: int;

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 B

View file

@ -244,10 +244,17 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_settings_show_name" = "Show sender's name"; "lng_settings_show_name" = "Show sender's name";
"lng_settings_show_preview" = "Show message preview"; "lng_settings_show_preview" = "Show message preview";
"lng_settings_use_windows" = "Use Windows notifications"; "lng_settings_use_windows" = "Use Windows notifications";
"lng_settings_use_native_notifications" = "Use native notifications";
"lng_settings_advanced_notifications" = "Notifications position and count";
"lng_settings_notifications_position" = "Location on the screen";
"lng_settings_notifications_count" = "Notifications count";
"lng_settings_sound_notify" = "Play sound"; "lng_settings_sound_notify" = "Play sound";
"lng_settings_include_muted" = "Include muted chats in unread count"; "lng_settings_include_muted" = "Include muted chats in unread count";
"lng_notification_preview" = "You have a new message"; "lng_notification_preview" = "You have a new message";
"lng_notification_reply" = "Reply";
"lng_notification_hide_all" = "Hide all";
"lng_notification_sample" = "This is a sample notification";
"lng_settings_section_general" = "General"; "lng_settings_section_general" = "General";
"lng_settings_change_lang" = "Change language"; "lng_settings_change_lang" = "Change language";
@ -567,7 +574,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_action_changed_title" = "{from} changed group name to «{title}»"; "lng_action_changed_title" = "{from} changed group name to «{title}»";
"lng_action_changed_title_channel" = "Channel name was changed to «{title}»"; "lng_action_changed_title_channel" = "Channel name was changed to «{title}»";
"lng_action_created_chat" = "{from} created group «{title}»"; "lng_action_created_chat" = "{from} created group «{title}»";
"lng_action_created_channel" = "Channel «{title}» created"; "lng_action_created_channel" = "Channel created";
"lng_action_group_migrate" = "The group was upgraded to a supergroup"; "lng_action_group_migrate" = "The group was upgraded to a supergroup";
"lng_action_pinned_message" = "{from} pinned «{text}»"; "lng_action_pinned_message" = "{from} pinned «{text}»";
"lng_action_pinned_media" = "{from} pinned {media}"; "lng_action_pinned_media" = "{from} pinned {media}";
@ -584,6 +591,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_action_pinned_media_game" = "the game «{game}»"; "lng_action_pinned_media_game" = "the game «{game}»";
"lng_action_game_score" = "{from} scored {count:#|#|#} in {game}"; "lng_action_game_score" = "{from} scored {count:#|#|#} in {game}";
"lng_action_game_you_scored" = "You scored {count:#|#|#} in {game}"; "lng_action_game_you_scored" = "You scored {count:#|#|#} in {game}";
"lng_action_game_score_no_game" = "{from} scored {count:#|#|#}";
"lng_action_game_you_scored_no_game" = "You scored {count:#|#|#}";
"lng_profile_migrate_reached" = "{count:_not_used_|# member|# members} limit reached"; "lng_profile_migrate_reached" = "{count:_not_used_|# member|# members} limit reached";
"lng_profile_migrate_body" = "To get over this limit, you can upgrade your group to a supergroup."; "lng_profile_migrate_body" = "To get over this limit, you can upgrade your group to a supergroup.";

View file

@ -772,12 +772,12 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_allow_bot" = "허용"; "lng_allow_bot" = "허용";
"lng_bot_start" = "시작"; "lng_bot_start" = "시작";
"lng_bot_choose_group" = "Select a Group"; "lng_bot_choose_group" = "그룹방 선택";
"lng_bot_no_groups" = "그룹이 존재하지 않습니다."; "lng_bot_no_groups" = "그룹이 존재하지 않습니다.";
"lng_bot_groups_not_found" = "그룹을 찾을 수 없습니다."; "lng_bot_groups_not_found" = "그룹을 찾을 수 없습니다.";
"lng_bot_sure_invite" = "<<{group}>>에 봇을 추가 하시겠습니까?"; "lng_bot_sure_invite" = "<<{group}>>에 봇을 추가 하시겠습니까?";
"lng_bot_already_in_group" = "봇이 이미 그룹의 멤버입니다."; "lng_bot_already_in_group" = "봇이 이미 그룹의 멤버입니다.";
"lng_bot_choose_chat" = "Select a Chat"; "lng_bot_choose_chat" = "채팅방 선택";
"lng_bot_no_chats" = "채팅방이 없습니다."; "lng_bot_no_chats" = "채팅방이 없습니다.";
"lng_bot_chats_not_found" = "채팅방을 찾 을 수 없음"; "lng_bot_chats_not_found" = "채팅방을 찾 을 수 없음";
"lng_bot_sure_share_game" = "{user}에게 게임을 공유하겠습니까?"; "lng_bot_sure_share_game" = "{user}에게 게임을 공유하겠습니까?";
@ -787,10 +787,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_user_typing" = "{user}님이 입력중입니다."; "lng_user_typing" = "{user}님이 입력중입니다.";
"lng_users_typing" = "{user}님과 {second_user}님이 입력중입니다."; "lng_users_typing" = "{user}님과 {second_user}님이 입력중입니다.";
"lng_many_typing" = "{count:_not_used_|#명이|#명이} 입력중입니다"; "lng_many_typing" = "{count:_not_used_|#명이|#명이} 입력중입니다";
"lng_playing_game" = "playing a game"; "lng_playing_game" = "게임 중";
"lng_user_playing_game" = "{user} is playing a game"; "lng_user_playing_game" = "{user}님이 게임 중입니다.";
"lng_users_playing_game" = "{user} and {second_user} are playing a game"; "lng_users_playing_game" = "{user}님과 {second_user}님이 게임 중입니다.";
"lng_many_playing_game" = "{count:_not_used_|# is|# are} playing a game"; "lng_many_playing_game" = "{count:_not_used_|#명이|#명이} 게임 중입니다";
"lng_send_action_record_video" = "비디오 녹화 중"; "lng_send_action_record_video" = "비디오 녹화 중";
"lng_user_action_record_video" = "{user}님이 녹화중입니다"; "lng_user_action_record_video" = "{user}님이 녹화중입니다";
"lng_send_action_upload_video" = "비디오 전송 중"; "lng_send_action_upload_video" = "비디오 전송 중";

View file

@ -34,8 +34,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,10,8,5 FILEVERSION 0,10,13,0
PRODUCTVERSION 0,10,8,5 PRODUCTVERSION 0,10,13,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -51,10 +51,10 @@ BEGIN
BLOCK "040904b0" BLOCK "040904b0"
BEGIN BEGIN
VALUE "CompanyName", "Telegram Messenger LLP" VALUE "CompanyName", "Telegram Messenger LLP"
VALUE "FileVersion", "0.10.8.5" VALUE "FileVersion", "0.10.13.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "LegalCopyright", "Copyright (C) 2014-2016"
VALUE "ProductName", "Telegram Desktop" VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "0.10.8.5" VALUE "ProductVersion", "0.10.13.0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,10,8,5 FILEVERSION 0,10,13,0
PRODUCTVERSION 0,10,8,5 PRODUCTVERSION 0,10,13,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -43,10 +43,10 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Telegram Messenger LLP" VALUE "CompanyName", "Telegram Messenger LLP"
VALUE "FileDescription", "Telegram Updater" VALUE "FileDescription", "Telegram Updater"
VALUE "FileVersion", "0.10.8.5" VALUE "FileVersion", "0.10.13.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "LegalCopyright", "Copyright (C) 2014-2016"
VALUE "ProductName", "Telegram Desktop" VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "0.10.8.5" VALUE "ProductVersion", "0.10.13.0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -20,6 +20,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#include "core/single_timer.h"
class ApiWrap : public QObject, public RPCSender { class ApiWrap : public QObject, public RPCSender {
Q_OBJECT Q_OBJECT

View file

@ -42,6 +42,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "numbers.h" #include "numbers.h"
#include "observer_peer.h" #include "observer_peer.h"
#include "window/chat_background.h" #include "window/chat_background.h"
#include "window/notifications_manager.h"
namespace { namespace {
App::LaunchState _launchState = App::Launched; App::LaunchState _launchState = App::Launched;
@ -1991,13 +1992,10 @@ namespace {
if (::mousedItem == item) { if (::mousedItem == item) {
mousedItem(nullptr); mousedItem(nullptr);
} }
if (App::wnd()) {
App::wnd()->notifyItemRemoved(item);
}
} }
void historyUnregItem(HistoryItem *item) { void historyUnregItem(HistoryItem *item) {
MsgsData *data = fetchMsgsData(item->channelId(), false); auto data = fetchMsgsData(item->channelId(), false);
if (!data) return; if (!data) return;
auto i = data->find(item->id); auto i = data->find(item->id);
@ -2013,10 +2011,13 @@ namespace {
std::swap(items, j.value()); std::swap(items, j.value());
::dependentItems.erase(j); ::dependentItems.erase(j);
for_const (HistoryItem *dependent, items) { for_const (auto dependent, items) {
dependent->dependencyItemRemoved(item); dependent->dependencyItemRemoved(item);
} }
} }
if (auto manager = Window::Notifications::manager()) {
manager->clearFromItem(item);
}
if (App::main() && !App::quitting()) { if (App::main() && !App::quitting()) {
App::main()->itemRemoved(item); App::main()->itemRemoved(item);
} }

View file

@ -28,6 +28,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "lang.h" #include "lang.h"
#include "boxes/confirmbox.h" #include "boxes/confirmbox.h"
#include "ui/filedialog.h" #include "ui/filedialog.h"
#include "ui/popupmenu.h"
#include "langloaderplain.h" #include "langloaderplain.h"
#include "localstorage.h" #include "localstorage.h"
#include "autoupdater.h" #include "autoupdater.h"
@ -35,6 +36,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "observer_peer.h" #include "observer_peer.h"
#include "window/chat_background.h" #include "window/chat_background.h"
#include "media/player/media_player_instance.h" #include "media/player/media_player_instance.h"
#include "window/notifications_manager.h"
#include "history/history_location_manager.h" #include "history/history_location_manager.h"
namespace { namespace {
@ -303,9 +305,8 @@ void Application::readClients() {
if (!startUrl.isEmpty()) { if (!startUrl.isEmpty()) {
cSetStartUrl(startUrl); cSetStartUrl(startUrl);
} }
if (!cStartUrl().isEmpty() && App::main() && App::self()) { if (auto main = App::main()) {
App::main()->openLocalUrl(cStartUrl()); main->checkStartUrl();
cSetStartUrl(QString());
} }
} }
@ -332,8 +333,11 @@ void Application::closeApplication() {
if (App::launchState() == App::QuitProcessed) return; if (App::launchState() == App::QuitProcessed) return;
App::setLaunchState(App::QuitProcessed); App::setLaunchState(App::QuitProcessed);
delete AppObject; if (auto manager = Window::Notifications::manager()) {
AppObject = 0; manager->clearAllFast();
}
delete base::take(AppObject);
Sandbox::finish(); Sandbox::finish();
@ -729,6 +733,7 @@ AppClass::AppClass() : QObject()
anim::startManager(); anim::startManager();
historyInit(); historyInit();
Media::Player::start(); Media::Player::start();
Window::Notifications::start();
DEBUG_LOG(("Application Info: inited...")); DEBUG_LOG(("Application Info: inited..."));
@ -742,7 +747,8 @@ AppClass::AppClass() : QObject()
DEBUG_LOG(("Application Info: starting app...")); DEBUG_LOG(("Application Info: starting app..."));
QMimeDatabase().mimeTypeForName(qsl("text/plain")); // create mime database // Create mime database, so it won't be slow later.
QMimeDatabase().mimeTypeForName(qsl("text/plain"));
_window = new MainWindow(); _window = new MainWindow();
_window->createWinId(); _window->createWinId();
@ -1080,8 +1086,8 @@ void AppClass::checkMapVersion() {
if (Local::oldMapVersion() < AppVersion) { if (Local::oldMapVersion() < AppVersion) {
if (Local::oldMapVersion()) { if (Local::oldMapVersion()) {
QString versionFeatures; QString versionFeatures;
if ((cAlphaVersion() || cBetaVersion()) && Local::oldMapVersion() < 10003) { if ((cAlphaVersion() || cBetaVersion()) && Local::oldMapVersion() < 10012) {
versionFeatures = QString::fromUtf8("\xe2\x80\x94 New cute design for the Settings page"); versionFeatures = QString::fromUtf8("Windows and Linux:\n\xe2\x80\x94 Quick reply from notifications\n\xe2\x80\x94 Hide all notifications button added\n\xe2\x80\x94 Change notifications location and maximum count\n\nLinux:\n\xe2\x80\x94 You can enable native notifications in Settings");
} else if (!(cAlphaVersion() || cBetaVersion()) && Local::oldMapVersion() < 10005) { } else if (!(cAlphaVersion() || cBetaVersion()) && Local::oldMapVersion() < 10005) {
versionFeatures = langNewVersionText(); versionFeatures = langNewVersionText();
} else { } else {
@ -1098,8 +1104,9 @@ void AppClass::checkMapVersion() {
AppClass::~AppClass() { AppClass::~AppClass() {
Shortcuts::finish(); Shortcuts::finish();
auto window = createAndSwap(_window); delete base::take(_window);
delete window;
Window::Notifications::finish();
anim::stopManager(); anim::stopManager();
@ -1110,8 +1117,8 @@ AppClass::~AppClass() {
MTP::finish(); MTP::finish();
AppObject = nullptr; AppObject = nullptr;
deleteAndMark(_uploader); delete base::take(_uploader);
deleteAndMark(_translator); delete base::take(_translator);
Window::chatBackground()->reset(); Window::chatBackground()->reset();
@ -1128,9 +1135,9 @@ AppClass *AppClass::app() {
} }
MainWindow *AppClass::wnd() { MainWindow *AppClass::wnd() {
return AppObject ? AppObject->_window : 0; return AppObject ? AppObject->_window : nullptr;
} }
MainWidget *AppClass::main() { MainWidget *AppClass::main() {
return (AppObject && AppObject->_window) ? AppObject->_window->mainWidget() : 0; return (AppObject && AppObject->_window) ? AppObject->_window->mainWidget() : nullptr;
} }

View file

@ -22,6 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "mainwindow.h" #include "mainwindow.h"
#include "pspecific.h" #include "pspecific.h"
#include "core/single_timer.h"
class UpdateChecker; class UpdateChecker;
class Application : public QApplication { class Application : public QApplication {

View file

@ -160,7 +160,7 @@ void AbstractBox::resizeMaxHeight(int32 newWidth, int32 maxHeight) {
move(r.left(), newTop); move(r.left(), newTop);
} }
} }
parentWidget()->update(geometry().united(g).marginsAdded(QMargins(st::boxShadow.pxWidth(), st::boxShadow.pxHeight(), st::boxShadow.pxWidth(), st::boxShadow.pxHeight()))); parentWidget()->update(geometry().united(g).marginsAdded(QMargins(st::boxShadow.width(), st::boxShadow.height(), st::boxShadow.width(), st::boxShadow.height())));
} }
} }
} }

View file

@ -1405,7 +1405,7 @@ void RevokePublicLinkBox::mousePressEvent(QMouseEvent *e) {
} }
void RevokePublicLinkBox::mouseReleaseEvent(QMouseEvent *e) { void RevokePublicLinkBox::mouseReleaseEvent(QMouseEvent *e) {
auto pressed = createAndSwap(_pressed); auto pressed = base::take(_pressed);
setCursor((_selected || _pressed) ? style::cur_pointer : style::cur_default); setCursor((_selected || _pressed) ? style::cur_pointer : style::cur_default);
if (pressed && pressed == _selected) { if (pressed && pressed == _selected) {
auto text_method = pressed->isMegagroup() ? lng_channels_too_much_public_revoke_confirm_group : lng_channels_too_much_public_revoke_confirm_channel; auto text_method = pressed->isMegagroup() ? lng_channels_too_much_public_revoke_confirm_group : lng_channels_too_much_public_revoke_confirm_channel;

View file

@ -89,3 +89,24 @@ shareColumnSkip: 6px;
shareSelectDuration: 150; shareSelectDuration: 150;
shareActivateDuration: 150; shareActivateDuration: 150;
shareScrollDuration: 300; shareScrollDuration: 300;
notificationsBoxHeight: 450px;
notificationsBoxMonitorTop: 63px;
notificationsBoxMonitor: icon {{ "monitor", #000000 }};
notificationsBoxScreenTop: 10px;
notificationsBoxScreenSize: size(280px, 160px);
notificationsBoxScreenBg: titleBg;
notificationsBoxCountLabelTop: 80px;
notificationsBoxCountTop: 30px;
notificationsSampleSkip: 5px;
notificationsSampleTopSkip: 5px;
notificationsSampleBottomSkip: 5px;
notificationsSampleMargin: 2px;
notificationSampleOpacity: 0.5;
notificationSampleSize: size(64px, 16px);
notificationSampleUserpicFg: #40ace3;
notificationSampleCloseFg: #d7d7d7;
notificationSampleTextFg: #d7d7d7;
notificationSampleNameFg: #939393;

View file

@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#pragma once #pragma once
#include "abstractbox.h" #include "abstractbox.h"
#include "core/single_timer.h"
namespace Dialogs { namespace Dialogs {
class Row; class Row;

View file

@ -0,0 +1,421 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop 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/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "boxes/notifications_box.h"
#include "lang.h"
#include "ui/buttons/round_button.h"
#include "ui/widgets/discrete_slider.h"
#include "styles/style_boxes.h"
#include "styles/style_dialogs.h"
#include "styles/style_window.h"
#include "application.h"
#include "localstorage.h"
namespace {
constexpr int kMaxNotificationsCount = 5;
} // namespace
class NotificationsBox::SampleWidget : public QWidget {
public:
SampleWidget(NotificationsBox *owner, const QPixmap &cache) : QWidget(nullptr)
, _owner(owner)
, _cache(cache) {
resize(cache.width() / cache.devicePixelRatio(), cache.height() / cache.devicePixelRatio());
setAttribute(Qt::WA_MacAlwaysShowToolWindow);
setAttribute(Qt::WA_TransparentForMouseEvents);
setAttribute(Qt::WA_OpaquePaintEvent);
setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::BypassWindowManagerHint | Qt::NoDropShadowWindowHint);
setWindowOpacity(0.);
show();
}
void detach() {
_owner = nullptr;
hideFast();
}
void showFast() {
_hiding = false;
startAnimation();
}
void hideFast() {
_hiding = true;
startAnimation();
}
protected:
virtual void paintEvent(QPaintEvent *e) {
Painter p(this);
p.drawPixmap(0, 0, _cache);
}
private:
void startAnimation() {
_opacity.start([this] { animationCallback(); }, _hiding ? 1. : 0., _hiding ? 0. : 1., st::notifyFastAnim);
}
void animationCallback() {
setWindowOpacity(_opacity.current(_hiding ? 0. : 1.));
if (!_opacity.animating() && _hiding) {
if (_owner) {
_owner->removeSample(this);
}
hide();
destroyDelayed();
}
}
void destroyDelayed() {
if (_deleted) return;
_deleted = true;
// Ubuntu has a lag if deleteLater() called immediately.
#if defined Q_OS_LINUX32 || defined Q_OS_LINUX64
QTimer::singleShot(1000, [this] { delete this; });
#else // Q_OS_LINUX32 || Q_OS_LINUX64
deleteLater();
#endif // Q_OS_LINUX32 || Q_OS_LINUX64
}
NotificationsBox *_owner;
QPixmap _cache;
FloatAnimation _opacity;
bool _hiding = false;
bool _deleted = false;
};
NotificationsBox::NotificationsBox() : AbstractBox()
, _chosenCorner(Global::NotificationsCorner())
, _oldCount(snap(Global::NotificationsCount(), 1, kMaxNotificationsCount))
, _countSlider(this)
, _done(this, lang(lng_about_done), st::defaultBoxButton) {
_sampleOpacities.reserve(kMaxNotificationsCount);
for (int i = 0; i != kMaxNotificationsCount; ++i) {
_countSlider->addSection(QString::number(i + 1));
_sampleOpacities.push_back(FloatAnimation());
}
_countSlider->setActiveSectionFast(_oldCount - 1);
_countSlider->setSectionActivatedCallback([this] { countChanged(); });
setMouseTracking(true);
_done->setClickedCallback([this] { onClose(); });
prepareNotificationSampleSmall();
prepareNotificationSampleLarge();
setMaxHeight(st::notificationsBoxHeight);
prepare();
}
void NotificationsBox::paintEvent(QPaintEvent *e) {
Painter p(this);
if (paint(p)) return;
auto contentLeft = getContentLeft();
p.setFont(st::boxTitleFont);
p.setPen(st::boxTitleFg);
p.drawTextLeft(contentLeft, st::boxTitlePosition.y(), width(), lang(lng_settings_notifications_position));
auto screenRect = getScreenRect();
p.fillRect(screenRect.x(), screenRect.y(), st::notificationsBoxScreenSize.width(), st::notificationsBoxScreenSize.height(), st::notificationsBoxScreenBg);
auto monitorTop = st::notificationsBoxMonitorTop;
st::notificationsBoxMonitor.paint(p, contentLeft, monitorTop, width());
for (int corner = 0; corner != 4; ++corner) {
auto screenCorner = static_cast<Notify::ScreenCorner>(corner);
auto isLeft = Notify::IsLeftCorner(screenCorner);
auto isTop = Notify::IsTopCorner(screenCorner);
auto sampleLeft = isLeft ? (screenRect.x() + st::notificationsSampleSkip) : (screenRect.x() + screenRect.width() - st::notificationsSampleSkip - st::notificationSampleSize.width());
auto sampleTop = isTop ? (screenRect.y() + st::notificationsSampleTopSkip) : (screenRect.y() + screenRect.height() - st::notificationsSampleBottomSkip - st::notificationSampleSize.height());
if (corner == static_cast<int>(_chosenCorner)) {
auto count = currentCount();
for (int i = 0; i != kMaxNotificationsCount; ++i) {
auto opacity = _sampleOpacities[i].current(getms(), (i < count) ? 1. : 0.);
p.setOpacity(opacity);
p.drawPixmapLeft(sampleLeft, sampleTop, width(), _notificationSampleSmall);
sampleTop += (isTop ? 1 : -1) * (st::notificationSampleSize.height() + st::notificationsSampleMargin);
}
} else {
p.setOpacity(st::notificationSampleOpacity);
p.drawPixmapLeft(sampleLeft, sampleTop, width(), _notificationSampleSmall);
p.setOpacity(1.);
}
}
auto labelTop = screenRect.y() + screenRect.height() + st::notificationsBoxCountLabelTop;
p.drawTextLeft(contentLeft, labelTop, width(), lang(lng_settings_notifications_count));
}
void NotificationsBox::countChanged() {
auto count = currentCount();
auto moreSamples = (count > _oldCount);
auto from = moreSamples ? 0. : 1.;
auto to = moreSamples ? 1. : 0.;
auto indexDelta = moreSamples ? 1 : -1;
auto animatedDelta = moreSamples ? 0 : -1;
for (; _oldCount != count; _oldCount += indexDelta) {
_sampleOpacities[_oldCount + animatedDelta].start([this] { update(); }, from, to, st::notifyFastAnim);
}
if (currentCount() != Global::NotificationsCount()) {
Global::SetNotificationsCount(currentCount());
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::MaxCount);
Local::writeUserSettings();
}
}
int NotificationsBox::getContentLeft() const {
return (width() - st::notificationsBoxMonitor.width()) / 2;
}
QRect NotificationsBox::getScreenRect() const {
auto screenLeft = (width() - st::notificationsBoxScreenSize.width()) / 2;
auto screenTop = st::notificationsBoxMonitorTop + st::notificationsBoxScreenTop;
return QRect(screenLeft, screenTop, st::notificationsBoxScreenSize.width(), st::notificationsBoxScreenSize.height());
}
void NotificationsBox::resizeEvent(QResizeEvent *e) {
_done->moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _done->height());
auto screenRect = getScreenRect();
auto sliderTop = screenRect.y() + screenRect.height() + st::notificationsBoxCountLabelTop + st::notificationsBoxCountTop;
auto contentLeft = getContentLeft();
_countSlider->resizeToWidth(width() - 2 * contentLeft);
_countSlider->move(contentLeft, sliderTop);
AbstractBox::resizeEvent(e);
}
void NotificationsBox::prepareNotificationSampleSmall() {
auto width = st::notificationSampleSize.width();
auto height = st::notificationSampleSize.height();
auto sampleImage = QImage(width * cIntRetinaFactor(), height * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
sampleImage.setDevicePixelRatio(cRetinaFactor());
sampleImage.fill(st::notifyBg->c);
{
Painter p(&sampleImage);
p.setPen(Qt::NoPen);
p.setRenderHint(QPainter::HighQualityAntialiasing);
auto padding = height / 8;
auto userpicSize = height - 2 * padding;
p.setBrush(st::notificationSampleUserpicFg);
p.drawEllipse(rtlrect(padding, padding, userpicSize, userpicSize, width));
auto rowLeft = height;
auto rowHeight = padding;
auto nameTop = (height - 5 * padding) / 2;
auto nameWidth = height;
p.setBrush(st::notificationSampleNameFg);
p.drawRoundedRect(rtlrect(rowLeft, nameTop, nameWidth, rowHeight, width), rowHeight / 2, rowHeight / 2);
auto rowWidth = (width - rowLeft - 3 * padding);
auto rowTop = nameTop + rowHeight + padding;
p.setBrush(st::notificationSampleTextFg);
p.drawRoundedRect(rtlrect(rowLeft, rowTop, rowWidth, rowHeight, width), rowHeight / 2, rowHeight / 2);
rowTop += rowHeight + padding;
p.drawRoundedRect(rtlrect(rowLeft, rowTop, rowWidth, rowHeight, width), rowHeight / 2, rowHeight / 2);
auto closeLeft = width - 2 * padding;
p.fillRect(rtlrect(closeLeft, padding, padding, padding, width), st::notificationSampleCloseFg);
}
_notificationSampleSmall = App::pixmapFromImageInPlace(std_::move(sampleImage));
_notificationSampleSmall.setDevicePixelRatio(cRetinaFactor());
}
void NotificationsBox::prepareNotificationSampleUserpic() {
if (_notificationSampleUserpic.isNull()) {
_notificationSampleUserpic = App::pixmapFromImageInPlace(App::wnd()->iconLarge().scaled(st::notifyPhotoSize * cIntRetinaFactor(), st::notifyPhotoSize * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
_notificationSampleUserpic.setDevicePixelRatio(cRetinaFactor());
}
}
void NotificationsBox::prepareNotificationSampleLarge() {
int w = st::notifyWidth, h = st::notifyMinHeight;
auto sampleImage = QImage(w * cIntRetinaFactor(), h * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
sampleImage.setDevicePixelRatio(cRetinaFactor());
sampleImage.fill(st::notifyBg->c);
{
Painter p(&sampleImage);
p.fillRect(0, 0, w - st::notifyBorderWidth, st::notifyBorderWidth, st::notifyBorder->b);
p.fillRect(w - st::notifyBorderWidth, 0, st::notifyBorderWidth, h - st::notifyBorderWidth, st::notifyBorder->b);
p.fillRect(st::notifyBorderWidth, h - st::notifyBorderWidth, w - st::notifyBorderWidth, st::notifyBorderWidth, st::notifyBorder->b);
p.fillRect(0, st::notifyBorderWidth, st::notifyBorderWidth, h - st::notifyBorderWidth, st::notifyBorder->b);
prepareNotificationSampleUserpic();
p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), _notificationSampleUserpic);
int itemWidth = w - st::notifyPhotoPos.x() - st::notifyPhotoSize - st::notifyTextLeft - st::notifyClosePos.x() - st::notifyClose.width;
auto rectForName = rtlrect(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyTextTop, itemWidth, st::msgNameFont->height, w);
auto notifyText = st::dialogsTextFont->elided(lang(lng_notification_sample), itemWidth);
p.setFont(st::dialogsTextFont);
p.setPen(st::dialogsTextFgService);
p.drawText(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyItemTop + st::msgNameFont->height + st::dialogsTextFont->ascent, notifyText);
p.setPen(st::dialogsNameFg);
p.setFont(st::msgNameFont);
auto notifyTitle = st::msgNameFont->elided(qsl("Telegram Desktop"), rectForName.width());
p.drawText(rectForName.left(), rectForName.top() + st::msgNameFont->ascent, notifyTitle);
p.setOpacity(st::notifyClose.opacity);
p.drawSpriteLeft(w - st::notifyClosePos.x() - st::notifyClose.width + st::notifyClose.iconPos.x(), st::notifyClosePos.y() + st::notifyClose.iconPos.y(), w, st::notifyClose.icon);
}
_notificationSampleLarge = App::pixmapFromImageInPlace(std_::move(sampleImage));
}
void NotificationsBox::removeSample(SampleWidget *widget) {
for (auto &samples : _cornerSamples) {
for (int i = 0, size = samples.size(); i != size; ++i) {
if (samples[i] == widget) {
for (int j = i + 1; j != size; ++j) {
samples[j]->detach();
}
samples.resize(i);
break;
}
}
}
}
void NotificationsBox::mouseMoveEvent(QMouseEvent *e) {
auto screenRect = getScreenRect();
auto cornerWidth = screenRect.width() / 3;
auto cornerHeight = screenRect.height() / 3;
auto topLeft = rtlrect(screenRect.x(), screenRect.y(), cornerWidth, cornerHeight, width());
auto topRight = rtlrect(screenRect.x() + screenRect.width() - cornerWidth, screenRect.y(), cornerWidth, cornerHeight, width());
auto bottomRight = rtlrect(screenRect.x() + screenRect.width() - cornerWidth, screenRect.y() + screenRect.height() - cornerHeight, cornerWidth, cornerHeight, width());
auto bottomLeft = rtlrect(screenRect.x(), screenRect.y() + screenRect.height() - cornerHeight, cornerWidth, cornerHeight, width());
if (topLeft.contains(e->pos())) {
setOverCorner(Notify::ScreenCorner::TopLeft);
} else if (topRight.contains(e->pos())) {
setOverCorner(Notify::ScreenCorner::TopRight);
} else if (bottomRight.contains(e->pos())) {
setOverCorner(Notify::ScreenCorner::BottomRight);
} else if (bottomLeft.contains(e->pos())) {
setOverCorner(Notify::ScreenCorner::BottomLeft);
} else {
clearOverCorner();
}
}
void NotificationsBox::leaveEvent(QEvent *e) {
clearOverCorner();
}
void NotificationsBox::setOverCorner(Notify::ScreenCorner corner) {
if (_isOverCorner) {
if (corner == _overCorner) {
return;
}
for_const (auto widget, _cornerSamples[static_cast<int>(_overCorner)]) {
widget->hideFast();
}
} else {
_isOverCorner = true;
setCursor(style::cur_pointer);
Global::SetNotificationsDemoIsShown(true);
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::DemoIsShown);
}
_overCorner = corner;
auto &samples = _cornerSamples[static_cast<int>(_overCorner)];
auto samplesAlready = samples.size();
auto samplesNeeded = currentCount();
auto samplesLeave = qMin(samplesAlready, samplesNeeded);
for (int i = 0; i != samplesLeave; ++i) {
samples[i]->showFast();
}
if (samplesNeeded > samplesLeave) {
auto r = psDesktopRect();
auto isLeft = Notify::IsLeftCorner(_overCorner);
auto isTop = Notify::IsTopCorner(_overCorner);
auto sampleLeft = (isLeft == rtl()) ? (r.x() + r.width() - st::notifyWidth - st::notifyDeltaX) : (r.x() + st::notifyDeltaX);
auto sampleTop = isTop ? (r.y() + st::notifyDeltaY) : (r.y() + r.height() - st::notifyDeltaY - st::notifyMinHeight);
for (int i = samplesLeave; i != samplesNeeded; ++i) {
auto widget = std_::make_unique<SampleWidget>(this, _notificationSampleLarge);
widget->move(sampleLeft, sampleTop + (isTop ? 1 : -1) * i * (st::notifyMinHeight + st::notifyDeltaY));
widget->showFast();
samples.push_back(widget.release());
}
} else {
for (int i = samplesLeave; i != samplesAlready; ++i) {
samples[i]->hideFast();
}
}
}
void NotificationsBox::clearOverCorner() {
if (_isOverCorner) {
_isOverCorner = false;
setCursor(style::cur_default);
Global::SetNotificationsDemoIsShown(false);
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::DemoIsShown);
for_const (auto &samples, _cornerSamples) {
for_const (auto widget, samples) {
widget->hideFast();
}
}
}
}
int NotificationsBox::currentCount() const {
return _countSlider->activeSection() + 1;
}
void NotificationsBox::mousePressEvent(QMouseEvent *e) {
_isDownCorner = _isOverCorner;
_downCorner = _overCorner;
}
void NotificationsBox::mouseReleaseEvent(QMouseEvent *e) {
auto isDownCorner = base::take(_isDownCorner);
if (isDownCorner && _isOverCorner && _downCorner == _overCorner && _downCorner != _chosenCorner) {
_chosenCorner = _downCorner;
update();
if (_chosenCorner != Global::NotificationsCorner()) {
Global::SetNotificationsCorner(_chosenCorner);
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::Corner);
Local::writeUserSettings();
}
}
}
NotificationsBox::~NotificationsBox() {
for_const (auto &samples, _cornerSamples) {
for_const (auto widget, samples) {
widget->detach();
}
}
clearOverCorner();
}

View file

@ -0,0 +1,79 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop 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/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "abstractbox.h"
class BoxButton;
class LinkButton;
namespace Ui {
class DiscreteSlider;
} // namespace Ui
class NotificationsBox : public AbstractBox {
public:
NotificationsBox();
~NotificationsBox();
protected:
void paintEvent(QPaintEvent *e) override;
void resizeEvent(QResizeEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void leaveEvent(QEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
private:
using ScreenCorner = Notify::ScreenCorner;
void countChanged();
void setOverCorner(ScreenCorner corner);
void clearOverCorner();
class SampleWidget;
void removeSample(SampleWidget *widget);
int currentCount() const;
QRect getScreenRect() const;
int getContentLeft() const;
void prepareNotificationSampleSmall();
void prepareNotificationSampleLarge();
void prepareNotificationSampleUserpic();
QPixmap _notificationSampleUserpic;
QPixmap _notificationSampleSmall;
QPixmap _notificationSampleLarge;
ScreenCorner _chosenCorner;
std_::vector_of_moveable<FloatAnimation> _sampleOpacities;
bool _isOverCorner = false;
ScreenCorner _overCorner = ScreenCorner::TopLeft;
bool _isDownCorner = false;
ScreenCorner _downCorner = ScreenCorner::TopLeft;
int _oldCount;
ChildWidget<Ui::DiscreteSlider> _countSlider;
ChildWidget<BoxButton> _done;
QVector<SampleWidget*> _cornerSamples[4];
};

View file

@ -83,11 +83,11 @@ void ReportBox::onChange() {
connect(_reasonOtherText, SIGNAL(submitted(bool)), this, SLOT(onReport())); connect(_reasonOtherText, SIGNAL(submitted(bool)), this, SLOT(onReport()));
connect(_reasonOtherText, SIGNAL(cancelled()), this, SLOT(onClose())); connect(_reasonOtherText, SIGNAL(cancelled()), this, SLOT(onClose()));
} }
_reasonOtherText->setFocus();
} else if (_reasonOtherText) { } else if (_reasonOtherText) {
_reasonOtherText.destroy(); _reasonOtherText.destroy();
updateMaxHeight(); updateMaxHeight();
} }
_reasonOtherText->setFocus();
} }
void ReportBox::doSetInnerFocus() { void ReportBox::doSetInnerFocus() {

View file

@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#pragma once #pragma once
#include "abstractbox.h" #include "abstractbox.h"
#include "core/single_timer.h"
class ConfirmBox; class ConfirmBox;

View file

@ -337,7 +337,7 @@ private:
int _dragging = -1; int _dragging = -1;
int _above = -1; int _above = -1;
BoxShadow _aboveShadow; Ui::RectShadow _aboveShadow;
int32 _scrollbar = 0; int32 _scrollbar = 0;
}; };

View file

@ -769,10 +769,6 @@ structure::Value ParsedFile::readIconValue() {
} }
} }
if (parts.empty()) {
logErrorUnexpectedToken() << "at least one icon part";
return {};
}
return { structure::data::icon { parts } }; return { structure::data::icon { parts } };
} }
file_.putBack(); file_.putBack();

View file

@ -97,9 +97,6 @@ enum {
MediaOverviewStartPerPage = 5, MediaOverviewStartPerPage = 5,
MediaOverviewPreloadCount = 4, MediaOverviewPreloadCount = 4,
// a new message from the same sender is attached to previous within 15 minutes
AttachMessageToPreviousSecondsDelta = 900,
AudioSimultaneousLimit = 4, AudioSimultaneousLimit = 4,
AudioCheckPositionTimeout = 100, // 100ms per check audio pos AudioCheckPositionTimeout = 100, // 100ms per check audio pos
AudioCheckPositionDelta = 2400, // update position called each 2400 samples AudioCheckPositionDelta = 2400, // update position called each 2400 samples
@ -215,7 +212,7 @@ Efzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+\n\
8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n\n\ 8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n\n\
Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB\n\ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB\n\
-----END RSA PUBLIC KEY-----"}; -----END RSA PUBLIC KEY-----"};
keysCount = arraysize(keys); keysCount = base::array_size(keys);
return keys; return keys;
} }
@ -292,6 +289,10 @@ static const int32 ApiId = 17349;
static const char *ApiHash = "344583e45741c457fe1862106095a5eb"; static const char *ApiHash = "344583e45741c457fe1862106095a5eb";
#endif #endif
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
#error "Only little endian is supported!"
#endif // Q_BYTE_ORDER == Q_BIG_ENDIAN
#ifndef BETA_VERSION_MACRO #ifndef BETA_VERSION_MACRO
#error "Beta version macro is not defined." #error "Beta version macro is not defined."
#endif #endif
@ -375,9 +376,7 @@ enum {
WaitForChannelGetDifference = 1000, // 1s wait after show channel history before sending getChannelDifference WaitForChannelGetDifference = 1000, // 1s wait after show channel history before sending getChannelDifference
MemoryForImageCache = 64 * 1024 * 1024, // after 64mb of unpacked images we try to clear some memory MemoryForImageCache = 64 * 1024 * 1024, // after 64mb of unpacked images we try to clear some memory
NotifyWindowsCount = 3, // 3 desktop notifies at the same time
NotifySettingSaveTimeout = 1000, // wait 1 second before saving notify setting to server NotifySettingSaveTimeout = 1000, // wait 1 second before saving notify setting to server
NotifyDeletePhotoAfter = 60000, // delete notify photo after 1 minute
UpdateChunk = 100 * 1024, // 100kb parts when downloading the update UpdateChunk = 100 * 1024, // 100kb parts when downloading the update
IdleMsecs = 60 * 1000, // after 60secs without user input we think we are idle IdleMsecs = 60 * 1000, // after 60secs without user input we think we are idle

View file

@ -27,6 +27,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "core/qthelp_regex.h" #include "core/qthelp_regex.h"
#include "core/qthelp_url.h" #include "core/qthelp_url.h"
#include "localstorage.h" #include "localstorage.h"
#include "ui/popupmenu.h"
QString UrlClickHandler::copyToClipboardContextItemText() const { QString UrlClickHandler::copyToClipboardContextItemText() const {
return lang(isEmail() ? lng_context_copy_email : lng_context_copy_link); return lang(isEmail() ? lng_context_copy_email : lng_context_copy_link);

View file

@ -20,9 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#ifndef OS_MAC_OLD #include "core/stl_subset.h"
#include <memory>
#endif // OS_MAC_OLD
namespace base { namespace base {
namespace internal { namespace internal {
@ -392,191 +390,3 @@ public:
}; };
} // namespace base } // namespace base
// While we still use rpcDone() and rpcFail()
#include "mtproto/rpc_sender.h"
template <typename FunctionType>
struct LambdaUniqueHelper;
template <typename Lambda, typename R, typename ...Args>
struct LambdaUniqueHelper<R(Lambda::*)(Args...) const> {
using UniqueType = base::lambda_unique<R(Args...)>;
};
template <typename FunctionType>
using LambdaGetUnique = typename LambdaUniqueHelper<FunctionType>::UniqueType;
template <typename Base, typename FunctionType>
class RPCHandlerImplementation : public Base {
protected:
using Lambda = base::lambda_unique<FunctionType>;
using Parent = RPCHandlerImplementation<Base, FunctionType>;
public:
RPCHandlerImplementation(Lambda &&handler) : _handler(std_::move(handler)) {
}
protected:
Lambda _handler;
};
template <typename FunctionType>
using RPCDoneHandlerImplementation = RPCHandlerImplementation<RPCAbstractDoneHandler, FunctionType>;
template <typename R>
class RPCDoneHandlerImplementationBare : public RPCDoneHandlerImplementation<R(const mtpPrime*, const mtpPrime*)> { // done(from, end)
public:
using RPCDoneHandlerImplementation<R(const mtpPrime*, const mtpPrime*)>::Parent::Parent;
void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override {
return this->_handler ? this->_handler(from, end) : void(0);
}
};
template <typename R>
class RPCDoneHandlerImplementationBareReq : public RPCDoneHandlerImplementation<R(const mtpPrime*, const mtpPrime*, mtpRequestId)> { // done(from, end, req_id)
public:
using RPCDoneHandlerImplementation<R(const mtpPrime*, const mtpPrime*, mtpRequestId)>::Parent::Parent;
void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override {
return this->_handler ? this->_handler(from, end, requestId) : void(0);
}
};
template <typename R, typename T>
class RPCDoneHandlerImplementationPlain : public RPCDoneHandlerImplementation<R(const T&)> { // done(result)
public:
using RPCDoneHandlerImplementation<R(const T&)>::Parent::Parent;
void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override {
return this->_handler ? this->_handler(T(from, end)) : void(0);
}
};
template <typename R, typename T>
class RPCDoneHandlerImplementationReq : public RPCDoneHandlerImplementation<R(const T&, mtpRequestId)> { // done(result, req_id)
public:
using RPCDoneHandlerImplementation<R(const T&, mtpRequestId)>::Parent::Parent;
void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override {
return this->_handler ? this->_handler(T(from, end), requestId) : void(0);
}
};
template <typename R>
class RPCDoneHandlerImplementationNo : public RPCDoneHandlerImplementation<R()> { // done()
public:
using RPCDoneHandlerImplementation<R()>::Parent::Parent;
void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override {
return this->_handler ? this->_handler() : void(0);
}
};
template <typename R>
class RPCDoneHandlerImplementationNoReq : public RPCDoneHandlerImplementation<R(mtpRequestId)> { // done(req_id)
public:
using RPCDoneHandlerImplementation<R(mtpRequestId)>::Parent::Parent;
void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override {
return this->_handler ? this->_handler(requestId) : void(0);
}
};
template <typename R>
inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique<R(const mtpPrime*, const mtpPrime*)> &&lambda) {
return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationBare<R>(std_::move(lambda)));
}
template <typename R>
inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique<R(const mtpPrime*, const mtpPrime*, mtpRequestId)> &&lambda) {
return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationBareReq<R>(std_::move(lambda)));
}
template <typename R, typename T>
inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique<R(const T&)> &&lambda) {
return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationPlain<R, T>(std_::move(lambda)));
}
template <typename R, typename T>
inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique<R(const T&, mtpRequestId)> &&lambda) {
return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationReq<R, T>(std_::move(lambda)));
}
template <typename R>
inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique<R()> &&lambda) {
return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationNo<R>(std_::move(lambda)));
}
template <typename R>
inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique<R(mtpRequestId)> &&lambda) {
return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationNoReq<R>(std_::move(lambda)));
}
template <typename Lambda, typename = std_::enable_if_t<std_::is_rvalue_reference<Lambda&&>::value>>
RPCDoneHandlerPtr rpcDone(Lambda &&lambda) {
return rpcDone_lambda_wrap_helper(LambdaGetUnique<decltype(&Lambda::operator())>(std_::move(lambda)));
}
template <typename FunctionType>
using RPCFailHandlerImplementation = RPCHandlerImplementation<RPCAbstractFailHandler, FunctionType>;
class RPCFailHandlerImplementationPlain : public RPCFailHandlerImplementation<bool(const RPCError&)> { // fail(error)
public:
using Parent::Parent;
bool operator()(mtpRequestId requestId, const RPCError &error) const override {
return _handler ? _handler(error) : true;
}
};
class RPCFailHandlerImplementationReq : public RPCFailHandlerImplementation<bool(const RPCError&, mtpRequestId)> { // fail(error, req_id)
public:
using Parent::Parent;
bool operator()(mtpRequestId requestId, const RPCError &error) const override {
return this->_handler ? this->_handler(error, requestId) : true;
}
};
class RPCFailHandlerImplementationNo : public RPCFailHandlerImplementation<bool()> { // fail()
public:
using Parent::Parent;
bool operator()(mtpRequestId requestId, const RPCError &error) const override {
return this->_handler ? this->_handler() : true;
}
};
class RPCFailHandlerImplementationNoReq : public RPCFailHandlerImplementation<bool(mtpRequestId)> { // fail(req_id)
public:
using Parent::Parent;
bool operator()(mtpRequestId requestId, const RPCError &error) const override {
return this->_handler ? this->_handler(requestId) : true;
}
};
inline RPCFailHandlerPtr rpcFail_lambda_wrap_helper(base::lambda_unique<bool(const RPCError&)> &&lambda) {
return RPCFailHandlerPtr(new RPCFailHandlerImplementationPlain(std_::move(lambda)));
}
inline RPCFailHandlerPtr rpcFail_lambda_wrap_helper(base::lambda_unique<bool(const RPCError&, mtpRequestId)> &&lambda) {
return RPCFailHandlerPtr(new RPCFailHandlerImplementationReq(std_::move(lambda)));
}
inline RPCFailHandlerPtr rpcFail_lambda_wrap_helper(base::lambda_unique<bool()> &&lambda) {
return RPCFailHandlerPtr(new RPCFailHandlerImplementationNo(std_::move(lambda)));
}
inline RPCFailHandlerPtr rpcFail_lambda_wrap_helper(base::lambda_unique<bool(mtpRequestId)> &&lambda) {
return RPCFailHandlerPtr(new RPCFailHandlerImplementationNoReq(std_::move(lambda)));
}
template <typename Lambda, typename = std_::enable_if_t<std_::is_rvalue_reference<Lambda&&>::value>>
RPCFailHandlerPtr rpcFail(Lambda &&lambda) {
return rpcFail_lambda_wrap_helper(LambdaGetUnique<decltype(&Lambda::operator())>(std_::move(lambda)));
}

View file

@ -60,7 +60,7 @@ public:
Subscription() = default; Subscription() = default;
Subscription(const Subscription &) = delete; Subscription(const Subscription &) = delete;
Subscription &operator=(const Subscription &) = delete; Subscription &operator=(const Subscription &) = delete;
Subscription(Subscription &&other) : _node(createAndSwap(other._node)), _removeMethod(other._removeMethod) { Subscription(Subscription &&other) : _node(base::take(other._node)), _removeMethod(other._removeMethod) {
} }
Subscription &operator=(Subscription &&other) { Subscription &operator=(Subscription &&other) {
qSwap(_node, other._node); qSwap(_node, other._node);
@ -258,7 +258,7 @@ public:
private: private:
void callHandlers() { void callHandlers() {
_handling = true; _handling = true;
auto events = createAndSwap(_events); auto events = base::take(_events);
for (auto &event : events) { for (auto &event : events) {
this->notifyEnumerate([this, &event]() { this->notifyEnumerate([this, &event]() {
this->_current->handler(event); this->_current->handler(event);
@ -305,7 +305,7 @@ public:
private: private:
void callHandlers() { void callHandlers() {
_handling = true; _handling = true;
auto eventsCount = createAndSwap(_eventsCount); auto eventsCount = base::take(_eventsCount);
for (int i = 0; i != eventsCount; ++i) { for (int i = 0; i != eventsCount; ++i) {
this->notifyEnumerate([this]() { this->notifyEnumerate([this]() {
this->_current->handler(); this->_current->handler();
@ -352,7 +352,7 @@ protected:
} }
~Subscriber() { ~Subscriber() {
auto subscriptions = createAndSwap(_subscriptions); auto subscriptions = base::take(_subscriptions);
for (auto &subscription : subscriptions) { for (auto &subscription : subscriptions) {
subscription.destroy(); subscription.destroy();
} }

View file

@ -0,0 +1,80 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop 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/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "core/single_timer.h"
#include "application.h"
SingleTimer::SingleTimer() {
QTimer::setSingleShot(true);
if (App::app()) {
connect(App::app(), SIGNAL(adjustSingleTimers()), this, SLOT(adjust()));
_inited = true;
}
}
void SingleTimer::setTimeoutHandler(base::lambda_unique<void()> &&handler) {
if (_handler && !handler) {
disconnect(this, SIGNAL(timeout()), this, SLOT(onTimeout()));
} else if (handler && !_handler) {
connect(this, SIGNAL(timeout()), this, SLOT(onTimeout()));
}
_handler = std_::move(handler);
}
void SingleTimer::adjust() {
uint64 n = getms(true);
if (isActive()) {
if (n >= _finishing) {
start(0);
} else {
start(_finishing - n);
}
}
}
void SingleTimer::onTimeout() {
if (_handler) {
_handler();
}
}
void SingleTimer::start(int msec) {
_finishing = getms(true) + (msec < 0 ? 0 : uint64(msec));
if (!_inited && App::app()) {
connect(App::app(), SIGNAL(adjustSingleTimers()), this, SLOT(adjust()));
_inited = true;
}
QTimer::start(msec);
}
void SingleTimer::startIfNotActive(int msec) {
if (isActive()) {
int remains = remainingTime();
if (remains > msec) {
start(msec);
} else if (!remains) {
start(1);
}
} else {
start(msec);
}
}

View file

@ -0,0 +1,50 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop 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/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "core/basic_types.h"
#include "core/lambda_wrap.h"
class SingleTimer : public QTimer { // single shot timer with check
Q_OBJECT
public:
SingleTimer();
void setSingleShot(bool); // is not available
void start(); // is not available
void setTimeoutHandler(base::lambda_unique<void()> &&handler);
public slots:
void start(int msec);
void startIfNotActive(int msec);
private slots:
void adjust();
void onTimeout();
private:
uint64 _finishing = 0;
bool _inited = false;
base::lambda_unique<void()> _handler;
};

View file

@ -345,36 +345,6 @@ uint64 getms(bool checked) {
#endif #endif
} }
SingleTimer::SingleTimer() : _finishing(0), _inited(false) {
QTimer::setSingleShot(true);
if (App::app()) {
connect(App::app(), SIGNAL(adjustSingleTimers()), this, SLOT(adjust()));
_inited = true;
}
}
void SingleTimer::start(int msec) {
_finishing = getms(true) + (msec < 0 ? 0 : uint64(msec));
if (!_inited && App::app()) {
connect(App::app(), SIGNAL(adjustSingleTimers()), this, SLOT(adjust()));
_inited = true;
}
QTimer::start(msec);
}
void SingleTimer::startIfNotActive(int msec) {
if (isActive()) {
int remains = remainingTime();
if (remains > msec) {
start(msec);
} else if (!remains) {
start(1);
}
} else {
start(msec);
}
}
uint64 msgid() { uint64 msgid() {
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
LARGE_INTEGER li; LARGE_INTEGER li;

View file

@ -22,23 +22,21 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "core/basic_types.h" #include "core/basic_types.h"
namespace base {
template <typename T, size_t N> template <typename T, size_t N>
inline constexpr size_t arraysize(T(&ArrahSizeHelper)[N]) { inline constexpr size_t array_size(T(&)[N]) {
return N; return N;
} }
template <typename T> template <typename T>
void deleteAndMark(T *&link) { inline T take(T &source) {
delete link; T result = T();
link = reinterpret_cast<T*>(0x00000BAD); std_::swap_moveable(result, source);
return std_::move(result);
} }
template <typename T> } // namespace base
T *getPointerAndReset(T *&ptr) {
T *result = nullptr;
qSwap(result, ptr);
return result;
}
template <typename Enum> template <typename Enum>
inline QFlags<Enum> qFlags(Enum v) { inline QFlags<Enum> qFlags(Enum v) {
@ -87,13 +85,6 @@ inline void accumulate_max(T &a, const T &b) { if (a < b) a = b; }
template <typename T> template <typename T>
inline void accumulate_min(T &a, const T &b) { if (a > b) a = b; } inline void accumulate_min(T &a, const T &b) { if (a > b) a = b; }
template <typename T>
T createAndSwap(T &value) {
T result = T();
std_::swap_moveable(result, value);
return std_::move(result);
}
static volatile int *t_assert_nullptr = nullptr; static volatile int *t_assert_nullptr = nullptr;
inline void t_noop() {} inline void t_noop() {}
inline void t_assert_fail(const char *message, const char *file, int32 line) { inline void t_assert_fail(const char *message, const char *file, int32 line) {
@ -172,37 +163,6 @@ void finish();
bool checkms(); // returns true if time has changed bool checkms(); // returns true if time has changed
uint64 getms(bool checked = false); uint64 getms(bool checked = false);
class SingleTimer : public QTimer { // single shot timer with check
Q_OBJECT
public:
SingleTimer();
void setSingleShot(bool); // is not available
void start(); // is not available
public slots:
void start(int msec);
void startIfNotActive(int msec);
void adjust() {
uint64 n = getms(true);
if (isActive()) {
if (n >= _finishing) {
start(0);
} else {
start(_finishing - n);
}
}
}
private:
uint64 _finishing;
bool _inited;
};
const static uint32 _md5_block_size = 64; const static uint32 _md5_block_size = 64;
class HashMd5 { class HashMd5 {
public: public:
@ -508,7 +468,7 @@ public:
return _p; return _p;
} }
T *release() { T *release() {
return getPointerAndReset(_p); return base::take(_p);
} }
void reset(T *p = nullptr) { void reset(T *p = nullptr) {
delete _p; delete _p;
@ -551,7 +511,7 @@ public:
return _p; return _p;
} }
T *release() { T *release() {
return getPointerAndReset(_p); return base::take(_p);
} }
void reset(T *p = nullptr) { void reset(T *p = nullptr) {
delete _p; delete _p;

View file

@ -36,9 +36,9 @@ public:
vector_of_moveable(const vector_of_moveable &other) = delete; vector_of_moveable(const vector_of_moveable &other) = delete;
vector_of_moveable &operator=(const vector_of_moveable &other) = delete; vector_of_moveable &operator=(const vector_of_moveable &other) = delete;
vector_of_moveable(vector_of_moveable &&other) vector_of_moveable(vector_of_moveable &&other)
: _size(createAndSwap(other._size)) : _size(base::take(other._size))
, _capacity(createAndSwap(other._capacity)) , _capacity(base::take(other._capacity))
, _plaindata(createAndSwap(other._plaindata)) { , _plaindata(base::take(other._plaindata)) {
} }
vector_of_moveable &operator=(vector_of_moveable &&other) { vector_of_moveable &operator=(vector_of_moveable &&other) {
std_::swap_moveable(_size, other._size); std_::swap_moveable(_size, other._size);

View file

@ -22,9 +22,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "core/utils.h" #include "core/utils.h"
#define BETA_VERSION_MACRO (10008005ULL) #define BETA_VERSION_MACRO (0ULL)
constexpr int AppVersion = 10008; constexpr int AppVersion = 10013;
constexpr str_const AppVersionStr = "0.10.8"; constexpr str_const AppVersionStr = "0.10.13";
constexpr bool AppAlphaVersion = false; constexpr bool AppAlphaVersion = true;
constexpr uint64 AppBetaVersion = BETA_VERSION_MACRO; constexpr uint64 AppBetaVersion = BETA_VERSION_MACRO;

View file

@ -25,6 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "dialogs/dialogs_layout.h" #include "dialogs/dialogs_layout.h"
#include "styles/style_dialogs.h" #include "styles/style_dialogs.h"
#include "ui/buttons/round_button.h" #include "ui/buttons/round_button.h"
#include "ui/popupmenu.h"
#include "data/data_drafts.h" #include "data/data_drafts.h"
#include "lang.h" #include "lang.h"
#include "application.h" #include "application.h"
@ -122,8 +123,8 @@ void DialogsInner::paintRegion(Painter &p, const QRegion &region, bool paintingO
p.fillRect(0, 0, w, st::mentionHeight, (selected ? st::mentionBgOver : st::white)->b); p.fillRect(0, 0, w, st::mentionHeight, (selected ? st::mentionBgOver : st::white)->b);
if (!paintingOther) { if (!paintingOther) {
if (selected) { if (selected) {
int skip = (st::mentionHeight - st::notifyClose.icon.pxHeight()) / 2; int skip = (st::mentionHeight - st::simpleClose.icon.pxHeight()) / 2;
p.drawSprite(QPoint(w - st::notifyClose.icon.pxWidth() - skip, skip), st::notifyClose.icon); p.drawSprite(QPoint(w - st::simpleClose.icon.pxWidth() - skip, skip), st::simpleClose.icon);
} }
QString first = (_hashtagFilter.size() < 2) ? QString() : ('#' + _hashtagResults.at(from).mid(0, _hashtagFilter.size() - 1)), second = (_hashtagFilter.size() < 2) ? ('#' + _hashtagResults.at(from)) : _hashtagResults.at(from).mid(_hashtagFilter.size() - 1); QString first = (_hashtagFilter.size() < 2) ? QString() : ('#' + _hashtagResults.at(from).mid(0, _hashtagFilter.size() - 1)), second = (_hashtagFilter.size() < 2) ? ('#' + _hashtagResults.at(from)) : _hashtagResults.at(from).mid(_hashtagFilter.size() - 1);
int32 firstwidth = st::mentionFont->width(first), secondwidth = st::mentionFont->width(second); int32 firstwidth = st::mentionFont->width(first), secondwidth = st::mentionFont->width(second);
@ -478,7 +479,6 @@ void DialogsInner::removeDialog(History *history) {
if (importantDialogs) { if (importantDialogs) {
history->removeFromChatList(Dialogs::Mode::Important, importantDialogs.get()); history->removeFromChatList(Dialogs::Mode::Important, importantDialogs.get());
} }
history->clearNotifications();
if (App::wnd()) App::wnd()->notifyClear(history); if (App::wnd()) App::wnd()->notifyClear(history);
if (contacts->contains(history->peer->id)) { if (contacts->contains(history->peer->id)) {
if (!contactsNoDialogs->contains(history->peer->id)) { if (!contactsNoDialogs->contains(history->peer->id)) {

View file

@ -22,7 +22,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "window/section_widget.h" #include "window/section_widget.h"
class MainWidget;
namespace Dialogs { namespace Dialogs {
class Row; class Row;
class FakeRow; class FakeRow;
@ -33,6 +32,9 @@ namespace Ui {
class RoundButton; class RoundButton;
} // namespace Ui } // namespace Ui
class MainWidget;
class PopupMenu;
enum DialogsSearchRequestType { enum DialogsSearchRequestType {
DialogsSearchFromStart, DialogsSearchFromStart,
DialogsSearchFromOffset, DialogsSearchFromOffset,

View file

@ -122,7 +122,7 @@ void Dropdown::resizeEvent(QResizeEvent *e) {
} }
void Dropdown::paintEvent(QPaintEvent *e) { void Dropdown::paintEvent(QPaintEvent *e) {
QPainter p(this); Painter p(this);
if (_a_appearance.animating()) { if (_a_appearance.animating()) {
p.setOpacity(a_opacity.current()); p.setOpacity(a_opacity.current());
@ -358,7 +358,7 @@ void DragArea::setText(const QString &text, const QString &subtext) {
} }
void DragArea::paintEvent(QPaintEvent *e) { void DragArea::paintEvent(QPaintEvent *e) {
QPainter p(this); Painter p(this);
if (_a_appearance.animating()) { if (_a_appearance.animating()) {
p.setOpacity(a_opacity.current()); p.setOpacity(a_opacity.current());

View file

@ -21,7 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#pragma once #pragma once
#include "ui/twidget.h" #include "ui/twidget.h"
#include "ui/boxshadow.h" #include "ui/effects/rect_shadow.h"
class Dropdown : public TWidget { class Dropdown : public TWidget {
Q_OBJECT Q_OBJECT
@ -91,7 +91,7 @@ private:
QTimer _hideTimer; QTimer _hideTimer;
BoxShadow _shadow; Ui::RectShadow _shadow;
}; };
@ -101,13 +101,6 @@ class DragArea : public TWidget {
public: public:
DragArea(QWidget *parent); DragArea(QWidget *parent);
void paintEvent(QPaintEvent *e);
void mouseMoveEvent(QMouseEvent *e);
void dragEnterEvent(QDragEnterEvent *e);
void dragLeaveEvent(QDragLeaveEvent *e);
void dropEvent(QDropEvent *e);
void dragMoveEvent(QDragMoveEvent *e);
void setText(const QString &text, const QString &subtext); void setText(const QString &text, const QString &subtext);
void otherEnter(); void otherEnter();
@ -127,6 +120,14 @@ public:
).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size())); ).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
} }
protected:
void paintEvent(QPaintEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void dragEnterEvent(QDragEnterEvent *e) override;
void dragLeaveEvent(QDragLeaveEvent *e) override;
void dropEvent(QDropEvent *e) override;
void dragMoveEvent(QDragMoveEvent *e) override;
signals: signals:
void dropped(const QMimeData *data); void dropped(const QMimeData *data);
@ -143,7 +144,7 @@ private:
anim::cvalue a_color; anim::cvalue a_color;
Animation _a_appearance; Animation _a_appearance;
BoxShadow _shadow; Ui::RectShadow _shadow;
QString _text, _subtext; QString _text, _subtext;

View file

@ -634,8 +634,10 @@ struct Data {
bool RestoreSoundNotifyFromTray = false; bool RestoreSoundNotifyFromTray = false;
bool IncludeMuted = true; bool IncludeMuted = true;
DBINotifyView NotifyView = dbinvShowPreview; DBINotifyView NotifyView = dbinvShowPreview;
bool WindowsNotifications = true; bool NativeNotifications = false;
bool CustomNotifies = (cPlatform() == dbipMac) ? false : true; int NotificationsCount = 3;
Notify::ScreenCorner NotificationsCorner = Notify::ScreenCorner::BottomRight;
bool NotificationsDemoIsShown = false;
base::Observable<Notify::ChangeType> NotifySettingsChanged; base::Observable<Notify::ChangeType> NotifySettingsChanged;
DBIConnectionType ConnectionType = dbictAuto; DBIConnectionType ConnectionType = dbictAuto;
@ -742,8 +744,10 @@ DefineVar(Global, bool, DesktopNotify);
DefineVar(Global, bool, RestoreSoundNotifyFromTray); DefineVar(Global, bool, RestoreSoundNotifyFromTray);
DefineVar(Global, bool, IncludeMuted); DefineVar(Global, bool, IncludeMuted);
DefineVar(Global, DBINotifyView, NotifyView); DefineVar(Global, DBINotifyView, NotifyView);
DefineVar(Global, bool, WindowsNotifications); DefineVar(Global, bool, NativeNotifications);
DefineVar(Global, bool, CustomNotifies); DefineVar(Global, int, NotificationsCount);
DefineVar(Global, Notify::ScreenCorner, NotificationsCorner);
DefineVar(Global, bool, NotificationsDemoIsShown);
DefineRefVar(Global, base::Observable<Notify::ChangeType>, NotifySettingsChanged); DefineRefVar(Global, base::Observable<Notify::ChangeType>, NotifySettingsChanged);
DefineVar(Global, DBIConnectionType, ConnectionType); DefineVar(Global, DBIConnectionType, ConnectionType);

View file

@ -148,9 +148,26 @@ enum class ChangeType {
IncludeMuted, IncludeMuted,
DesktopEnabled, DesktopEnabled,
ViewParams, ViewParams,
UseNative, MaxCount,
Corner,
DemoIsShown,
}; };
enum class ScreenCorner {
TopLeft = 0,
TopRight = 1,
BottomRight = 2,
BottomLeft = 3,
};
inline bool IsLeftCorner(ScreenCorner corner) {
return (corner == ScreenCorner::TopLeft) || (corner == ScreenCorner::BottomLeft);
}
inline bool IsTopCorner(ScreenCorner corner) {
return (corner == ScreenCorner::TopLeft) || (corner == ScreenCorner::TopRight);
}
} // namespace Notify } // namespace Notify
#define DeclareReadOnlyVar(Type, Name) const Type &Name(); #define DeclareReadOnlyVar(Type, Name) const Type &Name();
@ -309,8 +326,10 @@ DeclareVar(bool, DesktopNotify);
DeclareVar(bool, RestoreSoundNotifyFromTray); DeclareVar(bool, RestoreSoundNotifyFromTray);
DeclareVar(bool, IncludeMuted); DeclareVar(bool, IncludeMuted);
DeclareVar(DBINotifyView, NotifyView); DeclareVar(DBINotifyView, NotifyView);
DeclareVar(bool, WindowsNotifications); DeclareVar(bool, NativeNotifications);
DeclareVar(bool, CustomNotifies); DeclareVar(int, NotificationsCount);
DeclareVar(Notify::ScreenCorner, NotificationsCorner);
DeclareVar(bool, NotificationsDemoIsShown);
DeclareRefVar(base::Observable<Notify::ChangeType>, NotifySettingsChanged); DeclareRefVar(base::Observable<Notify::ChangeType>, NotifySettingsChanged);
DeclareVar(DBIConnectionType, ConnectionType); DeclareVar(DBIConnectionType, ConnectionType);

View file

@ -1427,7 +1427,6 @@ MsgId History::inboxRead(MsgId upTo) {
showFrom = nullptr; showFrom = nullptr;
App::wnd()->notifyClear(this); App::wnd()->notifyClear(this);
clearNotifications();
return upTo; return upTo;
} }

View file

@ -28,13 +28,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
FieldAutocomplete::FieldAutocomplete(QWidget *parent) : TWidget(parent) FieldAutocomplete::FieldAutocomplete(QWidget *parent) : TWidget(parent)
, _scroll(this, st::mentionScroll) , _scroll(this, st::mentionScroll)
, _inner(this, &_mrows, &_hrows, &_brows, &_srows) , _inner(this, &_mrows, &_hrows, &_brows, &_srows)
, _chat(0)
, _user(0)
, _channel(0)
, _hiding(false)
, a_opacity(0) , a_opacity(0)
, _a_appearance(animation(this, &FieldAutocomplete::step_appearance)) , _a_appearance(animation(this, &FieldAutocomplete::step_appearance)) {
, _shadow(st::dropdownDef.shadow) {
_hideTimer.setSingleShot(true); _hideTimer.setSingleShot(true);
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(hideStart())); connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(hideStart()));
@ -605,9 +600,9 @@ void FieldAutocompleteInner::paintEvent(QPaintEvent *e) {
bool selected = (i == _sel); bool selected = (i == _sel);
if (selected) { if (selected) {
p.fillRect(0, i * st::mentionHeight, width(), st::mentionHeight, st::mentionBgOver->b); p.fillRect(0, i * st::mentionHeight, width(), st::mentionHeight, st::mentionBgOver->b);
int skip = (st::mentionHeight - st::notifyClose.icon.pxHeight()) / 2; int skip = (st::mentionHeight - st::simpleClose.icon.pxHeight()) / 2;
if (!_hrows->isEmpty() || (!_mrows->isEmpty() && i < _recentInlineBotsInRows)) { if (!_hrows->isEmpty() || (!_mrows->isEmpty() && i < _recentInlineBotsInRows)) {
p.drawSprite(QPoint(width() - st::notifyClose.icon.pxWidth() - skip, i * st::mentionHeight + skip), st::notifyClose.icon); p.drawSprite(QPoint(width() - st::simpleClose.icon.pxWidth() - skip, i * st::mentionHeight + skip), st::simpleClose.icon);
} }
} }
p.setPen(st::black->p); p.setPen(st::black->p);

View file

@ -21,7 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#pragma once #pragma once
#include "ui/twidget.h" #include "ui/twidget.h"
#include "ui/boxshadow.h" #include "ui/effects/rect_shadow.h"
namespace internal { namespace internal {
@ -91,9 +91,10 @@ public slots:
void showStart(); void showStart();
private: protected:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
private:
void updateFiltered(bool resetScroll = false); void updateFiltered(bool resetScroll = false);
void recount(bool resetScroll = false); void recount(bool resetScroll = false);
@ -108,9 +109,9 @@ private:
ChildWidget<ScrollArea> _scroll; ChildWidget<ScrollArea> _scroll;
ChildWidget<internal::FieldAutocompleteInner> _inner; ChildWidget<internal::FieldAutocompleteInner> _inner;
ChatData *_chat; ChatData *_chat = nullptr;
UserData *_user; UserData *_user = nullptr;
ChannelData *_channel; ChannelData *_channel = nullptr;
EmojiPtr _emoji; EmojiPtr _emoji;
enum class Type { enum class Type {
Mentions, Mentions,
@ -124,14 +125,13 @@ private:
bool _addInlineBots; bool _addInlineBots;
int32 _width, _height; int32 _width, _height;
bool _hiding; bool _hiding = false;
anim::fvalue a_opacity; anim::fvalue a_opacity;
Animation _a_appearance; Animation _a_appearance;
QTimer _hideTimer; QTimer _hideTimer;
BoxShadow _shadow;
friend class internal::FieldAutocompleteInner; friend class internal::FieldAutocompleteInner;
}; };

View file

@ -28,6 +28,13 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "styles/style_dialogs.h" #include "styles/style_dialogs.h"
#include "fileuploader.h" #include "fileuploader.h"
namespace {
// a new message from the same sender is attached to previous within 15 minutes
constexpr int kAttachMessageToPreviousSecondsDelta = 900;
} // namespace
ReplyMarkupClickHandler::ReplyMarkupClickHandler(const HistoryItem *item, int row, int col) ReplyMarkupClickHandler::ReplyMarkupClickHandler(const HistoryItem *item, int row, int col)
: _itemId(item->fullId()) : _itemId(item->fullId())
, _row(row) , _row(row)
@ -352,7 +359,7 @@ void HistoryMessageReplyMarkup::createFromButtonRows(const QVector<MTPKeyboardBu
if (!b.isEmpty()) { if (!b.isEmpty()) {
ButtonRow buttonRow; ButtonRow buttonRow;
buttonRow.reserve(b.size()); buttonRow.reserve(b.size());
for_const (const auto &button, b) { for_const (auto &button, b) {
switch (button.type()) { switch (button.type()) {
case mtpc_keyboardButton: { case mtpc_keyboardButton: {
buttonRow.push_back({ Button::Type::Default, qs(button.c_keyboardButton().vtext), QByteArray(), 0 }); buttonRow.push_back({ Button::Type::Default, qs(button.c_keyboardButton().vtext), QByteArray(), 0 });
@ -401,31 +408,46 @@ void HistoryMessageReplyMarkup::create(const MTPReplyMarkup &markup) {
switch (markup.type()) { switch (markup.type()) {
case mtpc_replyKeyboardMarkup: { case mtpc_replyKeyboardMarkup: {
const auto &d(markup.c_replyKeyboardMarkup()); auto &d = markup.c_replyKeyboardMarkup();
flags = d.vflags.v; flags = d.vflags.v;
createFromButtonRows(d.vrows.c_vector().v); createFromButtonRows(d.vrows.c_vector().v);
} break; } break;
case mtpc_replyInlineMarkup: { case mtpc_replyInlineMarkup: {
const auto &d(markup.c_replyInlineMarkup()); auto &d = markup.c_replyInlineMarkup();
flags = MTPDreplyKeyboardMarkup::Flags(0) | MTPDreplyKeyboardMarkup_ClientFlag::f_inline; flags = MTPDreplyKeyboardMarkup::Flags(0) | MTPDreplyKeyboardMarkup_ClientFlag::f_inline;
createFromButtonRows(d.vrows.c_vector().v); createFromButtonRows(d.vrows.c_vector().v);
} break; } break;
case mtpc_replyKeyboardHide: { case mtpc_replyKeyboardHide: {
const auto &d(markup.c_replyKeyboardHide()); auto &d = markup.c_replyKeyboardHide();
flags = mtpCastFlags(d.vflags) | MTPDreplyKeyboardMarkup_ClientFlag::f_zero; flags = mtpCastFlags(d.vflags) | MTPDreplyKeyboardMarkup_ClientFlag::f_zero;
} break; } break;
case mtpc_replyKeyboardForceReply: { case mtpc_replyKeyboardForceReply: {
const auto &d(markup.c_replyKeyboardForceReply()); auto &d = markup.c_replyKeyboardForceReply();
flags = mtpCastFlags(d.vflags) | MTPDreplyKeyboardMarkup_ClientFlag::f_force_reply; flags = mtpCastFlags(d.vflags) | MTPDreplyKeyboardMarkup_ClientFlag::f_force_reply;
} break; } break;
} }
} }
void HistoryMessageReplyMarkup::create(const HistoryMessageReplyMarkup &markup) {
flags = markup.flags;
inlineKeyboard = nullptr;
rows.clear();
for_const (auto &row, markup.rows) {
ButtonRow buttonRow;
buttonRow.reserve(row.size());
for_const (auto &button, row) {
buttonRow.push_back({ button.type, button.text, button.data, 0 });
}
if (!buttonRow.isEmpty()) rows.push_back(buttonRow);
}
}
void HistoryMessageUnreadBar::init(int count) { void HistoryMessageUnreadBar::init(int count) {
if (_freezed) return; if (_freezed) return;
_text = lng_unread_bar(lt_count, count); _text = lng_unread_bar(lt_count, count);
@ -482,19 +504,19 @@ void HistoryMediaPtr::reset(HistoryMedia *p) {
namespace internal { namespace internal {
TextSelection unshiftSelection(TextSelection selection, const Text &byText) { TextSelection unshiftSelection(TextSelection selection, const Text &byText) {
if (selection == FullSelection) { if (selection == FullSelection) {
return selection; return selection;
}
return ::unshiftSelection(selection, byText);
} }
return ::unshiftSelection(selection, byText);
}
TextSelection shiftSelection(TextSelection selection, const Text &byText) { TextSelection shiftSelection(TextSelection selection, const Text &byText) {
if (selection == FullSelection) { if (selection == FullSelection) {
return selection; return selection;
}
return ::shiftSelection(selection, byText);
} }
return ::shiftSelection(selection, byText);
}
} // namespace internal } // namespace internal
@ -629,7 +651,7 @@ void HistoryItem::recountAttachToPrevious() {
&& !previos->serviceMsg() && !previos->serviceMsg()
&& !previos->isEmpty() && !previos->isEmpty()
&& previos->from() == from() && previos->from() == from()
&& (qAbs(previos->date.secsTo(date)) < AttachMessageToPreviousSecondsDelta); && (qAbs(previos->date.secsTo(date)) < kAttachMessageToPreviousSecondsDelta);
} }
} }
if (attach && !(_flags & MTPDmessage_ClientFlag::f_attach_to_previous)) { if (attach && !(_flags & MTPDmessage_ClientFlag::f_attach_to_previous)) {

View file

@ -199,6 +199,7 @@ struct HistoryMessageReplyMarkup : public RuntimeComponent<HistoryMessageReplyMa
} }
void create(const MTPReplyMarkup &markup); void create(const MTPReplyMarkup &markup);
void create(const HistoryMessageReplyMarkup &markup);
struct Button { struct Button {
enum class Type { enum class Type {
@ -436,8 +437,8 @@ private:
namespace internal { namespace internal {
TextSelection unshiftSelection(TextSelection selection, const Text &byText); TextSelection unshiftSelection(TextSelection selection, const Text &byText);
TextSelection shiftSelection(TextSelection selection, const Text &byText); TextSelection shiftSelection(TextSelection selection, const Text &byText);
} // namespace internal } // namespace internal
@ -758,13 +759,13 @@ public:
} }
PeerData *fromOriginal() const { PeerData *fromOriginal() const {
if (const HistoryMessageForwarded *fwd = Get<HistoryMessageForwarded>()) { if (auto fwd = Get<HistoryMessageForwarded>()) {
return fwd->_fromOriginal; return fwd->_fromOriginal;
} }
return from(); return from();
} }
PeerData *authorOriginal() const { PeerData *authorOriginal() const {
if (const HistoryMessageForwarded *fwd = Get<HistoryMessageForwarded>()) { if (auto fwd = Get<HistoryMessageForwarded>()) {
return fwd->_authorOriginal; return fwd->_authorOriginal;
} }
return author(); return author();
@ -837,7 +838,7 @@ public:
void clipCallback(Media::Clip::Notification notification); void clipCallback(Media::Clip::Notification notification);
virtual ~HistoryItem(); ~HistoryItem();
protected: protected:
HistoryItem(History *history, MsgId msgId, MTPDmessage::Flags flags, QDateTime msgDate, int32 from); HistoryItem(History *history, MsgId msgId, MTPDmessage::Flags flags, QDateTime msgDate, int32 from);
@ -898,6 +899,12 @@ protected:
void recountAttachToPrevious(); void recountAttachToPrevious();
const HistoryMessageReplyMarkup *inlineReplyMarkup() const { const HistoryMessageReplyMarkup *inlineReplyMarkup() const {
return const_cast<HistoryItem*>(this)->inlineReplyMarkup();
}
const ReplyKeyboard *inlineReplyKeyboard() const {
return const_cast<HistoryItem*>(this)->inlineReplyKeyboard();
}
HistoryMessageReplyMarkup *inlineReplyMarkup() {
if (auto markup = Get<HistoryMessageReplyMarkup>()) { if (auto markup = Get<HistoryMessageReplyMarkup>()) {
if (markup->flags & MTPDreplyKeyboardMarkup_ClientFlag::f_inline) { if (markup->flags & MTPDreplyKeyboardMarkup_ClientFlag::f_inline) {
return markup; return markup;
@ -905,18 +912,12 @@ protected:
} }
return nullptr; return nullptr;
} }
const ReplyKeyboard *inlineReplyKeyboard() const { ReplyKeyboard *inlineReplyKeyboard() {
if (auto markup = inlineReplyMarkup()) { if (auto markup = inlineReplyMarkup()) {
return markup->inlineKeyboard.get(); return markup->inlineKeyboard.get();
} }
return nullptr; return nullptr;
} }
HistoryMessageReplyMarkup *inlineReplyMarkup() {
return const_cast<HistoryMessageReplyMarkup*>(static_cast<const HistoryItem*>(this)->inlineReplyMarkup());
}
ReplyKeyboard *inlineReplyKeyboard() {
return const_cast<ReplyKeyboard*>(static_cast<const HistoryItem*>(this)->inlineReplyKeyboard());
}
TextSelection toMediaSelection(TextSelection selection) const { TextSelection toMediaSelection(TextSelection selection) const {
return internal::unshiftSelection(selection, _text); return internal::unshiftSelection(selection, _text);

View file

@ -232,7 +232,7 @@ void HistoryFileMedia::checkAnimationFinished() {
} }
HistoryFileMedia::~HistoryFileMedia() { HistoryFileMedia::~HistoryFileMedia() {
deleteAndMark(_animation); delete base::take(_animation);
} }
HistoryPhoto::HistoryPhoto(HistoryItem *parent, PhotoData *photo, const QString &caption) : HistoryFileMedia(parent) HistoryPhoto::HistoryPhoto(HistoryItem *parent, PhotoData *photo, const QString &caption) : HistoryFileMedia(parent)
@ -2562,7 +2562,7 @@ int HistoryWebPage::resizeGetHeight(int width) {
return _height; return _height;
} }
_width = width = qMin(width, _maxw); _width = width/* = qMin(width, _maxw)*/;
width -= st::msgPadding.left() + st::webPageLeft + st::msgPadding.right(); width -= st::msgPadding.left() + st::webPageLeft + st::msgPadding.right();
int32 linesMax = 5; int32 linesMax = 5;
@ -2686,9 +2686,9 @@ void HistoryWebPage::draw(Painter &p, const QRect &r, TextSelection selection, u
} else { } else {
pix = _data->photo->thumb->pixBlurredSingle(ImageRoundRadius::Small, pixw, pixh, pw, ph); pix = _data->photo->thumb->pixBlurredSingle(ImageRoundRadius::Small, pixw, pixh, pw, ph);
} }
p.drawPixmapLeft(padding.left() + width - pw, 0, _width, pix); p.drawPixmapLeft(padding.left() + width - pw, tshift, _width, pix);
if (selected) { if (selected) {
App::roundRect(p, rtlrect(padding.left() + width - pw, 0, pw, _pixh, _width), textstyleCurrent()->selectOverlay, SelectedOverlaySmallCorners); App::roundRect(p, rtlrect(padding.left() + width - pw, tshift, pw, _pixh, _width), textstyleCurrent()->selectOverlay, SelectedOverlaySmallCorners);
} }
width -= pw + st::webPagePhotoDelta; width -= pw + st::webPagePhotoDelta;
} }

View file

@ -309,7 +309,7 @@ struct HistoryDocumentVoice : public RuntimeComponent<HistoryDocumentVoice> {
return *this; return *this;
} }
~HistoryDocumentVoice() { ~HistoryDocumentVoice() {
deleteAndMark(_playback); delete base::take(_playback);
} }
void ensurePlayback(const HistoryDocument *interfaces) const; void ensurePlayback(const HistoryDocument *interfaces) const;
void checkPlaybackFinished() const; void checkPlaybackFinished() const;

View file

@ -366,7 +366,7 @@ HistoryMessage::HistoryMessage(History *history, const MTPDmessage &msg)
CreateConfig config; CreateConfig config;
if (msg.has_fwd_from() && msg.vfwd_from.type() == mtpc_messageFwdHeader) { if (msg.has_fwd_from() && msg.vfwd_from.type() == mtpc_messageFwdHeader) {
const auto &f(msg.vfwd_from.c_messageFwdHeader()); auto &f = msg.vfwd_from.c_messageFwdHeader();
if (f.has_from_id() || f.has_channel_id()) { if (f.has_from_id() || f.has_channel_id()) {
config.authorIdOriginal = f.has_channel_id() ? peerFromChannel(f.vchannel_id) : peerFromUser(f.vfrom_id); config.authorIdOriginal = f.has_channel_id() ? peerFromChannel(f.vchannel_id) : peerFromUser(f.vfrom_id);
config.fromIdOriginal = f.has_from_id() ? peerFromUser(f.vfrom_id) : peerFromChannel(f.vchannel_id); config.fromIdOriginal = f.has_from_id() ? peerFromUser(f.vfrom_id) : peerFromChannel(f.vchannel_id);
@ -376,7 +376,7 @@ HistoryMessage::HistoryMessage(History *history, const MTPDmessage &msg)
if (msg.has_reply_to_msg_id()) config.replyTo = msg.vreply_to_msg_id.v; if (msg.has_reply_to_msg_id()) config.replyTo = msg.vreply_to_msg_id.v;
if (msg.has_via_bot_id()) config.viaBotId = msg.vvia_bot_id.v; if (msg.has_via_bot_id()) config.viaBotId = msg.vvia_bot_id.v;
if (msg.has_views()) config.viewsCount = msg.vviews.v; if (msg.has_views()) config.viewsCount = msg.vviews.v;
if (msg.has_reply_markup()) config.markup = &msg.vreply_markup; if (msg.has_reply_markup()) config.mtpMarkup = &msg.vreply_markup;
if (msg.has_edit_date()) config.editDate = ::date(msg.vedit_date); if (msg.has_edit_date()) config.editDate = ::date(msg.vedit_date);
createComponents(config); createComponents(config);
@ -435,9 +435,15 @@ HistoryMessage::HistoryMessage(History *history, MsgId id, MTPDmessage::Flags fl
config.viewsCount = 1; config.viewsCount = 1;
} }
// Copy inline keyboard when forwarding messages with a game.
auto mediaOriginal = fwd->getMedia();
if (mediaOriginal && mediaOriginal->type() == MediaTypeGame) {
config.inlineMarkup = fwd->inlineReplyMarkup();
}
createComponents(config); createComponents(config);
if (HistoryMedia *mediaOriginal = fwd->getMedia()) { if (mediaOriginal) {
_media.reset(mediaOriginal->clone(this)); _media.reset(mediaOriginal->clone(this));
} }
setText(fwd->originalText()); setText(fwd->originalText());
@ -479,7 +485,7 @@ void HistoryMessage::createComponentsHelper(MTPDmessage::Flags flags, MsgId repl
if (flags & MTPDmessage::Flag::f_via_bot_id) config.viaBotId = viaBotId; if (flags & MTPDmessage::Flag::f_via_bot_id) config.viaBotId = viaBotId;
if (flags & MTPDmessage::Flag::f_reply_to_msg_id) config.replyTo = replyTo; if (flags & MTPDmessage::Flag::f_reply_to_msg_id) config.replyTo = replyTo;
if (flags & MTPDmessage::Flag::f_reply_markup) config.markup = &markup; if (flags & MTPDmessage::Flag::f_reply_markup) config.mtpMarkup = &markup;
if (isPost()) config.viewsCount = 1; if (isPost()) config.viewsCount = 1;
createComponents(config); createComponents(config);
@ -518,8 +524,10 @@ void HistoryMessage::updateMediaInBubbleState() {
_media->setInBubbleState(computeState()); _media->setInBubbleState(computeState());
} }
bool HistoryMessage::displayEditedBadge(bool hasViaBot) const { bool HistoryMessage::displayEditedBadge(bool hasViaBotOrInlineMarkup) const {
if (!(_flags & MTPDmessage::Flag::f_edit_date)) { if (hasViaBotOrInlineMarkup) {
return false;
} else if (!(_flags & MTPDmessage::Flag::f_edit_date)) {
return false; return false;
} }
if (auto fromUser = from()->asUser()) { if (auto fromUser = from()->asUser()) {
@ -527,9 +535,6 @@ bool HistoryMessage::displayEditedBadge(bool hasViaBot) const {
return false; return false;
} }
} }
if (hasViaBot) {
return false;
}
return true; return true;
} }
@ -548,20 +553,31 @@ void HistoryMessage::createComponents(const CreateConfig &config) {
if (isPost() && _from->isUser()) { if (isPost() && _from->isUser()) {
mask |= HistoryMessageSigned::Bit(); mask |= HistoryMessageSigned::Bit();
} }
if (displayEditedBadge(config.viaBotId != 0)) { auto hasViaBot = (config.viaBotId != 0);
auto hasInlineMarkup = [&config] {
if (config.mtpMarkup) {
return (config.mtpMarkup->type() == mtpc_replyInlineMarkup);
}
return (config.inlineMarkup != nullptr);
};
if (displayEditedBadge(hasViaBot || hasInlineMarkup())) {
mask |= HistoryMessageEdited::Bit(); mask |= HistoryMessageEdited::Bit();
} }
if (config.authorIdOriginal && config.fromIdOriginal) { if (config.authorIdOriginal && config.fromIdOriginal) {
mask |= HistoryMessageForwarded::Bit(); mask |= HistoryMessageForwarded::Bit();
} }
if (config.markup) { if (config.mtpMarkup) {
// optimization: don't create markup component for the case // optimization: don't create markup component for the case
// MTPDreplyKeyboardHide with flags = 0, assume it has f_zero flag // MTPDreplyKeyboardHide with flags = 0, assume it has f_zero flag
if (config.markup->type() != mtpc_replyKeyboardHide || config.markup->c_replyKeyboardHide().vflags.v != 0) { if (config.mtpMarkup->type() != mtpc_replyKeyboardHide || config.mtpMarkup->c_replyKeyboardHide().vflags.v != 0) {
mask |= HistoryMessageReplyMarkup::Bit(); mask |= HistoryMessageReplyMarkup::Bit();
} }
} else if (config.inlineMarkup) {
mask |= HistoryMessageReplyMarkup::Bit();
} }
UpdateComponents(mask); UpdateComponents(mask);
if (auto reply = Get<HistoryMessageReply>()) { if (auto reply = Get<HistoryMessageReply>()) {
reply->replyToMsgId = config.replyTo; reply->replyToMsgId = config.replyTo;
if (!reply->updateData(this) && App::api()) { if (!reply->updateData(this) && App::api()) {
@ -586,7 +602,11 @@ void HistoryMessage::createComponents(const CreateConfig &config) {
fwd->_originalId = config.originalId; fwd->_originalId = config.originalId;
} }
if (auto markup = Get<HistoryMessageReplyMarkup>()) { if (auto markup = Get<HistoryMessageReplyMarkup>()) {
markup->create(*config.markup); if (config.mtpMarkup) {
markup->create(*config.mtpMarkup);
} else if (config.inlineMarkup) {
markup->create(*config.inlineMarkup);
}
if (markup->flags & MTPDreplyKeyboardMarkup_ClientFlag::f_has_switch_inline_button) { if (markup->flags & MTPDreplyKeyboardMarkup_ClientFlag::f_has_switch_inline_button) {
_flags |= MTPDmessage_ClientFlag::f_has_switch_inline_button; _flags |= MTPDmessage_ClientFlag::f_has_switch_inline_button;
} }
@ -829,7 +849,9 @@ void HistoryMessage::applyEdition(const MTPDmessage &message) {
if (message.has_edit_date()) { if (message.has_edit_date()) {
_flags |= MTPDmessage::Flag::f_edit_date; _flags |= MTPDmessage::Flag::f_edit_date;
if (displayEditedBadge(Has<HistoryMessageVia>())) { auto hasViaBotId = Has<HistoryMessageVia>();
auto hasInlineMarkup = (inlineReplyMarkup() != nullptr);
if (displayEditedBadge(hasViaBotId || hasInlineMarkup)) {
if (!Has<HistoryMessageEdited>()) { if (!Has<HistoryMessageEdited>()) {
AddComponents(HistoryMessageEdited::Bit()); AddComponents(HistoryMessageEdited::Bit());
} }
@ -1808,7 +1830,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
case mtpc_messageActionChannelCreate: { case mtpc_messageActionChannelCreate: {
auto &d = action.c_messageActionChannelCreate(); auto &d = action.c_messageActionChannelCreate();
if (isPost()) { if (isPost()) {
text = lng_action_created_channel(lt_title, textClean(qs(d.vtitle))); text = lang(lng_action_created_channel);
} else { } else {
text = lng_action_created_chat(lt_from, from, lt_title, textClean(qs(d.vtitle))); text = lng_action_created_chat(lt_from, from, lt_title, textClean(qs(d.vtitle)));
} }
@ -2009,12 +2031,21 @@ bool HistoryService::prepareGameScoreText(const QString &from, QString *outText,
gameTitle = lang(lng_contacts_loading); gameTitle = lang(lng_contacts_loading);
result = true; result = true;
} else { } else {
gameTitle = lang(lng_deleted_message); gameTitle = QString();
} }
auto scoreNumber = gamescore ? gamescore->score : 0;
if (_from->isSelf()) { if (_from->isSelf()) {
*outText = lng_action_game_you_scored(lt_count, gamescore->score, lt_game, gameTitle); if (gameTitle.isEmpty()) {
*outText = lng_action_game_you_scored_no_game(lt_count, scoreNumber);
} else {
*outText = lng_action_game_you_scored(lt_count, scoreNumber, lt_game, gameTitle);
}
} else { } else {
*outText = lng_action_game_score(lt_from, from, lt_count, gamescore->score, lt_game, gameTitle); if (gameTitle.isEmpty()) {
*outText = lng_action_game_score_no_game(lt_from, from, lt_count, scoreNumber);
} else {
*outText = lng_action_game_score(lt_from, from, lt_count, scoreNumber, lt_game, gameTitle);
}
} }
if (second) { if (second) {
outLinks->push_back(second); outLinks->push_back(second);
@ -2212,12 +2243,13 @@ HistoryTextState HistoryService::getState(int x, int y, HistoryStateRequest requ
} }
void HistoryService::createFromMtp(const MTPDmessageService &message) { void HistoryService::createFromMtp(const MTPDmessageService &message) {
if (message.vaction.type() == mtpc_messageActionGameScore) {
UpdateComponents(HistoryServiceGameScore::Bit());
Get<HistoryServiceGameScore>()->score = message.vaction.c_messageActionGameScore().vscore.v;
}
if (message.has_reply_to_msg_id()) { if (message.has_reply_to_msg_id()) {
if (message.vaction.type() == mtpc_messageActionPinMessage) { if (message.vaction.type() == mtpc_messageActionPinMessage) {
UpdateComponents(HistoryServicePinned::Bit()); UpdateComponents(HistoryServicePinned::Bit());
} else if (message.vaction.type() == mtpc_messageActionGameScore) {
UpdateComponents(HistoryServiceGameScore::Bit());
Get<HistoryServiceGameScore>()->score = message.vaction.c_messageActionGameScore().vscore.v;
} }
if (auto dependent = GetDependentData()) { if (auto dependent = GetDependentData()) {
dependent->msgId = message.vreply_to_msg_id.v; dependent->msgId = message.vreply_to_msg_id.v;

View file

@ -63,7 +63,7 @@ public:
return (!emptyText() || !_media || !_media->isDisplayed() || Has<HistoryMessageReply>() || Has<HistoryMessageForwarded>() || viaBot() || !_media->hideFromName()); return (!emptyText() || !_media || !_media->isDisplayed() || Has<HistoryMessageReply>() || Has<HistoryMessageForwarded>() || viaBot() || !_media->hideFromName());
} }
bool displayEditedBadge(bool hasViaBot) const; bool displayEditedBadge(bool hasViaBotOrInlineMarkup) const;
bool uploading() const { bool uploading() const {
return _media && _media->uploading(); return _media && _media->uploading();
} }
@ -191,7 +191,12 @@ private:
PeerId fromIdOriginal = 0; PeerId fromIdOriginal = 0;
MsgId originalId = 0; MsgId originalId = 0;
QDateTime editDate; QDateTime editDate;
const MTPReplyMarkup *markup = nullptr;
// For messages created from MTP structs.
const MTPReplyMarkup *mtpMarkup = nullptr;
// For messages created from existing messages (forwarded).
const HistoryMessageReplyMarkup *inlineMarkup = nullptr;
}; };
void createComponentsHelper(MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, const MTPReplyMarkup &markup); void createComponentsHelper(MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, const MTPReplyMarkup &markup);
void createComponents(const CreateConfig &config); void createComponents(const CreateConfig &config);

View file

@ -2638,85 +2638,53 @@ void BotKeyboard::updateSelected() {
} }
HistoryHider::HistoryHider(MainWidget *parent, bool forwardSelected) : TWidget(parent) HistoryHider::HistoryHider(MainWidget *parent, bool forwardSelected) : TWidget(parent)
, _sharedContact(0)
, _forwardSelected(forwardSelected) , _forwardSelected(forwardSelected)
, _sendPath(false)
, _send(this, lang(lng_forward_send), st::defaultBoxButton) , _send(this, lang(lng_forward_send), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton) , _cancel(this, lang(lng_cancel), st::cancelBoxButton)
, offered(0)
, a_opacity(0, 1) , a_opacity(0, 1)
, _a_appearance(animation(this, &HistoryHider::step_appearance)) , _a_appearance(animation(this, &HistoryHider::step_appearance))
, hiding(false) , _shadow(st::boxShadow) {
, _forwardRequest(0)
, toTextWidth(0)
, shadow(st::boxShadow) {
init(); init();
} }
HistoryHider::HistoryHider(MainWidget *parent, UserData *sharedContact) : TWidget(parent) HistoryHider::HistoryHider(MainWidget *parent, UserData *sharedContact) : TWidget(parent)
, _sharedContact(sharedContact) , _sharedContact(sharedContact)
, _forwardSelected(false)
, _sendPath(false)
, _send(this, lang(lng_forward_send), st::defaultBoxButton) , _send(this, lang(lng_forward_send), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton) , _cancel(this, lang(lng_cancel), st::cancelBoxButton)
, offered(0)
, a_opacity(0, 1) , a_opacity(0, 1)
, _a_appearance(animation(this, &HistoryHider::step_appearance)) , _a_appearance(animation(this, &HistoryHider::step_appearance))
, hiding(false) , _shadow(st::boxShadow) {
, _forwardRequest(0)
, toTextWidth(0)
, shadow(st::boxShadow) {
init(); init();
} }
HistoryHider::HistoryHider(MainWidget *parent) : TWidget(parent) HistoryHider::HistoryHider(MainWidget *parent) : TWidget(parent)
, _sharedContact(0)
, _forwardSelected(false)
, _sendPath(true) , _sendPath(true)
, _send(this, lang(lng_forward_send), st::defaultBoxButton) , _send(this, lang(lng_forward_send), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton) , _cancel(this, lang(lng_cancel), st::cancelBoxButton)
, offered(0)
, a_opacity(0, 1) , a_opacity(0, 1)
, _a_appearance(animation(this, &HistoryHider::step_appearance)) , _a_appearance(animation(this, &HistoryHider::step_appearance))
, hiding(false) , _shadow(st::boxShadow) {
, _forwardRequest(0)
, toTextWidth(0)
, shadow(st::boxShadow) {
init(); init();
} }
HistoryHider::HistoryHider(MainWidget *parent, const QString &botAndQuery) : TWidget(parent) HistoryHider::HistoryHider(MainWidget *parent, const QString &botAndQuery) : TWidget(parent)
, _sharedContact(0)
, _forwardSelected(false)
, _sendPath(false)
, _botAndQuery(botAndQuery) , _botAndQuery(botAndQuery)
, _send(this, lang(lng_forward_send), st::defaultBoxButton) , _send(this, lang(lng_forward_send), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton) , _cancel(this, lang(lng_cancel), st::cancelBoxButton)
, offered(0)
, a_opacity(0, 1) , a_opacity(0, 1)
, _a_appearance(animation(this, &HistoryHider::step_appearance)) , _a_appearance(animation(this, &HistoryHider::step_appearance))
, hiding(false) , _shadow(st::boxShadow) {
, _forwardRequest(0)
, toTextWidth(0)
, shadow(st::boxShadow) {
init(); init();
} }
HistoryHider::HistoryHider(MainWidget *parent, const QString &url, const QString &text) : TWidget(parent) HistoryHider::HistoryHider(MainWidget *parent, const QString &url, const QString &text) : TWidget(parent)
, _sharedContact(0)
, _forwardSelected(false)
, _sendPath(false)
, _shareUrl(url) , _shareUrl(url)
, _shareText(text) , _shareText(text)
, _send(this, lang(lng_forward_send), st::defaultBoxButton) , _send(this, lang(lng_forward_send), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton) , _cancel(this, lang(lng_cancel), st::cancelBoxButton)
, offered(0)
, a_opacity(0, 1) , a_opacity(0, 1)
, _a_appearance(animation(this, &HistoryHider::step_appearance)) , _a_appearance(animation(this, &HistoryHider::step_appearance))
, hiding(false) , _shadow(st::boxShadow) {
, _forwardRequest(0)
, toTextWidth(0)
, shadow(st::boxShadow) {
init(); init();
} }
@ -2736,7 +2704,7 @@ void HistoryHider::step_appearance(float64 ms, bool timer) {
if (dt >= 1) { if (dt >= 1) {
_a_appearance.stop(); _a_appearance.stop();
a_opacity.finish(); a_opacity.finish();
if (hiding) { if (_hiding) {
QTimer::singleShot(0, this, SLOT(deleteLater())); QTimer::singleShot(0, this, SLOT(deleteLater()));
} }
} else { } else {
@ -2752,45 +2720,45 @@ bool HistoryHider::withConfirm() const {
void HistoryHider::paintEvent(QPaintEvent *e) { void HistoryHider::paintEvent(QPaintEvent *e) {
Painter p(this); Painter p(this);
if (!hiding || !cacheForAnim.isNull() || !offered) { if (!_hiding || !_cacheForAnim.isNull() || !_offered) {
p.setOpacity(a_opacity.current() * st::layerAlpha); p.setOpacity(a_opacity.current() * st::layerAlpha);
p.fillRect(rect(), st::layerBg->b); p.fillRect(rect(), st::layerBg->b);
p.setOpacity(a_opacity.current()); p.setOpacity(a_opacity.current());
} }
if (cacheForAnim.isNull() || !offered) { if (_cacheForAnim.isNull() || !_offered) {
p.setFont(st::forwardFont->f); p.setFont(st::forwardFont);
if (offered) { if (_offered) {
shadow.paint(p, box, st::boxShadowShift); _shadow.paint(p, _box, st::boxShadowShift);
// fill bg // fill bg
p.fillRect(box, st::boxBg->b); p.fillRect(_box, st::boxBg);
p.setPen(st::black->p); p.setPen(st::black);
toText.drawElided(p, box.left() + st::boxPadding.left(), box.top() + st::boxPadding.top(), toTextWidth + 2); _toText.drawElided(p, _box.left() + st::boxPadding.left(), _box.top() + st::boxPadding.top(), _toTextWidth + 2);
} else { } else {
int32 w = st::forwardMargins.left() + _chooseWidth + st::forwardMargins.right(), h = st::forwardMargins.top() + st::forwardFont->height + st::forwardMargins.bottom(); int32 w = st::forwardMargins.left() + _chooseWidth + st::forwardMargins.right(), h = st::forwardMargins.top() + st::forwardFont->height + st::forwardMargins.bottom();
App::roundRect(p, (width() - w) / 2, (height() - st::titleHeight - h) / 2, w, h, st::forwardBg, ForwardCorners); App::roundRect(p, (width() - w) / 2, (height() - st::titleHeight - h) / 2, w, h, st::forwardBg, ForwardCorners);
p.setPen(st::white->p); p.setPen(st::white);
p.drawText(box, lang(_botAndQuery.isEmpty() ? lng_forward_choose : lng_inline_switch_choose), QTextOption(style::al_center)); p.drawText(_box, lang(_botAndQuery.isEmpty() ? lng_forward_choose : lng_inline_switch_choose), QTextOption(style::al_center));
} }
} else { } else {
p.drawPixmap(box.left(), box.top(), cacheForAnim); p.drawPixmap(_box.left(), _box.top(), _cacheForAnim);
} }
} }
void HistoryHider::keyPressEvent(QKeyEvent *e) { void HistoryHider::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Escape) { if (e->key() == Qt::Key_Escape) {
if (offered) { if (_offered) {
offered = 0; _offered = nullptr;
resizeEvent(0); resizeEvent(nullptr);
update(); update();
App::main()->dialogsActivate(); App::main()->dialogsActivate();
} else { } else {
startHide(); startHide();
} }
} else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { } else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
if (offered) { if (_offered) {
forward(); forward();
} }
} }
@ -2798,19 +2766,19 @@ void HistoryHider::keyPressEvent(QKeyEvent *e) {
void HistoryHider::mousePressEvent(QMouseEvent *e) { void HistoryHider::mousePressEvent(QMouseEvent *e) {
if (e->button() == Qt::LeftButton) { if (e->button() == Qt::LeftButton) {
if (!box.contains(e->pos())) { if (!_box.contains(e->pos())) {
startHide(); startHide();
} }
} }
} }
void HistoryHider::startHide() { void HistoryHider::startHide() {
if (hiding) return; if (_hiding) return;
hiding = true; _hiding = true;
if (Adaptive::OneColumn()) { if (Adaptive::OneColumn()) {
QTimer::singleShot(0, this, SLOT(deleteLater())); QTimer::singleShot(0, this, SLOT(deleteLater()));
} else { } else {
if (offered) cacheForAnim = myGrab(this, box); if (_offered) _cacheForAnim = myGrab(this, _box);
if (_forwardRequest) MTP::cancel(_forwardRequest); if (_forwardRequest) MTP::cancel(_forwardRequest);
a_opacity.start(0); a_opacity.start(0);
_send.hide(); _send.hide();
@ -2820,17 +2788,17 @@ void HistoryHider::startHide() {
} }
void HistoryHider::forward() { void HistoryHider::forward() {
if (!hiding && offered) { if (!_hiding && _offered) {
if (_sharedContact) { if (_sharedContact) {
parent()->onShareContact(offered->id, _sharedContact); parent()->onShareContact(_offered->id, _sharedContact);
} else if (_sendPath) { } else if (_sendPath) {
parent()->onSendPaths(offered->id); parent()->onSendPaths(_offered->id);
} else if (!_shareUrl.isEmpty()) { } else if (!_shareUrl.isEmpty()) {
parent()->onShareUrl(offered->id, _shareUrl, _shareText); parent()->onShareUrl(_offered->id, _shareUrl, _shareText);
} else if (!_botAndQuery.isEmpty()) { } else if (!_botAndQuery.isEmpty()) {
parent()->onInlineSwitchChosen(offered->id, _botAndQuery); parent()->onInlineSwitchChosen(_offered->id, _botAndQuery);
} else { } else {
parent()->onForward(offered->id, _forwardSelected ? ForwardSelectedMessages : ForwardContextMessage); parent()->onForward(_offered->id, _forwardSelected ? ForwardSelectedMessages : ForwardContextMessage);
} }
} }
emit forwarded(); emit forwarded();
@ -2847,8 +2815,8 @@ MainWidget *HistoryHider::parent() {
void HistoryHider::resizeEvent(QResizeEvent *e) { void HistoryHider::resizeEvent(QResizeEvent *e) {
int32 w = st::boxWidth, h = st::boxPadding.top() + st::boxPadding.bottom(); int32 w = st::boxWidth, h = st::boxPadding.top() + st::boxPadding.bottom();
if (offered) { if (_offered) {
if (!hiding) { if (!_hiding) {
_send.show(); _send.show();
_cancel.show(); _cancel.show();
} }
@ -2858,22 +2826,22 @@ void HistoryHider::resizeEvent(QResizeEvent *e) {
_send.hide(); _send.hide();
_cancel.hide(); _cancel.hide();
} }
box = QRect((width() - w) / 2, (height() - st::titleHeight - h) / 2, w, h); _box = QRect((width() - w) / 2, (height() - st::titleHeight - h) / 2, w, h);
_send.moveToRight(width() - (box.x() + box.width()) + st::boxButtonPadding.right(), box.y() + h - st::boxButtonPadding.bottom() - _send.height()); _send.moveToRight(width() - (_box.x() + _box.width()) + st::boxButtonPadding.right(), _box.y() + h - st::boxButtonPadding.bottom() - _send.height());
_cancel.moveToRight(width() - (box.x() + box.width()) + st::boxButtonPadding.right() + _send.width() + st::boxButtonPadding.left(), _send.y()); _cancel.moveToRight(width() - (_box.x() + _box.width()) + st::boxButtonPadding.right() + _send.width() + st::boxButtonPadding.left(), _send.y());
} }
bool HistoryHider::offerPeer(PeerId peer) { bool HistoryHider::offerPeer(PeerId peer) {
if (!peer) { if (!peer) {
offered = 0; _offered = nullptr;
toText.setText(st::boxTextFont, QString()); _toText.setText(st::boxTextFont, QString());
toTextWidth = 0; _toTextWidth = 0;
resizeEvent(0); resizeEvent(nullptr);
return false; return false;
} }
offered = App::peer(peer); _offered = App::peer(peer);
LangString phrase; LangString phrase;
QString recipient = offered->isUser() ? offered->name : '\xAB' + offered->name + '\xBB'; QString recipient = _offered->isUser() ? _offered->name : '\xAB' + _offered->name + '\xBB';
if (_sharedContact) { if (_sharedContact) {
phrase = lng_forward_share_contact(lt_recipient, recipient); phrase = lng_forward_share_contact(lt_recipient, recipient);
} else if (_sendPath) { } else if (_sendPath) {
@ -2887,35 +2855,35 @@ bool HistoryHider::offerPeer(PeerId peer) {
phrase = lng_forward_send_file_confirm(lt_name, name, lt_recipient, recipient); phrase = lng_forward_send_file_confirm(lt_name, name, lt_recipient, recipient);
} }
} else if (!_shareUrl.isEmpty()) { } else if (!_shareUrl.isEmpty()) {
PeerId to = offered->id; PeerId to = _offered->id;
offered = 0; _offered = nullptr;
if (parent()->onShareUrl(to, _shareUrl, _shareText)) { if (parent()->onShareUrl(to, _shareUrl, _shareText)) {
startHide(); startHide();
} }
return false; return false;
} else if (!_botAndQuery.isEmpty()) { } else if (!_botAndQuery.isEmpty()) {
PeerId to = offered->id; PeerId to = _offered->id;
offered = 0; _offered = nullptr;
if (parent()->onInlineSwitchChosen(to, _botAndQuery)) { if (parent()->onInlineSwitchChosen(to, _botAndQuery)) {
startHide(); startHide();
} }
return false; return false;
} else { } else {
PeerId to = offered->id; PeerId to = _offered->id;
offered = 0; _offered = nullptr;
if (parent()->onForward(to, _forwardSelected ? ForwardSelectedMessages : ForwardContextMessage)) { if (parent()->onForward(to, _forwardSelected ? ForwardSelectedMessages : ForwardContextMessage)) {
startHide(); startHide();
} }
return false; return false;
} }
toText.setText(st::boxTextFont, phrase, _textNameOptions); _toText.setText(st::boxTextFont, phrase, _textNameOptions);
toTextWidth = toText.maxWidth(); _toTextWidth = _toText.maxWidth();
if (toTextWidth > box.width() - st::boxPadding.left() - st::boxButtonPadding.right()) { if (_toTextWidth > _box.width() - st::boxPadding.left() - st::boxButtonPadding.right()) {
toTextWidth = box.width() - st::boxPadding.left() - st::boxButtonPadding.right(); _toTextWidth = _box.width() - st::boxPadding.left() - st::boxButtonPadding.right();
} }
resizeEvent(0); resizeEvent(nullptr);
update(); update();
setFocus(); setFocus();
@ -2923,11 +2891,11 @@ bool HistoryHider::offerPeer(PeerId peer) {
} }
QString HistoryHider::offeredText() const { QString HistoryHider::offeredText() const {
return toText.originalText(); return _toText.originalText();
} }
bool HistoryHider::wasOffered() const { bool HistoryHider::wasOffered() const {
return !!offered; return _offered != nullptr;
} }
HistoryHider::~HistoryHider() { HistoryHider::~HistoryHider() {
@ -3404,7 +3372,7 @@ void HistoryWidget::writeDrafts(Data::Draft **localDraft, Data::Draft **editDraf
} }
} }
if (!_editMsgId) { if (!_editMsgId && !_inlineBot) {
_saveCloudDraftTimer.start(SaveCloudDraftIdleTimeout); _saveCloudDraftTimer.start(SaveCloudDraftIdleTimeout);
} }
} }
@ -6017,7 +5985,6 @@ bool HistoryWidget::hasSilentToggle() const {
void HistoryWidget::inlineBotResolveDone(const MTPcontacts_ResolvedPeer &result) { void HistoryWidget::inlineBotResolveDone(const MTPcontacts_ResolvedPeer &result) {
_inlineBotResolveRequestId = 0; _inlineBotResolveRequestId = 0;
// Notify::inlineBotRequesting(false); // Notify::inlineBotRequesting(false);
_inlineBotUsername = QString();
UserData *resolvedBot = nullptr; UserData *resolvedBot = nullptr;
if (result.type() == mtpc_contacts_resolvedPeer) { if (result.type() == mtpc_contacts_resolvedPeer) {
const auto &d(result.c_contacts_resolvedPeer()); const auto &d(result.c_contacts_resolvedPeer());
@ -8895,6 +8862,6 @@ bool HistoryWidget::touchScroll(const QPoint &delta) {
} }
HistoryWidget::~HistoryWidget() { HistoryWidget::~HistoryWidget() {
deleteAndMark(_pinnedBar); delete base::take(_pinnedBar);
deleteAndMark(_list); delete base::take(_list);
} }

View file

@ -21,10 +21,12 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#pragma once #pragma once
#include "localimageloader.h" #include "localimageloader.h"
#include "ui/boxshadow.h" #include "ui/effects/rect_shadow.h"
#include "ui/popupmenu.h"
#include "history/history_common.h" #include "history/history_common.h"
#include "history/field_autocomplete.h" #include "history/field_autocomplete.h"
#include "window/section_widget.h" #include "window/section_widget.h"
#include "core/single_timer.h"
namespace InlineBots { namespace InlineBots {
namespace Layout { namespace Layout {
@ -479,30 +481,31 @@ private:
void init(); void init();
MainWidget *parent(); MainWidget *parent();
UserData *_sharedContact; UserData *_sharedContact = nullptr;
bool _forwardSelected, _sendPath; bool _forwardSelected = false;
bool _sendPath = false;
QString _shareUrl, _shareText; QString _shareUrl, _shareText;
QString _botAndQuery; QString _botAndQuery;
BoxButton _send, _cancel; BoxButton _send, _cancel;
PeerData *offered; PeerData *_offered = nullptr;
anim::fvalue a_opacity; anim::fvalue a_opacity;
Animation _a_appearance; Animation _a_appearance;
QRect box; QRect _box;
bool hiding; bool _hiding = false;
mtpRequestId _forwardRequest; mtpRequestId _forwardRequest = 0;
int32 _chooseWidth; int _chooseWidth = 0;
Text toText; Text _toText;
int32 toTextWidth; int32 _toTextWidth = 0;
QPixmap cacheForAnim; QPixmap _cacheForAnim;
BoxShadow shadow; Ui::RectShadow _shadow;
}; };

View file

@ -29,7 +29,7 @@ constexpr const str_const LanguageCodes[] = {
"pt_BR", "pt_BR",
"ko", "ko",
}; };
constexpr const int languageTest = -1, languageDefault = 0, languageCount = arraysize(LanguageCodes); constexpr const int languageTest = -1, languageDefault = 0, languageCount = base::array_size(LanguageCodes);
class LangString : public QString { class LangString : public QString {
public: public:

View file

@ -83,7 +83,7 @@ private:
QRect _box, _hiddenSpecialBox; QRect _box, _hiddenSpecialBox;
float64 _opacity = 0.; float64 _opacity = 0.;
BoxShadow _shadow; Ui::RectShadow _shadow;
}; };

View file

@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#include "ui/boxshadow.h" #include "ui/effects/rect_shadow.h"
class LayerWidget : public TWidget { class LayerWidget : public TWidget {
Q_OBJECT Q_OBJECT

View file

@ -32,6 +32,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "mainwindow.h" #include "mainwindow.h"
#include "lang.h" #include "lang.h"
#include "media/media_audio.h" #include "media/media_audio.h"
#include "application.h"
#include "apiwrap.h" #include "apiwrap.h"
namespace Local { namespace Local {
@ -534,7 +535,7 @@ enum {
dbiDcOption = 0x27, dbiDcOption = 0x27,
dbiTryIPv6 = 0x28, dbiTryIPv6 = 0x28,
dbiSongVolume = 0x29, dbiSongVolume = 0x29,
dbiWindowsNotifications = 0x30, dbiWindowsNotificationsOld = 0x30,
dbiIncludeMuted = 0x31, dbiIncludeMuted = 0x31,
dbiMegagroupSizeMax = 0x32, dbiMegagroupSizeMax = 0x32,
dbiDownloadPath = 0x33, dbiDownloadPath = 0x33,
@ -548,6 +549,9 @@ enum {
dbiModerateMode = 0x41, dbiModerateMode = 0x41,
dbiVideoVolume = 0x42, dbiVideoVolume = 0x42,
dbiStickersRecentLimit = 0x43, dbiStickersRecentLimit = 0x43,
dbiNativeNotifications = 0x44,
dbiNotificationsCount = 0x45,
dbiNotificationsCorner = 0x46,
dbiEncryptedWithSalt = 333, dbiEncryptedWithSalt = 333,
dbiEncrypted = 444, dbiEncrypted = 444,
@ -989,15 +993,34 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version) {
if (App::wnd()) App::wnd()->updateTrayMenu(); if (App::wnd()) App::wnd()->updateTrayMenu();
} break; } break;
case dbiWindowsNotifications: { case dbiWindowsNotificationsOld: {
qint32 v;
stream >> v;
if (!_checkStreamStatus(stream)) return false;
} break;
case dbiNativeNotifications: {
qint32 v; qint32 v;
stream >> v; stream >> v;
if (!_checkStreamStatus(stream)) return false; if (!_checkStreamStatus(stream)) return false;
Global::SetWindowsNotifications(v == 1); Global::SetNativeNotifications(v == 1);
if (cPlatform() == dbipWindows) { } break;
Global::SetCustomNotifies((App::wnd() ? !App::wnd()->psHasNativeNotifications() : true) || !Global::WindowsNotifications());
} case dbiNotificationsCount: {
qint32 v;
stream >> v;
if (!_checkStreamStatus(stream)) return false;
Global::SetNotificationsCount((v > 0 ? v : 3));
} break;
case dbiNotificationsCorner: {
qint32 v;
stream >> v;
if (!_checkStreamStatus(stream)) return false;
Global::SetNotificationsCorner(static_cast<Notify::ScreenCorner>((v >= 0 && v < 4) ? v : 2));
} break; } break;
case dbiWorkMode: { case dbiWorkMode: {
@ -1056,6 +1079,9 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version) {
if (!_checkStreamStatus(stream)) return false; if (!_checkStreamStatus(stream)) return false;
cSetAutoUpdate(v == 1); cSetAutoUpdate(v == 1);
if (!cAutoUpdate()) {
Sandbox::stopUpdate();
}
} break; } break;
case dbiLastUpdateCheck: { case dbiLastUpdateCheck: {
@ -1568,7 +1594,7 @@ void _writeUserSettings() {
_writeMap(WriteMapFast); _writeMap(WriteMapFast);
} }
uint32 size = 18 * (sizeof(quint32) + sizeof(qint32)); uint32 size = 20 * (sizeof(quint32) + sizeof(qint32));
size += sizeof(quint32) + Serialize::stringSize(Global::AskDownloadPath() ? QString() : Global::DownloadPath()) + Serialize::bytearraySize(Global::AskDownloadPath() ? QByteArray() : Global::DownloadPathBookmark()); size += sizeof(quint32) + Serialize::stringSize(Global::AskDownloadPath() ? QString() : Global::DownloadPath()) + Serialize::bytearraySize(Global::AskDownloadPath() ? QByteArray() : Global::DownloadPathBookmark());
size += sizeof(quint32) + sizeof(qint32) + (cRecentEmojisPreload().isEmpty() ? cGetRecentEmojis().size() : cRecentEmojisPreload().size()) * (sizeof(uint64) + sizeof(ushort)); size += sizeof(quint32) + sizeof(qint32) + (cRecentEmojisPreload().isEmpty() ? cGetRecentEmojis().size() : cRecentEmojisPreload().size()) * (sizeof(uint64) + sizeof(ushort));
size += sizeof(quint32) + sizeof(qint32) + cEmojiVariants().size() * (sizeof(uint32) + sizeof(uint64)); size += sizeof(quint32) + sizeof(qint32) + cEmojiVariants().size() * (sizeof(uint32) + sizeof(uint64));
@ -1592,7 +1618,9 @@ void _writeUserSettings() {
data.stream << quint32(dbiShowingSavedGifs) << qint32(cShowingSavedGifs()); data.stream << quint32(dbiShowingSavedGifs) << qint32(cShowingSavedGifs());
data.stream << quint32(dbiDesktopNotify) << qint32(Global::DesktopNotify()); data.stream << quint32(dbiDesktopNotify) << qint32(Global::DesktopNotify());
data.stream << quint32(dbiNotifyView) << qint32(Global::NotifyView()); data.stream << quint32(dbiNotifyView) << qint32(Global::NotifyView());
data.stream << quint32(dbiWindowsNotifications) << qint32(Global::WindowsNotifications()); data.stream << quint32(dbiNativeNotifications) << qint32(Global::NativeNotifications());
data.stream << quint32(dbiNotificationsCount) << qint32(Global::NotificationsCount());
data.stream << quint32(dbiNotificationsCorner) << qint32(Global::NotificationsCorner());
data.stream << quint32(dbiAskDownloadPath) << qint32(Global::AskDownloadPath()); data.stream << quint32(dbiAskDownloadPath) << qint32(Global::AskDownloadPath());
data.stream << quint32(dbiDownloadPath) << (Global::AskDownloadPath() ? QString() : Global::DownloadPath()) << (Global::AskDownloadPath() ? QByteArray() : Global::DownloadPathBookmark()); data.stream << quint32(dbiDownloadPath) << (Global::AskDownloadPath() ? QString() : Global::DownloadPath()) << (Global::AskDownloadPath() ? QByteArray() : Global::DownloadPathBookmark());
data.stream << quint32(dbiCompressPastedImage) << qint32(cCompressPastedImage()); data.stream << quint32(dbiCompressPastedImage) << qint32(cCompressPastedImage());
@ -2627,7 +2655,7 @@ public:
virtual void readFromStream(QDataStream &stream, quint64 &first, quint64 &second, quint32 &type, QByteArray &data) = 0; virtual void readFromStream(QDataStream &stream, quint64 &first, quint64 &second, quint32 &type, QByteArray &data) = 0;
virtual void clearInMap() = 0; virtual void clearInMap() = 0;
virtual ~AbstractCachedLoadTask() { virtual ~AbstractCachedLoadTask() {
deleteAndMark(_result); delete base::take(_result);
} }
protected: protected:
@ -2903,7 +2931,7 @@ public:
} }
} }
virtual ~WebFileLoadTask() { virtual ~WebFileLoadTask() {
deleteAndMark(_result); delete base::take(_result);
} }
protected: protected:

View file

@ -1015,8 +1015,7 @@ namespace internal {
#if !defined Q_OS_MAC || defined MAC_USE_BREAKPAD #if !defined Q_OS_MAC || defined MAC_USE_BREAKPAD
if (internal::BreakpadExceptionHandler) { if (internal::BreakpadExceptionHandler) {
google_breakpad::ExceptionHandler *h = getPointerAndReset(internal::BreakpadExceptionHandler); delete base::take(internal::BreakpadExceptionHandler);
delete h;
} }
#endif // !Q_OS_MAC || MAC_USE_BREAKPAD #endif // !Q_OS_MAC || MAC_USE_BREAKPAD

View file

@ -3324,10 +3324,7 @@ void MainWidget::start(const MTPUser &user) {
App::feedUsers(MTP_vector<MTPUser>(1, user)); App::feedUsers(MTP_vector<MTPUser>(1, user));
MTP::send(MTPupdates_GetState(), rpcDone(&MainWidget::gotState)); MTP::send(MTPupdates_GetState(), rpcDone(&MainWidget::gotState));
update(); update();
if (!cStartUrl().isEmpty()) {
openLocalUrl(cStartUrl());
cSetStartUrl(QString());
}
_started = true; _started = true;
App::wnd()->sendServiceHistoryRequest(); App::wnd()->sendServiceHistoryRequest();
Local::readInstalledStickers(); Local::readInstalledStickers();
@ -3335,12 +3332,23 @@ void MainWidget::start(const MTPUser &user) {
Local::readRecentStickers(); Local::readRecentStickers();
Local::readSavedGifs(); Local::readSavedGifs();
_history->start(); _history->start();
checkStartUrl();
} }
bool MainWidget::started() { bool MainWidget::started() {
return _started; return _started;
} }
void MainWidget::checkStartUrl() {
if (!cStartUrl().isEmpty() && App::self() && !App::passcoded()) {
auto url = cStartUrl();
cSetStartUrl(QString());
openLocalUrl(url);
}
}
void MainWidget::openLocalUrl(const QString &url) { void MainWidget::openLocalUrl(const QString &url) {
auto urlTrimmed = url.trimmed(); auto urlTrimmed = url.trimmed();
if (urlTrimmed.size() > 8192) urlTrimmed = urlTrimmed.mid(0, 8192); if (urlTrimmed.size() > 8192) urlTrimmed = urlTrimmed.mid(0, 8192);

View file

@ -22,6 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "localimageloader.h" #include "localimageloader.h"
#include "history/history_common.h" #include "history/history_common.h"
#include "core/single_timer.h"
namespace Dialogs { namespace Dialogs {
class Row; class Row;
@ -156,6 +157,7 @@ public:
void start(const MTPUser &user); void start(const MTPUser &user);
void checkStartUrl();
void openLocalUrl(const QString &str); void openLocalUrl(const QString &str);
void openPeerByName(const QString &name, MsgId msgId = ShowAtUnreadMsgId, const QString &startToken = QString()); void openPeerByName(const QString &name, MsgId msgId = ShowAtUnreadMsgId, const QString &startToken = QString());
void joinGroupByHash(const QString &hash); void joinGroupByHash(const QString &hash);

View file

@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "dialogs/dialogs_layout.h" #include "dialogs/dialogs_layout.h"
#include "styles/style_dialogs.h" #include "styles/style_dialogs.h"
#include "ui/popupmenu.h"
#include "zip.h" #include "zip.h"
#include "lang.h" #include "lang.h"
#include "shortcuts.h" #include "shortcuts.h"
@ -42,8 +43,11 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "localstorage.h" #include "localstorage.h"
#include "apiwrap.h" #include "apiwrap.h"
#include "settings/settings_widget.h" #include "settings/settings_widget.h"
#include "window/notifications_manager.h"
ConnectingWidget::ConnectingWidget(QWidget *parent, const QString &text, const QString &reconnect) : QWidget(parent), _shadow(st::boxShadow), _reconnect(this, QString()) { ConnectingWidget::ConnectingWidget(QWidget *parent, const QString &text, const QString &reconnect) : QWidget(parent)
, _shadow(st::boxShadow)
, _reconnect(this, QString()) {
set(text, reconnect); set(text, reconnect);
connect(&_reconnect, SIGNAL(clicked()), this, SLOT(onReconnect())); connect(&_reconnect, SIGNAL(clicked()), this, SLOT(onReconnect()));
} }
@ -57,310 +61,27 @@ void ConnectingWidget::set(const QString &text, const QString &reconnect) {
} else { } else {
_reconnect.setText(reconnect); _reconnect.setText(reconnect);
_reconnect.show(); _reconnect.show();
_reconnect.move(st::connectingPadding.left() + _textWidth, st::boxShadow.pxHeight() + st::connectingPadding.top()); _reconnect.move(st::connectingPadding.left() + _textWidth, st::boxShadow.height() + st::connectingPadding.top());
_reconnectWidth = _reconnect.width(); _reconnectWidth = _reconnect.width();
} }
resize(st::connectingPadding.left() + _textWidth + _reconnectWidth + st::connectingPadding.right() + st::boxShadow.pxWidth(), st::boxShadow.pxHeight() + st::connectingPadding.top() + st::linkFont->height + st::connectingPadding.bottom()); resize(st::connectingPadding.left() + _textWidth + _reconnectWidth + st::connectingPadding.right() + st::boxShadow.width(), st::boxShadow.height() + st::connectingPadding.top() + st::linkFont->height + st::connectingPadding.bottom());
update(); update();
} }
void ConnectingWidget::paintEvent(QPaintEvent *e) { void ConnectingWidget::paintEvent(QPaintEvent *e) {
QPainter p(this); Painter p(this);
_shadow.paint(p, QRect(0, st::boxShadow.pxHeight(), width() - st::boxShadow.pxWidth(), height() - st::boxShadow.pxHeight()), 0, BoxShadow::Top | BoxShadow::Right); _shadow.paint(p, QRect(0, st::boxShadow.height(), width() - st::boxShadow.width(), height() - st::boxShadow.height()), 0, Ui::RectShadow::Side::Top | Ui::RectShadow::Side::Right);
p.fillRect(0, st::boxShadow.pxHeight(), width() - st::boxShadow.pxWidth(), height() - st::boxShadow.pxHeight(), st::connectingBG->b); p.fillRect(0, st::boxShadow.height(), width() - st::boxShadow.width(), height() - st::boxShadow.height(), st::connectingBG->b);
p.setFont(st::linkFont->f); p.setFont(st::linkFont->f);
p.setPen(st::connectingColor->p); p.setPen(st::connectingColor->p);
p.drawText(st::connectingPadding.left(), st::boxShadow.pxHeight() + st::connectingPadding.top() + st::linkFont->ascent, _text); p.drawText(st::connectingPadding.left(), st::boxShadow.height() + st::connectingPadding.top() + st::linkFont->ascent, _text);
} }
void ConnectingWidget::onReconnect() { void ConnectingWidget::onReconnect() {
MTP::restart(); MTP::restart();
} }
NotifyWindow::NotifyWindow(HistoryItem *msg, int32 x, int32 y, int32 fwdCount) : TWidget(0)
, history(msg->history())
, item(msg)
, fwdCount(fwdCount)
#if defined Q_OS_WIN && !defined Q_OS_WINRT
, started(GetTickCount())
#endif // Q_OS_WIN && !Q_OS_WINRT
, close(this, st::notifyClose)
, alphaDuration(st::notifyFastAnim)
, posDuration(st::notifyFastAnim)
, hiding(false)
, _index(0)
, a_opacity(0)
, a_func(anim::linear)
, a_y(y + st::notifyHeight + st::notifyDeltaY)
, _a_appearance(animation(this, &NotifyWindow::step_appearance)) {
updateNotifyDisplay();
hideTimer.setSingleShot(true);
connect(&hideTimer, SIGNAL(timeout()), this, SLOT(hideByTimer()));
inputTimer.setSingleShot(true);
connect(&inputTimer, SIGNAL(timeout()), this, SLOT(checkLastInput()));
connect(&close, SIGNAL(clicked()), this, SLOT(unlinkHistoryAndNotify()));
close.setAcceptBoth(true);
close.move(st::notifyWidth - st::notifyClose.width - st::notifyClosePos.x(), st::notifyClosePos.y());
close.show();
a_y.start(y);
setGeometry(x, a_y.current(), st::notifyWidth, st::notifyHeight);
a_opacity.start(1);
setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint);
setAttribute(Qt::WA_MacAlwaysShowToolWindow);
show();
setWindowOpacity(a_opacity.current());
alphaDuration = posDuration = st::notifyFastAnim;
_a_appearance.start();
checkLastInput();
}
void NotifyWindow::checkLastInput() {
#if defined Q_OS_WIN && !defined Q_OS_WINRT
LASTINPUTINFO lii;
lii.cbSize = sizeof(LASTINPUTINFO);
BOOL res = GetLastInputInfo(&lii);
if (!res || lii.dwTime >= started) {
hideTimer.start(st::notifyWaitLongHide);
} else {
inputTimer.start(300);
}
#else // Q_OS_WIN && !Q_OS_WINRT
// TODO
if (true) {
hideTimer.start(st::notifyWaitLongHide);
} else {
inputTimer.start(300);
}
#endif // else for Q_OS_WIN && !Q_OS_WINRT
}
void NotifyWindow::moveTo(int32 x, int32 y, int32 index) {
if (index >= 0) {
_index = index;
}
move(x, a_y.current());
a_y.start(y);
a_opacity.restart();
posDuration = st::notifyFastAnim;
_a_appearance.start();
}
void NotifyWindow::updateNotifyDisplay() {
if (!item) return;
int32 w = st::notifyWidth, h = st::notifyHeight;
QImage img(w * cIntRetinaFactor(), h * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
if (cRetina()) img.setDevicePixelRatio(cRetinaFactor());
img.fill(st::notifyBG->c);
{
Painter p(&img);
p.fillRect(0, 0, w - st::notifyBorderWidth, st::notifyBorderWidth, st::notifyBorder->b);
p.fillRect(w - st::notifyBorderWidth, 0, st::notifyBorderWidth, h - st::notifyBorderWidth, st::notifyBorder->b);
p.fillRect(st::notifyBorderWidth, h - st::notifyBorderWidth, w - st::notifyBorderWidth, st::notifyBorderWidth, st::notifyBorder->b);
p.fillRect(0, st::notifyBorderWidth, st::notifyBorderWidth, h - st::notifyBorderWidth, st::notifyBorder->b);
if (!App::passcoded() && Global::NotifyView() <= dbinvShowName) {
history->peer->loadUserpic(true, true);
history->peer->paintUserpicLeft(p, st::notifyPhotoSize, st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), width());
} else {
static QPixmap icon = App::pixmapFromImageInPlace(App::wnd()->iconLarge().scaled(st::notifyPhotoSize, st::notifyPhotoSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), icon);
}
int32 itemWidth = w - st::notifyPhotoPos.x() - st::notifyPhotoSize - st::notifyTextLeft - st::notifyClosePos.x() - st::notifyClose.width;
QRect rectForName(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyTextTop, itemWidth, st::msgNameFont->height);
if (!App::passcoded() && Global::NotifyView() <= dbinvShowName) {
if (auto chatTypeIcon = Dialogs::Layout::ChatTypeIcon(history->peer, false)) {
chatTypeIcon->paint(p, rectForName.topLeft(), w);
rectForName.setLeft(rectForName.left() + st::dialogsChatTypeSkip);
}
}
QDateTime now(QDateTime::currentDateTime()), lastTime(item->date);
QDate nowDate(now.date()), lastDate(lastTime.date());
QString dt = lastTime.toString(cTimeFormat());
int32 dtWidth = st::dialogsTextFont->width(dt);
rectForName.setWidth(rectForName.width() - dtWidth - st::dialogsDateSkip);
p.setFont(st::dialogsDateFont);
p.setPen(st::dialogsDateFg);
p.drawText(rectForName.left() + rectForName.width() + st::dialogsDateSkip, rectForName.top() + st::dialogsTextFont->ascent, dt);
if (!App::passcoded() && Global::NotifyView() <= dbinvShowPreview) {
const HistoryItem *textCachedFor = 0;
Text itemTextCache(itemWidth);
QRect r(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyItemTop + st::msgNameFont->height, itemWidth, 2 * st::dialogsTextFont->height);
if (fwdCount < 2) {
bool active = false;
item->drawInDialog(p, r, active, textCachedFor, itemTextCache);
} else {
p.setFont(st::dialogsTextFont);
if (item->hasFromName() && !item->isPost()) {
itemTextCache.setText(st::dialogsTextFont, item->author()->name);
p.setPen(st::dialogsTextFgService);
itemTextCache.drawElided(p, r.left(), r.top(), r.width(), st::dialogsTextFont->height);
r.setTop(r.top() + st::dialogsTextFont->height);
}
p.setPen(st::dialogsTextFg);
p.drawText(r.left(), r.top() + st::dialogsTextFont->ascent, lng_forward_messages(lt_count, fwdCount));
}
} else {
static QString notifyText = st::dialogsTextFont->elided(lang(lng_notification_preview), itemWidth);
p.setPen(st::dialogsTextFgService);
p.drawText(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyItemTop + st::msgNameFont->height + st::dialogsTextFont->ascent, notifyText);
}
p.setPen(st::dialogsNameFg);
if (!App::passcoded() && Global::NotifyView() <= dbinvShowName) {
history->peer->dialogName().drawElided(p, rectForName.left(), rectForName.top(), rectForName.width());
} else {
p.setFont(st::msgNameFont->f);
static QString notifyTitle = st::msgNameFont->elided(qsl("Telegram Desktop"), rectForName.width());
p.drawText(rectForName.left(), rectForName.top() + st::msgNameFont->ascent, notifyTitle);
}
}
pm = App::pixmapFromImageInPlace(std_::move(img));
update();
}
void NotifyWindow::updatePeerPhoto() {
if (!peerPhoto->isNull() && peerPhoto->loaded()) {
QImage img(pm.toImage());
{
QPainter p(&img);
p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), peerPhoto->pix(st::notifyPhotoSize));
}
peerPhoto = ImagePtr();
pm = App::pixmapFromImageInPlace(std_::move(img));
update();
}
}
void NotifyWindow::itemRemoved(HistoryItem *del) {
if (item == del) {
item = 0;
unlinkHistoryAndNotify();
}
}
void NotifyWindow::unlinkHistoryAndNotify() {
unlinkHistory();
App::wnd()->notifyShowNext();
}
void NotifyWindow::unlinkHistory(History *hist) {
if (!hist || hist == history) {
animHide(st::notifyFastAnim, anim::linear);
history = 0;
item = 0;
}
}
void NotifyWindow::enterEvent(QEvent *e) {
if (!history) return;
if (App::wnd()) App::wnd()->notifyStopHiding();
}
void NotifyWindow::leaveEvent(QEvent *e) {
if (!history) return;
App::wnd()->notifyStartHiding();
}
void NotifyWindow::startHiding() {
hideTimer.start(st::notifyWaitShortHide);
}
void NotifyWindow::mousePressEvent(QMouseEvent *e) {
if (!history) return;
PeerId peer = history->peer->id;
MsgId msgId = (!history->peer->isUser() && item && item->mentionsMe() && item->id > 0) ? item->id : ShowAtUnreadMsgId;
if (e->button() == Qt::RightButton) {
unlinkHistoryAndNotify();
} else {
App::wnd()->showFromTray();
if (App::passcoded()) {
App::wnd()->setInnerFocus();
App::wnd()->notifyClear();
} else {
Ui::showPeerHistory(peer, msgId);
}
e->ignore();
}
}
void NotifyWindow::paintEvent(QPaintEvent *e) {
QPainter p(this);
p.drawPixmap(0, 0, pm);
}
void NotifyWindow::animHide(float64 duration, anim::transition func) {
if (!history) return;
alphaDuration = duration;
a_func = func;
a_opacity.start(0);
a_y.restart();
hiding = true;
_a_appearance.start();
}
void NotifyWindow::stopHiding() {
if (!history) return;
alphaDuration = st::notifyFastAnim;
a_func = anim::linear;
a_opacity.start(1);
a_y.restart();
hiding = false;
hideTimer.stop();
_a_appearance.start();
}
void NotifyWindow::hideByTimer() {
if (!history) return;
animHide(st::notifySlowHide, st::notifySlowHideFunc);
}
void NotifyWindow::step_appearance(float64 ms, bool timer) {
float64 dtAlpha = ms / alphaDuration, dtPos = ms / posDuration;
if (dtAlpha >= 1) {
a_opacity.finish();
if (hiding) {
_a_appearance.stop();
deleteLater();
} else if (dtPos >= 1) {
_a_appearance.stop();
}
} else {
a_opacity.update(dtAlpha, a_func);
}
setWindowOpacity(a_opacity.current());
if (dtPos >= 1) {
a_y.finish();
} else {
a_y.update(dtPos, anim::linear);
}
move(x(), a_y.current());
update();
}
NotifyWindow::~NotifyWindow() {
if (App::wnd()) App::wnd()->notifyShowNext(this);
}
MainWindow::MainWindow() { MainWindow::MainWindow() {
icon16 = icon256.scaledToWidth(16, Qt::SmoothTransformation); icon16 = icon256.scaledToWidth(16, Qt::SmoothTransformation);
icon32 = icon256.scaledToWidth(32, Qt::SmoothTransformation); icon32 = icon256.scaledToWidth(32, Qt::SmoothTransformation);
@ -375,8 +96,6 @@ MainWindow::MainWindow() {
notifyClear(); notifyClear();
} else if (type == Notify::ChangeType::ViewParams) { } else if (type == Notify::ChangeType::ViewParams) {
notifyUpdateAll(); notifyUpdateAll();
} else if (type == Notify::ChangeType::UseNative) {
notifyClearFast();
} else if (type == Notify::ChangeType::IncludeMuted) { } else if (type == Notify::ChangeType::IncludeMuted) {
Notify::unreadCounterUpdated(); Notify::unreadCounterUpdated();
} }
@ -397,14 +116,13 @@ MainWindow::MainWindow() {
_inactiveTimer.setSingleShot(true); _inactiveTimer.setSingleShot(true);
connect(&_inactiveTimer, SIGNAL(timeout()), this, SLOT(onInactiveTimer())); connect(&_inactiveTimer, SIGNAL(timeout()), this, SLOT(onInactiveTimer()));
connect(&notifyWaitTimer, SIGNAL(timeout()), this, SLOT(notifyFire())); connect(&_notifyWaitTimer, SIGNAL(timeout()), this, SLOT(notifyShowNext()));
_isActiveTimer.setSingleShot(true); _isActiveTimer.setSingleShot(true);
connect(&_isActiveTimer, SIGNAL(timeout()), this, SLOT(updateIsActive())); connect(&_isActiveTimer, SIGNAL(timeout()), this, SLOT(updateIsActive()));
connect(&_autoLockTimer, SIGNAL(timeout()), this, SLOT(checkAutoLock())); connect(&_autoLockTimer, SIGNAL(timeout()), this, SLOT(checkAutoLock()));
subscribe(FileDownload::ImageLoaded(), [this] { notifyUpdateAllPhotos(); });
subscribe(Global::RefSelfChanged(), [this]() { updateGlobalMenu(); }); subscribe(Global::RefSelfChanged(), [this]() { updateGlobalMenu(); });
setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_NoSystemBackground);
@ -547,6 +265,10 @@ void MainWindow::clearPasscode() {
notifyUpdateAll(); notifyUpdateAll();
title->updateControlsVisibility(); title->updateControlsVisibility();
updateGlobalMenu(); updateGlobalMenu();
if (auto main = App::main()) {
main->checkStartUrl();
}
} }
void MainWindow::setupPasscode(bool anim) { void MainWindow::setupPasscode(bool anim) {
@ -1030,9 +752,8 @@ bool MainWindow::eventFilter(QObject *obj, QEvent *e) {
QString url = static_cast<QFileOpenEvent*>(e)->url().toEncoded().trimmed(); QString url = static_cast<QFileOpenEvent*>(e)->url().toEncoded().trimmed();
if (url.startsWith(qstr("tg://"), Qt::CaseInsensitive)) { if (url.startsWith(qstr("tg://"), Qt::CaseInsensitive)) {
cSetStartUrl(url.mid(0, 8192)); cSetStartUrl(url.mid(0, 8192));
if (!cStartUrl().isEmpty() && App::main() && App::self()) { if (auto main = App::main()) {
App::main()->openLocalUrl(cStartUrl()); main->checkStartUrl();
cSetStartUrl(QString());
} }
} }
activate(); activate();
@ -1402,72 +1123,66 @@ void MainWindow::notifySchedule(History *history, HistoryItem *item) {
// LOG(("Is online: %1, otherOnline: %2, currentTime: %3, otherNotOld: %4, otherLaterThanMe: %5").arg(Logs::b(isOnline)).arg(cOtherOnline()).arg(t).arg(Logs::b(otherNotOld)).arg(Logs::b(otherLaterThanMe))); // LOG(("Is online: %1, otherOnline: %2, currentTime: %3, otherNotOld: %4, otherLaterThanMe: %5").arg(Logs::b(isOnline)).arg(cOtherOnline()).arg(t).arg(Logs::b(otherNotOld)).arg(Logs::b(otherLaterThanMe)));
uint64 when = ms + delay; uint64 when = ms + delay;
notifyWhenAlerts[history].insert(when, notifyByFrom); _notifyWhenAlerts[history].insert(when, notifyByFrom);
if (Global::DesktopNotify() && !psSkipDesktopNotify()) { if (Global::DesktopNotify() && !psSkipDesktopNotify()) {
NotifyWhenMaps::iterator i = notifyWhenMaps.find(history); NotifyWhenMaps::iterator i = _notifyWhenMaps.find(history);
if (i == notifyWhenMaps.end()) { if (i == _notifyWhenMaps.end()) {
i = notifyWhenMaps.insert(history, NotifyWhenMap()); i = _notifyWhenMaps.insert(history, NotifyWhenMap());
} }
if (i.value().constFind(item->id) == i.value().cend()) { if (i.value().constFind(item->id) == i.value().cend()) {
i.value().insert(item->id, when); i.value().insert(item->id, when);
} }
NotifyWaiters *addTo = haveSetting ? &notifyWaiters : &notifySettingWaiters; NotifyWaiters *addTo = haveSetting ? &_notifyWaiters : &_notifySettingWaiters;
NotifyWaiters::const_iterator it = addTo->constFind(history); NotifyWaiters::const_iterator it = addTo->constFind(history);
if (it == addTo->cend() || it->when > when) { if (it == addTo->cend() || it->when > when) {
addTo->insert(history, NotifyWaiter(item->id, when, notifyByFrom)); addTo->insert(history, NotifyWaiter(item->id, when, notifyByFrom));
} }
} }
if (haveSetting) { if (haveSetting) {
if (!notifyWaitTimer.isActive() || notifyWaitTimer.remainingTime() > delay) { if (!_notifyWaitTimer.isActive() || _notifyWaitTimer.remainingTime() > delay) {
notifyWaitTimer.start(delay); _notifyWaitTimer.start(delay);
} }
} }
} }
void MainWindow::notifyFire() {
notifyShowNext();
}
void MainWindow::notifyClear(History *history) { void MainWindow::notifyClear(History *history) {
if (!history) { if (!history) {
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { Window::Notifications::manager()->clearAll();
(*i)->unlinkHistory();
} for (auto i = _notifyWhenMaps.cbegin(), e = _notifyWhenMaps.cend(); i != e; ++i) {
psClearNotifies();
for (NotifyWhenMaps::const_iterator i = notifyWhenMaps.cbegin(), e = notifyWhenMaps.cend(); i != e; ++i) {
i.key()->clearNotifications(); i.key()->clearNotifications();
} }
notifyWaiters.clear(); _notifyWhenMaps.clear();
notifySettingWaiters.clear(); _notifyWhenAlerts.clear();
notifyWhenMaps.clear(); _notifyWaiters.clear();
_notifySettingWaiters.clear();
return; return;
} }
notifyWaiters.remove(history);
notifySettingWaiters.remove(history); Window::Notifications::manager()->clearFromHistory(history);
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
(*i)->unlinkHistory(history); history->clearNotifications();
} _notifyWhenMaps.remove(history);
psClearNotifies(history->peer->id); _notifyWhenAlerts.remove(history);
notifyWhenMaps.remove(history); _notifyWaiters.remove(history);
notifyWhenAlerts.remove(history); _notifySettingWaiters.remove(history);
_notifyWaitTimer.stop();
notifyShowNext(); notifyShowNext();
} }
void MainWindow::notifyClearFast() { void MainWindow::notifyClearFast() {
notifyWaiters.clear(); Window::Notifications::manager()->clearAllFast();
notifySettingWaiters.clear();
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { _notifyWhenMaps.clear();
(*i)->deleteLater(); _notifyWhenAlerts.clear();
} _notifyWaiters.clear();
psClearNotifies(); _notifySettingWaiters.clear();
notifyWindows.clear();
notifyWhenMaps.clear();
notifyWhenAlerts.clear();
} }
void MainWindow::notifySettingGot() { void MainWindow::notifySettingGot() {
int32 t = unixtime(); int32 t = unixtime();
for (NotifyWaiters::iterator i = notifySettingWaiters.begin(); i != notifySettingWaiters.end();) { for (NotifyWaiters::iterator i = _notifySettingWaiters.begin(); i != _notifySettingWaiters.end();) {
History *history = i.key(); History *history = i.key();
bool loaded = false, muted = false; bool loaded = false, muted = false;
if (history->peer->notify != UnknownNotifySettings) { if (history->peer->notify != UnknownNotifySettings) {
@ -1496,34 +1211,24 @@ void MainWindow::notifySettingGot() {
} }
if (loaded) { if (loaded) {
if (!muted) { if (!muted) {
notifyWaiters.insert(i.key(), i.value()); _notifyWaiters.insert(i.key(), i.value());
} }
i = notifySettingWaiters.erase(i); i = _notifySettingWaiters.erase(i);
} else { } else {
++i; ++i;
} }
} }
notifyWaitTimer.stop(); _notifyWaitTimer.stop();
notifyShowNext(); notifyShowNext();
} }
void MainWindow::notifyShowNext(NotifyWindow *remove) { void MainWindow::notifyShowNext() {
if (App::quitting()) return; if (App::quitting()) return;
int32 count = NotifyWindowsCount;
if (remove) {
for (NotifyWindows::iterator i = notifyWindows.begin(), e = notifyWindows.end(); i != e; ++i) {
if ((*i) == remove) {
notifyWindows.erase(i);
break;
}
}
}
uint64 ms = getms(true), nextAlert = 0; uint64 ms = getms(true), nextAlert = 0;
bool alert = false; bool alert = false;
int32 now = unixtime(); int32 now = unixtime();
for (NotifyWhenAlerts::iterator i = notifyWhenAlerts.begin(); i != notifyWhenAlerts.end();) { for (NotifyWhenAlerts::iterator i = _notifyWhenAlerts.begin(); i != _notifyWhenAlerts.end();) {
while (!i.value().isEmpty() && i.value().begin().key() <= ms) { while (!i.value().isEmpty() && i.value().begin().key() <= ms) {
NotifySettingsPtr n = i.key()->peer->notify, f = i.value().begin().value() ? i.value().begin().value()->notify : UnknownNotifySettings; NotifySettingsPtr n = i.key()->peer->notify, f = i.value().begin().value() ? i.value().begin().value()->notify : UnknownNotifySettings;
while (!i.value().isEmpty() && i.value().begin().key() <= ms + 500) { // not more than one sound in 500ms from one peer - grouping while (!i.value().isEmpty() && i.value().begin().key() <= ms + 500) { // not more than one sound in 500ms from one peer - grouping
@ -1536,7 +1241,7 @@ void MainWindow::notifyShowNext(NotifyWindow *remove) {
} }
} }
if (i.value().isEmpty()) { if (i.value().isEmpty()) {
i = notifyWhenAlerts.erase(i); i = _notifyWhenAlerts.erase(i);
} else { } else {
if (!nextAlert || nextAlert > i.value().begin().key()) { if (!nextAlert || nextAlert > i.value().begin().key()) {
nextAlert = i.value().begin().key(); nextAlert = i.value().begin().key();
@ -1549,33 +1254,24 @@ void MainWindow::notifyShowNext(NotifyWindow *remove) {
App::playSound(); App::playSound();
} }
if (Global::CustomNotifies()) { if (_notifyWaiters.isEmpty() || !Global::DesktopNotify() || psSkipDesktopNotify()) {
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
int32 ind = (*i)->index();
if (ind < 0) continue;
--count;
}
}
if (count <= 0 || notifyWaiters.isEmpty() || !Global::DesktopNotify() || psSkipDesktopNotify()) {
if (nextAlert) { if (nextAlert) {
notifyWaitTimer.start(nextAlert - ms); _notifyWaitTimer.start(nextAlert - ms);
} }
return; return;
} }
QRect r = psDesktopRect(); while (true) {
int32 x = r.x() + r.width() - st::notifyWidth - st::notifyDeltaX, y = r.y() + r.height() - st::notifyHeight - st::notifyDeltaY;
while (count > 0) {
uint64 next = 0; uint64 next = 0;
HistoryItem *notifyItem = 0; HistoryItem *notifyItem = 0;
History *notifyHistory = 0; History *notifyHistory = 0;
for (NotifyWaiters::iterator i = notifyWaiters.begin(); i != notifyWaiters.end();) { for (NotifyWaiters::iterator i = _notifyWaiters.begin(); i != _notifyWaiters.end();) {
History *history = i.key(); History *history = i.key();
if (history->currentNotification() && history->currentNotification()->id != i.value().msg) { if (history->currentNotification() && history->currentNotification()->id != i.value().msg) {
NotifyWhenMaps::iterator j = notifyWhenMaps.find(history); NotifyWhenMaps::iterator j = _notifyWhenMaps.find(history);
if (j == notifyWhenMaps.end()) { if (j == _notifyWhenMaps.end()) {
history->clearNotifications(); history->clearNotifications();
i = notifyWaiters.erase(i); i = _notifyWaiters.erase(i);
continue; continue;
} }
do { do {
@ -1589,8 +1285,8 @@ void MainWindow::notifyShowNext(NotifyWindow *remove) {
} while (history->currentNotification()); } while (history->currentNotification());
} }
if (!history->currentNotification()) { if (!history->currentNotification()) {
notifyWhenMaps.remove(history); _notifyWhenMaps.remove(history);
i = notifyWaiters.erase(i); i = _notifyWaiters.erase(i);
continue; continue;
} }
uint64 when = i.value().when; uint64 when = i.value().when;
@ -1607,7 +1303,7 @@ void MainWindow::notifyShowNext(NotifyWindow *remove) {
next = nextAlert; next = nextAlert;
nextAlert = 0; nextAlert = 0;
} }
notifyWaitTimer.start(next - ms); _notifyWaitTimer.start(next - ms);
break; break;
} else { } else {
HistoryItem *fwd = notifyItem->Has<HistoryMessageForwarded>() ? notifyItem : nullptr; // forwarded notify grouping HistoryItem *fwd = notifyItem->Has<HistoryMessageForwarded>() ? notifyItem : nullptr; // forwarded notify grouping
@ -1615,8 +1311,8 @@ void MainWindow::notifyShowNext(NotifyWindow *remove) {
uint64 ms = getms(true); uint64 ms = getms(true);
History *history = notifyItem->history(); History *history = notifyItem->history();
NotifyWhenMaps::iterator j = notifyWhenMaps.find(history); NotifyWhenMaps::iterator j = _notifyWhenMaps.find(history);
if (j == notifyWhenMaps.cend()) { if (j == _notifyWhenMaps.cend()) {
history->clearNotifications(); history->clearNotifications();
} else { } else {
HistoryItem *nextNotify = 0; HistoryItem *nextNotify = 0;
@ -1631,7 +1327,7 @@ void MainWindow::notifyShowNext(NotifyWindow *remove) {
NotifyWhenMap::const_iterator k = j.value().constFind(history->currentNotification()->id); NotifyWhenMap::const_iterator k = j.value().constFind(history->currentNotification()->id);
if (k != j.value().cend()) { if (k != j.value().cend()) {
nextNotify = history->currentNotification(); nextNotify = history->currentNotification();
notifyWaiters.insert(notifyHistory, NotifyWaiter(k.key(), k.value(), 0)); _notifyWaiters.insert(notifyHistory, NotifyWaiter(k.key(), k.value(), 0));
break; break;
} }
history->skipNotification(); history->skipNotification();
@ -1652,18 +1348,11 @@ void MainWindow::notifyShowNext(NotifyWindow *remove) {
} while (nextNotify); } while (nextNotify);
} }
if (Global::CustomNotifies()) { Window::Notifications::manager()->showNotification(notifyItem, fwdCount);
NotifyWindow *notify = new NotifyWindow(notifyItem, x, y, fwdCount);
notifyWindows.push_back(notify);
psNotifyShown(notify);
--count;
} else {
psPlatformNotify(notifyItem, fwdCount);
}
if (!history->hasNotification()) { if (!history->hasNotification()) {
notifyWaiters.remove(history); _notifyWaiters.remove(history);
notifyWhenMaps.remove(history); _notifyWhenMaps.remove(history);
continue; continue;
} }
} }
@ -1672,49 +1361,8 @@ void MainWindow::notifyShowNext(NotifyWindow *remove) {
} }
} }
if (nextAlert) { if (nextAlert) {
notifyWaitTimer.start(nextAlert - ms); _notifyWaitTimer.start(nextAlert - ms);
} }
count = NotifyWindowsCount - count;
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
int32 ind = (*i)->index();
if (ind < 0) continue;
--count;
(*i)->moveTo(x, y - count * (st::notifyHeight + st::notifyDeltaY));
}
}
void MainWindow::notifyItemRemoved(HistoryItem *item) {
if (Global::CustomNotifies()) {
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
(*i)->itemRemoved(item);
}
}
}
void MainWindow::notifyStopHiding() {
if (Global::CustomNotifies()) {
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
(*i)->stopHiding();
}
}
}
void MainWindow::notifyStartHiding() {
if (Global::CustomNotifies()) {
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
(*i)->startHiding();
}
}
}
void MainWindow::notifyUpdateAllPhotos() {
if (Global::CustomNotifies()) {
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
(*i)->updatePeerPhoto();
}
}
if (_mediaView && !_mediaView->isHidden()) _mediaView->updateControls();
} }
void MainWindow::app_activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button) { void MainWindow::app_activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button) {
@ -1722,20 +1370,7 @@ void MainWindow::app_activateClickHandler(ClickHandlerPtr handler, Qt::MouseButt
} }
void MainWindow::notifyUpdateAll() { void MainWindow::notifyUpdateAll() {
if (Global::CustomNotifies()) { Window::Notifications::manager()->updateAll();
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
(*i)->updateNotifyDisplay();
}
}
psClearNotifies();
}
void MainWindow::notifyActivateAll() {
if (Global::CustomNotifies()) {
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
psActivateNotify(*i);
}
}
} }
QImage MainWindow::iconLarge() const { QImage MainWindow::iconLarge() const {

View file

@ -22,8 +22,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "title.h" #include "title.h"
#include "pspecific.h" #include "pspecific.h"
#include "ui/boxshadow.h" #include "ui/effects/rect_shadow.h"
#include "platform/platform_main_window.h" #include "platform/platform_main_window.h"
#include "core/single_timer.h"
class MediaView; class MediaView;
class TitleWidget; class TitleWidget;
@ -32,9 +33,11 @@ class IntroWidget;
class MainWidget; class MainWidget;
class LayerStackWidget; class LayerStackWidget;
class LayerWidget; class LayerWidget;
namespace Local { namespace Local {
class ClearManager; class ClearManager;
} // namespace Local } // namespace Local
namespace Settings { namespace Settings {
class Widget; class Widget;
} // namespace Settings } // namespace Settings
@ -43,87 +46,21 @@ class ConnectingWidget : public QWidget {
Q_OBJECT Q_OBJECT
public: public:
ConnectingWidget(QWidget *parent, const QString &text, const QString &reconnect); ConnectingWidget(QWidget *parent, const QString &text, const QString &reconnect);
void set(const QString &text, const QString &reconnect); void set(const QString &text, const QString &reconnect);
void paintEvent(QPaintEvent *e); void paintEvent(QPaintEvent *e);
public slots: public slots:
void onReconnect(); void onReconnect();
private: private:
Ui::RectShadow _shadow;
BoxShadow _shadow;
QString _text; QString _text;
int32 _textWidth; int32 _textWidth;
LinkButton _reconnect; LinkButton _reconnect;
}; };
class NotifyWindow : public TWidget {
Q_OBJECT
public:
NotifyWindow(HistoryItem *item, int32 x, int32 y, int32 fwdCount);
void enterEvent(QEvent *e);
void leaveEvent(QEvent *e);
void mousePressEvent(QMouseEvent *e);
void paintEvent(QPaintEvent *e);
void step_appearance(float64 ms, bool timer);
void animHide(float64 duration, anim::transition func);
void startHiding();
void stopHiding();
void moveTo(int32 x, int32 y, int32 index = -1);
void updateNotifyDisplay();
void updatePeerPhoto();
void itemRemoved(HistoryItem *del);
int32 index() const {
return history ? _index : -1;
}
void unlinkHistory(History *hist = 0);
~NotifyWindow();
public slots:
void hideByTimer();
void checkLastInput();
void unlinkHistoryAndNotify();
private:
#if defined Q_OS_WIN && !defined Q_OS_WINRT
DWORD started;
#endif // Q_OS_WIN && !Q_OS_WINRT
History *history;
HistoryItem *item;
int32 fwdCount;
IconedButton close;
QPixmap pm;
float64 alphaDuration, posDuration;
QTimer hideTimer, inputTimer;
bool hiding;
int32 _index;
anim::fvalue a_opacity;
anim::transition a_func;
anim::ivalue a_y;
Animation _a_appearance;
ImagePtr peerPhoto;
};
typedef QList<NotifyWindow*> NotifyWindows;
class MediaPreviewWidget; class MediaPreviewWidget;
class MainWindow : public Platform::MainWindow, private base::Subscriber { class MainWindow : public Platform::MainWindow, private base::Subscriber {
@ -204,12 +141,7 @@ public:
void notifySchedule(History *history, HistoryItem *item); void notifySchedule(History *history, HistoryItem *item);
void notifyClear(History *history = 0); void notifyClear(History *history = 0);
void notifyClearFast(); void notifyClearFast();
void notifyShowNext(NotifyWindow *remove = 0);
void notifyItemRemoved(HistoryItem *item);
void notifyStopHiding();
void notifyStartHiding();
void notifyUpdateAll(); void notifyUpdateAll();
void notifyActivateAll();
QImage iconLarge() const; QImage iconLarge() const;
@ -266,7 +198,7 @@ public slots:
void onClearFinished(int task, void *manager); void onClearFinished(int task, void *manager);
void onClearFailed(int task, void *manager); void onClearFailed(int task, void *manager);
void notifyFire(); void notifyShowNext();
void updateTrayMenu(bool force = false); void updateTrayMenu(bool force = false);
void onShowAddContact(); void onShowAddContact();
@ -278,8 +210,6 @@ public slots:
void onReActivate(); void onReActivate();
void notifyUpdateAllPhotos();
void app_activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button); void app_activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button);
signals: signals:
@ -333,28 +263,30 @@ private:
SingleTimer _autoLockTimer; SingleTimer _autoLockTimer;
uint64 _shouldLockAt = 0; uint64 _shouldLockAt = 0;
typedef QMap<MsgId, uint64> NotifyWhenMap; using NotifyWhenMap = QMap<MsgId, uint64>;
typedef QMap<History*, NotifyWhenMap> NotifyWhenMaps; using NotifyWhenMaps = QMap<History*, NotifyWhenMap>;
NotifyWhenMaps notifyWhenMaps; NotifyWhenMaps _notifyWhenMaps;
struct NotifyWaiter { struct NotifyWaiter {
NotifyWaiter(MsgId msg, uint64 when, PeerData *notifyByFrom) : msg(msg), when(when), notifyByFrom(notifyByFrom) { NotifyWaiter(MsgId msg, uint64 when, PeerData *notifyByFrom)
: msg(msg)
, when(when)
, notifyByFrom(notifyByFrom) {
} }
MsgId msg; MsgId msg;
uint64 when; uint64 when;
PeerData *notifyByFrom; PeerData *notifyByFrom;
}; };
typedef QMap<History*, NotifyWaiter> NotifyWaiters; using NotifyWaiters = QMap<History*, NotifyWaiter>;
NotifyWaiters notifyWaiters; NotifyWaiters _notifyWaiters;
NotifyWaiters notifySettingWaiters; NotifyWaiters _notifySettingWaiters;
SingleTimer notifyWaitTimer; SingleTimer _notifyWaitTimer;
typedef QMap<uint64, PeerData*> NotifyWhenAlert; using NotifyWhenAlert = QMap<uint64, PeerData*>;
typedef QMap<History*, NotifyWhenAlert> NotifyWhenAlerts; using NotifyWhenAlerts = QMap<History*, NotifyWhenAlert>;
NotifyWhenAlerts notifyWhenAlerts; NotifyWhenAlerts _notifyWhenAlerts;
NotifyWindows notifyWindows;
MediaView *_mediaView = nullptr; MediaView *_mediaView = nullptr;
}; };
class PreLaunchWindow : public TWidget { class PreLaunchWindow : public TWidget {

View file

@ -985,13 +985,13 @@ void AudioPlayerFader::onTimer() {
} else if (ms > _suppressAllStart + notifyLengthMs - AudioFadeDuration) { } else if (ms > _suppressAllStart + notifyLengthMs - AudioFadeDuration) {
if (_suppressAllGain.to() != 1.) _suppressAllGain.start(1.); if (_suppressAllGain.to() != 1.) _suppressAllGain.start(1.);
_suppressAllGain.update(1. - ((_suppressAllStart + notifyLengthMs - ms) / float64(AudioFadeDuration)), anim::linear); _suppressAllGain.update(1. - ((_suppressAllStart + notifyLengthMs - ms) / float64(AudioFadeDuration)), anim::linear);
} else if (ms >= _suppressAllStart + st::notifyFastAnim) { } else if (ms >= _suppressAllStart + st::mediaPlayerSuppressDuration) {
if (_suppressAllAnim) { if (_suppressAllAnim) {
_suppressAllGain.finish(); _suppressAllGain.finish();
_suppressAllAnim = false; _suppressAllAnim = false;
} }
} else if (ms > _suppressAllStart) { } else if (ms > _suppressAllStart) {
_suppressAllGain.update((ms - _suppressAllStart) / st::notifyFastAnim, anim::linear); _suppressAllGain.update((ms - _suppressAllStart) / st::mediaPlayerSuppressDuration, anim::linear);
} }
suppressAllGain = _suppressAllGain.current(); suppressAllGain = _suppressAllGain.current();
suppressAudioChanged = (suppressAllGain != wasAudio); suppressAudioChanged = (suppressAllGain != wasAudio);

View file

@ -75,7 +75,7 @@ AudioPlayerLoaders::~AudioPlayerLoaders() {
} }
void AudioPlayerLoaders::clearFromVideoQueue() { void AudioPlayerLoaders::clearFromVideoQueue() {
auto queue = createAndSwap(_fromVideoQueue); auto queue = base::take(_fromVideoQueue);
for (auto &packetData : queue) { for (auto &packetData : queue) {
AVPacket packet; AVPacket packet;
FFMpeg::packetFromDataWrap(packet, packetData); FFMpeg::packetFromDataWrap(packet, packetData);

View file

@ -197,7 +197,7 @@ void ChildFFMpegLoader::enqueuePackets(QQueue<FFMpeg::AVPacketDataWrap> &packets
} }
ChildFFMpegLoader::~ChildFFMpegLoader() { ChildFFMpegLoader::~ChildFFMpegLoader() {
auto queue = createAndSwap(_queue); auto queue = base::take(_queue);
for (auto &packetData : queue) { for (auto &packetData : queue) {
AVPacket packet; AVPacket packet;
FFMpeg::packetFromDataWrap(packet, packetData); FFMpeg::packetFromDataWrap(packet, packetData);

View file

@ -525,7 +525,7 @@ void FFMpegReaderImplementation::finishPacket() {
void FFMpegReaderImplementation::clearPacketQueue() { void FFMpegReaderImplementation::clearPacketQueue() {
finishPacket(); finishPacket();
auto packets = createAndSwap(_packetQueue); auto packets = base::take(_packetQueue);
for (auto &packetData : packets) { for (auto &packetData : packets) {
AVPacket packet; AVPacket packet;
FFMpeg::packetFromDataWrap(packet, packetData); FFMpeg::packetFromDataWrap(packet, packetData);

View file

@ -106,7 +106,7 @@ bool QtGifReaderImplementation::start(Mode mode, int64 &positionMs) {
} }
QtGifReaderImplementation::~QtGifReaderImplementation() { QtGifReaderImplementation::~QtGifReaderImplementation() {
deleteAndMark(_reader); delete base::take(_reader);
} }
bool QtGifReaderImplementation::jumpToStart() { bool QtGifReaderImplementation::jumpToStart() {

View file

@ -44,8 +44,7 @@ bool exists() {
} }
void finish() { void finish() {
auto temp = createAndSwap(SingleInstance); delete base::take(SingleInstance);
delete temp;
audioFinish(); audioFinish();
} }

View file

@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#include "ui/boxshadow.h" #include "ui/effects/rect_shadow.h"
class ScrollArea; class ScrollArea;

View file

@ -26,6 +26,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "mainwindow.h" #include "mainwindow.h"
#include "application.h" #include "application.h"
#include "ui/filedialog.h" #include "ui/filedialog.h"
#include "ui/popupmenu.h"
#include "media/media_clip_reader.h" #include "media/media_clip_reader.h"
#include "media/view/media_clip_controller.h" #include "media/view/media_clip_controller.h"
#include "styles/style_mediaview.h" #include "styles/style_mediaview.h"
@ -96,6 +97,12 @@ MediaView::MediaView() : TWidget(App::wnd())
connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(onScreenResized(int))); connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(onScreenResized(int)));
subscribe(FileDownload::ImageLoaded(), [this] {
if (!isHidden()) {
updateControls();
}
});
_transparentBrush = QBrush(App::sprite().copy(st::mvTransparentBrush.rect())); _transparentBrush = QBrush(App::sprite().copy(st::mvTransparentBrush.rect()));
setWindowFlags(Qt::FramelessWindowHint | Qt::BypassWindowManagerHint | Qt::Tool | Qt::NoDropShadowWindowHint); setWindowFlags(Qt::FramelessWindowHint | Qt::BypassWindowManagerHint | Qt::Tool | Qt::NoDropShadowWindowHint);
@ -612,7 +619,7 @@ void MediaView::clearData() {
} }
MediaView::~MediaView() { MediaView::~MediaView() {
deleteAndMark(_menu); delete base::take(_menu);
} }
void MediaView::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { void MediaView::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {

View file

@ -29,9 +29,11 @@ class Controller;
} // namespace Clip } // namespace Clip
} // namespace Media } // namespace Media
class PopupMenu;
struct AudioPlaybackState; struct AudioPlaybackState;
class MediaView : public TWidget, public RPCSender, public ClickHandlerHost { class MediaView : public TWidget, private base::Subscriber, public RPCSender, public ClickHandlerHost {
Q_OBJECT Q_OBJECT
public: public:

View file

@ -44,17 +44,17 @@ public:
} }
uint32 getDC() const { uint32 getDC() const {
if (!_isset) throw mtpErrorKeyNotReady("getDC()"); t_assert(_isset);
return _dc; return _dc;
} }
uint64 keyId() const { uint64 keyId() const {
if (!_isset) throw mtpErrorKeyNotReady("keyId()"); t_assert(_isset);
return _keyId; return _keyId;
} }
void prepareAES(const MTPint128 &msgKey, MTPint256 &aesKey, MTPint256 &aesIV, bool send = true) const { void prepareAES(const MTPint128 &msgKey, MTPint256 &aesKey, MTPint256 &aesIV, bool send = true) const {
if (!_isset) throw mtpErrorKeyNotReady(QString("prepareAES(..., %1)").arg(Logs::b(send))); t_assert(_isset);
uint32 x = send ? 0 : 8; uint32 x = send ? 0 : 8;
@ -90,7 +90,7 @@ public:
} }
void write(QDataStream &to) const { void write(QDataStream &to) const {
if (!_isset) throw mtpErrorKeyNotReady("write(...)"); t_assert(_isset);
to.writeRawData(_key, 256); to.writeRawData(_key, 256);
} }

View file

@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "mtproto/core_types.h" #include "mtproto/core_types.h"
#include "mtproto/auth_key.h" #include "mtproto/auth_key.h"
#include "mtproto/connection_abstract.h" #include "mtproto/connection_abstract.h"
#include "core/single_timer.h"
namespace MTP { namespace MTP {
namespace internal { namespace internal {

View file

@ -298,7 +298,7 @@ void AbstractTCPConnection::tcpSend(mtpBuffer &buffer) {
// prepare decryption key/iv // prepare decryption key/iv
char reversed[48]; char reversed[48];
memcpy(reversed, nonce + 8, sizeof(reversed)); memcpy(reversed, nonce + 8, sizeof(reversed));
std::reverse(reversed, reversed + arraysize(reversed)); std::reverse(reversed, reversed + base::array_size(reversed));
memcpy(_receiveKey, reversed, CTRState::KeySize); memcpy(_receiveKey, reversed, CTRState::KeySize);
memcpy(_receiveState.ivec, reversed + CTRState::KeySize, CTRState::IvecSize); memcpy(_receiveState.ivec, reversed + CTRState::KeySize, CTRState::IvecSize);

View file

@ -199,30 +199,12 @@ public:
} }
}; };
class mtpErrorUninitialized : public Exception {
public:
mtpErrorUninitialized() : Exception("MTP Uninitialized variable write attempt") {
}
};
class mtpErrorBadTypeId : public Exception { class mtpErrorBadTypeId : public Exception {
public: public:
mtpErrorBadTypeId(mtpTypeId typeId, const QString &type) : Exception(QString("MTP Bad type id %1 passed to constructor of %2").arg(typeId).arg(type)) { mtpErrorBadTypeId(mtpTypeId typeId, const QString &type) : Exception(QString("MTP Bad type id %1 passed to constructor of %2").arg(typeId).arg(type)) {
} }
}; };
class mtpErrorWrongTypeId : public Exception {
public:
mtpErrorWrongTypeId(mtpTypeId typeId, mtpTypeId required) : Exception(QString("MTP Wrong type id %1 for this data conversion, must be %2").arg(typeId).arg(required)) {
}
};
class mtpErrorKeyNotReady : public Exception {
public:
mtpErrorKeyNotReady(const QString &method) : Exception(QString("MTP Auth key is used in %1 without being created").arg(method)) {
}
};
class mtpData { class mtpData {
public: public:
mtpData() : cnt(1) { mtpData() : cnt(1) {
@ -686,12 +668,12 @@ public:
} }
MTPDstring &_string() { MTPDstring &_string() {
if (!data) throw mtpErrorUninitialized(); t_assert(data != nullptr);
split(); split();
return *(MTPDstring*)data; return *(MTPDstring*)data;
} }
const MTPDstring &c_string() const { const MTPDstring &c_string() const {
if (!data) throw mtpErrorUninitialized(); t_assert(data != nullptr);
return *(const MTPDstring*)data; return *(const MTPDstring*)data;
} }
@ -823,12 +805,12 @@ public:
} }
MTPDvector<T> &_vector() { MTPDvector<T> &_vector() {
if (!data) throw mtpErrorUninitialized(); t_assert(data != nullptr);
split(); split();
return *(MTPDvector<T>*)data; return *(MTPDvector<T>*)data;
} }
const MTPDvector<T> &c_vector() const { const MTPDvector<T> &c_vector() const {
if (!data) throw mtpErrorUninitialized(); t_assert(data != nullptr);
return *(const MTPDvector<T>*)data; return *(const MTPDvector<T>*)data;
} }

View file

@ -20,6 +20,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#include "core/single_timer.h"
namespace MTP { namespace MTP {
namespace internal { namespace internal {
@ -27,7 +29,6 @@ class Dcenter : public QObject {
Q_OBJECT Q_OBJECT
public: public:
Dcenter(int32 id, const AuthKeyPtr &key); Dcenter(int32 id, const AuthKeyPtr &key);
QReadWriteLock *keyMutex() const; QReadWriteLock *keyMutex() const;
@ -46,21 +47,19 @@ public:
} }
signals: signals:
void authKeyCreated(); void authKeyCreated();
void layerWasInited(bool was); void layerWasInited(bool was);
private slots: private slots:
void authKeyWrite(); void authKeyWrite();
private: private:
mutable QReadWriteLock keyLock; mutable QReadWriteLock keyLock;
mutable QMutex initLock; mutable QMutex initLock;
int32 _id; int32 _id;
AuthKeyPtr _key; AuthKeyPtr _key;
bool _connectionInited; bool _connectionInited;
}; };
typedef QSharedPointer<Dcenter> DcenterPtr; typedef QSharedPointer<Dcenter> DcenterPtr;
@ -70,21 +69,17 @@ class ConfigLoader : public QObject {
Q_OBJECT Q_OBJECT
public: public:
ConfigLoader(); ConfigLoader();
void load(); void load();
void done(); void done();
public slots: public slots:
void enumDC(); void enumDC();
signals: signals:
void loaded(); void loaded();
private: private:
SingleTimer _enumDCTimer; SingleTimer _enumDCTimer;
int32 _enumCurrent; int32 _enumCurrent;
mtpRequestId _enumRequest; mtpRequestId _enumRequest;

View file

@ -22,6 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "mtproto/core_types.h" #include "mtproto/core_types.h"
#include "mtproto/session.h" #include "mtproto/session.h"
#include "core/single_timer.h"
namespace MTP { namespace MTP {
@ -57,17 +58,15 @@ class GlobalSlotCarrier : public QObject {
Q_OBJECT Q_OBJECT
public: public:
GlobalSlotCarrier(); GlobalSlotCarrier();
public slots: public slots:
void checkDelayed(); void checkDelayed();
void connectionFinished(Connection *connection); void connectionFinished(Connection *connection);
private: private:
SingleTimer _timer; SingleTimer _timer;
}; };
GlobalSlotCarrier *globalSlotCarrier(); GlobalSlotCarrier *globalSlotCarrier();

View file

@ -612,17 +612,19 @@ for restype in typesList:
withData = 1; withData = 1;
getters += '\n\tMTPD' + name + ' &_' + name + '() {\n'; # splitting getter getters += '\n\tMTPD' + name + ' &_' + name + '() {\n'; # splitting getter
getters += '\t\tif (!data) throw mtpErrorUninitialized();\n';
if (withType): if (withType):
getters += '\t\tif (_type != mtpc_' + name + ') throw mtpErrorWrongTypeId(_type, mtpc_' + name + ');\n'; getters += '\t\tt_assert(data != nullptr && _type == mtpc_' + name + ');\n';
else:
getters += '\t\tt_assert(data != nullptr);\n';
getters += '\t\tsplit();\n'; getters += '\t\tsplit();\n';
getters += '\t\treturn *(MTPD' + name + '*)data;\n'; getters += '\t\treturn *(MTPD' + name + '*)data;\n';
getters += '\t}\n'; getters += '\t}\n';
getters += '\tconst MTPD' + name + ' &c_' + name + '() const {\n'; # const getter getters += '\tconst MTPD' + name + ' &c_' + name + '() const {\n'; # const getter
getters += '\t\tif (!data) throw mtpErrorUninitialized();\n';
if (withType): if (withType):
getters += '\t\tif (_type != mtpc_' + name + ') throw mtpErrorWrongTypeId(_type, mtpc_' + name + ');\n'; getters += '\t\tt_assert(data != nullptr && _type == mtpc_' + name + ');\n';
else:
getters += '\t\tt_assert(data != nullptr);\n';
getters += '\t\treturn *(const MTPD' + name + '*)data;\n'; getters += '\t\treturn *(const MTPD' + name + '*)data;\n';
getters += '\t}\n'; getters += '\t}\n';
@ -783,7 +785,7 @@ for restype in typesList:
typesText += '\tmtpTypeId type() const;\n'; # type id method typesText += '\tmtpTypeId type() const;\n'; # type id method
inlineMethods += 'inline mtpTypeId MTP' + restype + '::type() const {\n'; inlineMethods += 'inline mtpTypeId MTP' + restype + '::type() const {\n';
if (withType): if (withType):
inlineMethods += '\tif (!_type) throw mtpErrorUninitialized();\n'; inlineMethods += '\tt_assert(_type != 0);\n';
inlineMethods += '\treturn _type;\n'; inlineMethods += '\treturn _type;\n';
else: else:
inlineMethods += '\treturn mtpc_' + v[0][0] + ';\n'; inlineMethods += '\treturn mtpc_' + v[0][0] + ';\n';

View file

@ -20,9 +20,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#include "core/lambda_wrap.h"
class RPCError { class RPCError {
public: public:
RPCError(const MTPrpcError &error) : _code(error.c_rpc_error().verror_code.v) { RPCError(const MTPrpcError &error) : _code(error.c_rpc_error().verror_code.v) {
QString text = qs(error.c_rpc_error().verror_message); QString text = qs(error.c_rpc_error().verror_message);
if (_code < 0 || _code >= 500) { if (_code < 0 || _code >= 500) {
@ -827,3 +828,187 @@ protected:
typedef void (*MTPStateChangedHandler)(int32 dcId, int32 state); typedef void (*MTPStateChangedHandler)(int32 dcId, int32 state);
typedef void(*MTPSessionResetHandler)(int32 dcId); typedef void(*MTPSessionResetHandler)(int32 dcId);
template <typename FunctionType>
struct LambdaUniqueHelper;
template <typename Lambda, typename R, typename ...Args>
struct LambdaUniqueHelper<R(Lambda::*)(Args...) const> {
using UniqueType = base::lambda_unique<R(Args...)>;
};
template <typename FunctionType>
using LambdaGetUnique = typename LambdaUniqueHelper<FunctionType>::UniqueType;
template <typename Base, typename FunctionType>
class RPCHandlerImplementation : public Base {
protected:
using Lambda = base::lambda_unique<FunctionType>;
using Parent = RPCHandlerImplementation<Base, FunctionType>;
public:
RPCHandlerImplementation(Lambda &&handler) : _handler(std_::move(handler)) {
}
protected:
Lambda _handler;
};
template <typename FunctionType>
using RPCDoneHandlerImplementation = RPCHandlerImplementation<RPCAbstractDoneHandler, FunctionType>;
template <typename R>
class RPCDoneHandlerImplementationBare : public RPCDoneHandlerImplementation<R(const mtpPrime*, const mtpPrime*)> { // done(from, end)
public:
using RPCDoneHandlerImplementation<R(const mtpPrime*, const mtpPrime*)>::Parent::Parent;
void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override {
return this->_handler ? this->_handler(from, end) : void(0);
}
};
template <typename R>
class RPCDoneHandlerImplementationBareReq : public RPCDoneHandlerImplementation<R(const mtpPrime*, const mtpPrime*, mtpRequestId)> { // done(from, end, req_id)
public:
using RPCDoneHandlerImplementation<R(const mtpPrime*, const mtpPrime*, mtpRequestId)>::Parent::Parent;
void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override {
return this->_handler ? this->_handler(from, end, requestId) : void(0);
}
};
template <typename R, typename T>
class RPCDoneHandlerImplementationPlain : public RPCDoneHandlerImplementation<R(const T&)> { // done(result)
public:
using RPCDoneHandlerImplementation<R(const T&)>::Parent::Parent;
void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override {
return this->_handler ? this->_handler(T(from, end)) : void(0);
}
};
template <typename R, typename T>
class RPCDoneHandlerImplementationReq : public RPCDoneHandlerImplementation<R(const T&, mtpRequestId)> { // done(result, req_id)
public:
using RPCDoneHandlerImplementation<R(const T&, mtpRequestId)>::Parent::Parent;
void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override {
return this->_handler ? this->_handler(T(from, end), requestId) : void(0);
}
};
template <typename R>
class RPCDoneHandlerImplementationNo : public RPCDoneHandlerImplementation<R()> { // done()
public:
using RPCDoneHandlerImplementation<R()>::Parent::Parent;
void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override {
return this->_handler ? this->_handler() : void(0);
}
};
template <typename R>
class RPCDoneHandlerImplementationNoReq : public RPCDoneHandlerImplementation<R(mtpRequestId)> { // done(req_id)
public:
using RPCDoneHandlerImplementation<R(mtpRequestId)>::Parent::Parent;
void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override {
return this->_handler ? this->_handler(requestId) : void(0);
}
};
template <typename R>
inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique<R(const mtpPrime*, const mtpPrime*)> &&lambda) {
return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationBare<R>(std_::move(lambda)));
}
template <typename R>
inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique<R(const mtpPrime*, const mtpPrime*, mtpRequestId)> &&lambda) {
return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationBareReq<R>(std_::move(lambda)));
}
template <typename R, typename T>
inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique<R(const T&)> &&lambda) {
return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationPlain<R, T>(std_::move(lambda)));
}
template <typename R, typename T>
inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique<R(const T&, mtpRequestId)> &&lambda) {
return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationReq<R, T>(std_::move(lambda)));
}
template <typename R>
inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique<R()> &&lambda) {
return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationNo<R>(std_::move(lambda)));
}
template <typename R>
inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique<R(mtpRequestId)> &&lambda) {
return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationNoReq<R>(std_::move(lambda)));
}
template <typename Lambda, typename = std_::enable_if_t<std_::is_rvalue_reference<Lambda&&>::value>>
RPCDoneHandlerPtr rpcDone(Lambda &&lambda) {
return rpcDone_lambda_wrap_helper(LambdaGetUnique<decltype(&Lambda::operator())>(std_::move(lambda)));
}
template <typename FunctionType>
using RPCFailHandlerImplementation = RPCHandlerImplementation<RPCAbstractFailHandler, FunctionType>;
class RPCFailHandlerImplementationPlain : public RPCFailHandlerImplementation<bool(const RPCError&)> { // fail(error)
public:
using Parent::Parent;
bool operator()(mtpRequestId requestId, const RPCError &error) const override {
return _handler ? _handler(error) : true;
}
};
class RPCFailHandlerImplementationReq : public RPCFailHandlerImplementation<bool(const RPCError&, mtpRequestId)> { // fail(error, req_id)
public:
using Parent::Parent;
bool operator()(mtpRequestId requestId, const RPCError &error) const override {
return this->_handler ? this->_handler(error, requestId) : true;
}
};
class RPCFailHandlerImplementationNo : public RPCFailHandlerImplementation<bool()> { // fail()
public:
using Parent::Parent;
bool operator()(mtpRequestId requestId, const RPCError &error) const override {
return this->_handler ? this->_handler() : true;
}
};
class RPCFailHandlerImplementationNoReq : public RPCFailHandlerImplementation<bool(mtpRequestId)> { // fail(req_id)
public:
using Parent::Parent;
bool operator()(mtpRequestId requestId, const RPCError &error) const override {
return this->_handler ? this->_handler(requestId) : true;
}
};
inline RPCFailHandlerPtr rpcFail_lambda_wrap_helper(base::lambda_unique<bool(const RPCError&)> &&lambda) {
return RPCFailHandlerPtr(new RPCFailHandlerImplementationPlain(std_::move(lambda)));
}
inline RPCFailHandlerPtr rpcFail_lambda_wrap_helper(base::lambda_unique<bool(const RPCError&, mtpRequestId)> &&lambda) {
return RPCFailHandlerPtr(new RPCFailHandlerImplementationReq(std_::move(lambda)));
}
inline RPCFailHandlerPtr rpcFail_lambda_wrap_helper(base::lambda_unique<bool()> &&lambda) {
return RPCFailHandlerPtr(new RPCFailHandlerImplementationNo(std_::move(lambda)));
}
inline RPCFailHandlerPtr rpcFail_lambda_wrap_helper(base::lambda_unique<bool(mtpRequestId)> &&lambda) {
return RPCFailHandlerPtr(new RPCFailHandlerImplementationNoReq(std_::move(lambda)));
}
template <typename Lambda, typename = std_::enable_if_t<std_::is_rvalue_reference<Lambda&&>::value>>
RPCFailHandlerPtr rpcFail(Lambda &&lambda) {
return rpcFail_lambda_wrap_helper(LambdaGetUnique<decltype(&Lambda::operator())>(std_::move(lambda)));
}

File diff suppressed because it is too large Load diff

View file

@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "mtproto/connection.h" #include "mtproto/connection.h"
#include "mtproto/dcenter.h" #include "mtproto/dcenter.h"
#include "mtproto/rpc_sender.h" #include "mtproto/rpc_sender.h"
#include "core/single_timer.h"
namespace MTP { namespace MTP {
namespace internal { namespace internal {
@ -31,7 +32,6 @@ class Session;
class SessionData { class SessionData {
public: public:
SessionData(Session *creator) SessionData(Session *creator)
: _session(0) : _session(0)
, _salt(0) , _salt(0)
@ -227,7 +227,6 @@ class Session : public QObject {
Q_OBJECT Q_OBJECT
public: public:
Session(int32 dcenter); Session(int32 dcenter);
void restart(); void restart();
@ -237,7 +236,6 @@ public:
void unpaused(); void unpaused();
int32 getDcWithShift() const; int32 getDcWithShift() const;
~Session();
QReadWriteLock *keyMutex() const; QReadWriteLock *keyMutex() const;
void notifyKeyCreated(const AuthKeyPtr &key); void notifyKeyCreated(const AuthKeyPtr &key);
@ -255,15 +253,15 @@ public:
void sendPrepared(const mtpRequest &request, uint64 msCanWait = 0, bool newRequest = true); // nulls msgId and seqNo in request, if newRequest = true void sendPrepared(const mtpRequest &request, uint64 msCanWait = 0, bool newRequest = true); // nulls msgId and seqNo in request, if newRequest = true
signals: ~Session();
signals:
void authKeyCreated(); void authKeyCreated();
void needToSend(); void needToSend();
void needToPing(); void needToPing();
void needToRestart(); void needToRestart();
public slots: public slots:
void needToResumeAndSend(); void needToResumeAndSend();
mtpRequestId resend(quint64 msgId, quint64 msCanWait = 0, bool forceContainer = false, bool sendMsgStateInfo = false); mtpRequestId resend(quint64 msgId, quint64 msCanWait = 0, bool forceContainer = false, bool sendMsgStateInfo = false);
@ -283,7 +281,6 @@ public slots:
void sendMsgsStateInfo(quint64 msgId, QByteArray data); void sendMsgsStateInfo(quint64 msgId, QByteArray data);
private: private:
Connection *_connection; Connection *_connection;
bool _killed; bool _killed;

View file

@ -98,8 +98,8 @@ void peerUpdatedSendDelayed() {
if (!SmallUpdates || !AllUpdates || SmallUpdates->empty()) return; if (!SmallUpdates || !AllUpdates || SmallUpdates->empty()) return;
auto smallList = createAndSwap(*SmallUpdates); auto smallList = base::take(*SmallUpdates);
auto allList = createAndSwap(*AllUpdates); auto allList = base::take(*AllUpdates);
for (auto &update : smallList) { for (auto &update : smallList) {
PeerUpdated().notify(std_::move(update), true); PeerUpdated().notify(std_::move(update), true);
} }

View file

@ -106,7 +106,7 @@ void RadialProgressItem::checkRadialFinished() {
} }
RadialProgressItem::~RadialProgressItem() { RadialProgressItem::~RadialProgressItem() {
deleteAndMark(_radial); delete base::take(_radial);
} }
void FileBase::setStatusSize(int32 newSize, int32 fullSize, int32 duration, qint64 realDuration) const { void FileBase::setStatusSize(int32 newSize, int32 fullSize, int32 duration, qint64 realDuration) const {

View file

@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#pragma once #pragma once
#include "window/section_widget.h" #include "window/section_widget.h"
#include "ui/popupmenu.h"
namespace Overview { namespace Overview {
namespace Layout { namespace Layout {

View file

@ -0,0 +1,122 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop 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/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "platform/linux/linux_libnotify.h"
#include "platform/linux/linux_libs.h"
namespace Platform {
namespace Libs {
namespace {
bool loadLibrary(QLibrary &lib, const char *name, int version) {
DEBUG_LOG(("Loading '%1' with version %2...").arg(QLatin1String(name)).arg(version));
lib.setFileNameAndVersion(QLatin1String(name), version);
if (lib.load()) {
DEBUG_LOG(("Loaded '%1' with version %2!").arg(QLatin1String(name)).arg(version));
return true;
}
lib.setFileNameAndVersion(QLatin1String(name), QString());
if (lib.load()) {
DEBUG_LOG(("Loaded '%1' without version!").arg(QLatin1String(name)));
return true;
}
LOG(("Could not load '%1' with version %2 :(").arg(QLatin1String(name)).arg(version));
return false;
}
} // namespace
f_notify_init notify_init = nullptr;
f_notify_uninit notify_uninit = nullptr;
f_notify_is_initted notify_is_initted = nullptr;
//f_notify_get_app_name notify_get_app_name = nullptr;
//f_notify_set_app_name notify_set_app_name = nullptr;
f_notify_get_server_caps notify_get_server_caps = nullptr;
f_notify_get_server_info notify_get_server_info = nullptr;
f_notify_notification_new notify_notification_new = nullptr;
//f_notify_notification_update notify_notification_update = nullptr;
f_notify_notification_show notify_notification_show = nullptr;
//f_notify_notification_set_app_name notify_notification_set_app_name = nullptr;
f_notify_notification_set_timeout notify_notification_set_timeout = nullptr;
//f_notify_notification_set_category notify_notification_set_category = nullptr;
//f_notify_notification_set_urgency notify_notification_set_urgency = nullptr;
//f_notify_notification_set_icon_from_pixbuf notify_notification_set_icon_from_pixbuf = nullptr;
f_notify_notification_set_image_from_pixbuf notify_notification_set_image_from_pixbuf = nullptr;
//f_notify_notification_set_hint notify_notification_set_hint = nullptr;
//f_notify_notification_set_hint_int32 notify_notification_set_hint_int32 = nullptr;
//f_notify_notification_set_hint_uint32 notify_notification_set_hint_uint32 = nullptr;
//f_notify_notification_set_hint_double notify_notification_set_hint_double = nullptr;
f_notify_notification_set_hint_string notify_notification_set_hint_string = nullptr;
//f_notify_notification_set_hint_byte notify_notification_set_hint_byte = nullptr;
//f_notify_notification_set_hint_byte_array notify_notification_set_hint_byte_array = nullptr;
//f_notify_notification_clear_hints notify_notification_clear_hints = nullptr;
f_notify_notification_add_action notify_notification_add_action = nullptr;
f_notify_notification_clear_actions notify_notification_clear_actions = nullptr;
f_notify_notification_close notify_notification_close = nullptr;
f_notify_notification_get_closed_reason notify_notification_get_closed_reason = nullptr;
void startLibNotify() {
DEBUG_LOG(("Loading libnotify"));
QLibrary lib_notify;
if (!loadLibrary(lib_notify, "notify", 4)) {
if (!loadLibrary(lib_notify, "notify", 5)) {
if (!loadLibrary(lib_notify, "notify", 1)) {
return;
}
}
}
load(lib_notify, "notify_init", notify_init);
load(lib_notify, "notify_uninit", notify_uninit);
load(lib_notify, "notify_is_initted", notify_is_initted);
// load(lib_notify, "notify_get_app_name", notify_get_app_name);
// load(lib_notify, "notify_set_app_name", notify_set_app_name);
load(lib_notify, "notify_get_server_caps", notify_get_server_caps);
load(lib_notify, "notify_get_server_info", notify_get_server_info);
load(lib_notify, "notify_notification_new", notify_notification_new);
// load(lib_notify, "notify_notification_update", notify_notification_update);
load(lib_notify, "notify_notification_show", notify_notification_show);
// load(lib_notify, "notify_notification_set_app_name", notify_notification_set_app_name);
load(lib_notify, "notify_notification_set_timeout", notify_notification_set_timeout);
// load(lib_notify, "notify_notification_set_category", notify_notification_set_category);
// load(lib_notify, "notify_notification_set_urgency", notify_notification_set_urgency);
// load(lib_notify, "notify_notification_set_icon_from_pixbuf", notify_notification_set_icon_from_pixbuf);
load(lib_notify, "notify_notification_set_image_from_pixbuf", notify_notification_set_image_from_pixbuf);
// load(lib_notify, "notify_notification_set_hint", notify_notification_set_hint);
// load(lib_notify, "notify_notification_set_hint_int32", notify_notification_set_hint_int32);
// load(lib_notify, "notify_notification_set_hint_uint32", notify_notification_set_hint_uint32);
// load(lib_notify, "notify_notification_set_hint_double", notify_notification_set_hint_double);
load(lib_notify, "notify_notification_set_hint_string", notify_notification_set_hint_string);
// load(lib_notify, "notify_notification_set_hint_byte", notify_notification_set_hint_byte);
// load(lib_notify, "notify_notification_set_hint_byte_array", notify_notification_set_hint_byte_array);
// load(lib_notify, "notify_notification_clear_hints", notify_notification_clear_hints);
load(lib_notify, "notify_notification_add_action", notify_notification_add_action);
load(lib_notify, "notify_notification_clear_actions", notify_notification_clear_actions);
load(lib_notify, "notify_notification_close", notify_notification_close);
load(lib_notify, "notify_notification_get_closed_reason", notify_notification_get_closed_reason);
}
} // namespace Libs
} // namespace Platform

View file

@ -0,0 +1,131 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop 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/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
extern "C" {
#undef signals
#include <gtk/gtk.h>
#define signals public
} // extern "C"
namespace Platform {
namespace Libs {
void startLibNotify();
constexpr gint NOTIFY_EXPIRES_DEFAULT = -1;
constexpr gint NOTIFY_EXPIRES_NEVER = 0;
struct NotifyNotification;
typedef enum {
NOTIFY_URGENCY_LOW,
NOTIFY_URGENCY_NORMAL,
NOTIFY_URGENCY_CRITICAL,
} NotifyUrgency;
using NotifyActionCallback = void (*)(NotifyNotification *notification, char *action, gpointer user_data);
using f_notify_init = gboolean (*)(const char *app_name);
extern f_notify_init notify_init;
using f_notify_uninit = void (*)(void);
extern f_notify_uninit notify_uninit;
using f_notify_is_initted = gboolean (*)(void);
extern f_notify_is_initted notify_is_initted;
//using f_notify_get_app_name = const char* (*)(void);
//extern f_notify_get_app_name notify_get_app_name;
//using f_notify_set_app_name = void (*)(const char *app_name);
//extern f_notify_set_app_name notify_set_app_name;
using f_notify_get_server_caps = GList* (*)(void);
extern f_notify_get_server_caps notify_get_server_caps;
using f_notify_get_server_info = gboolean (*)(char **ret_name, char **ret_vendor, char **ret_version, char **ret_spec_version);
extern f_notify_get_server_info notify_get_server_info;
using f_notify_notification_new = NotifyNotification* (*)(const char *summary, const char *body, const char *icon);
extern f_notify_notification_new notify_notification_new;
//using f_notify_notification_update = gboolean (*)(NotifyNotification *notification, const char *summary, const char *body, const char *icon);
//extern f_notify_notification_update notify_notification_update;
using f_notify_notification_show = gboolean (*)(NotifyNotification *notification, GError **error);
extern f_notify_notification_show notify_notification_show;
//using f_notify_notification_set_app_name = void (*)(NotifyNotification *notification, const char *app_name);
//extern f_notify_notification_set_app_name notify_notification_set_app_name;
using f_notify_notification_set_timeout = void (*)(NotifyNotification *notification, gint timeout);
extern f_notify_notification_set_timeout notify_notification_set_timeout;
//using f_notify_notification_set_category = void (*)(NotifyNotification *notification, const char *category);
//extern f_notify_notification_set_category notify_notification_set_category;
//using f_notify_notification_set_urgency = void (*)(NotifyNotification *notification, NotifyUrgency urgency);
//extern f_notify_notification_set_urgency notify_notification_set_urgency;
//using f_notify_notification_set_icon_from_pixbuf = void (*)(NotifyNotification *notification, GdkPixbuf *icon);
//extern f_notify_notification_set_icon_from_pixbuf notify_notification_set_icon_from_pixbuf;
using f_notify_notification_set_image_from_pixbuf = void (*)(NotifyNotification *notification, GdkPixbuf *pixbuf);
extern f_notify_notification_set_image_from_pixbuf notify_notification_set_image_from_pixbuf;
//using f_notify_notification_set_hint = void (*)(NotifyNotification *notification, const char *key, GVariant *value);
//extern f_notify_notification_set_hint notify_notification_set_hint;
//using f_notify_notification_set_hint_int32 = void (*)(NotifyNotification *notification, const char *key, gint value);
//extern f_notify_notification_set_hint_int32 notify_notification_set_hint_int32;
//using f_notify_notification_set_hint_uint32 = void (*)(NotifyNotification *notification, const char *key, guint value);
//extern f_notify_notification_set_hint_uint32 notify_notification_set_hint_uint32;
//using f_notify_notification_set_hint_double = void (*)(NotifyNotification *notification, const char *key, gdouble value);
//extern f_notify_notification_set_hint_double notify_notification_set_hint_double;
using f_notify_notification_set_hint_string = void (*)(NotifyNotification *notification, const char *key, const char *value);
extern f_notify_notification_set_hint_string notify_notification_set_hint_string;
//using f_notify_notification_set_hint_byte = void (*)(NotifyNotification *notification, const char *key, guchar value);
//extern f_notify_notification_set_hint_byte notify_notification_set_hint_byte;
//using f_notify_notification_set_hint_byte_array = void (*)(NotifyNotification *notification, const char *key, const guchar *value, gsize len);
//extern f_notify_notification_set_hint_byte_array notify_notification_set_hint_byte_array;
//using f_notify_notification_clear_hints = void (*)(NotifyNotification *notification);
//extern f_notify_notification_clear_hints notify_notification_clear_hints;
using f_notify_notification_add_action = void (*)(NotifyNotification *notification, const char *action, const char *label, NotifyActionCallback callback, gpointer user_data, GFreeFunc free_func);
extern f_notify_notification_add_action notify_notification_add_action;
using f_notify_notification_clear_actions = void (*)(NotifyNotification *notification);
extern f_notify_notification_clear_actions notify_notification_clear_actions;
using f_notify_notification_close = gboolean (*)(NotifyNotification *notification, GError **error);
extern f_notify_notification_close notify_notification_close;
using f_notify_notification_get_closed_reason = gint (*)(const NotifyNotification *notification);
extern f_notify_notification_get_closed_reason notify_notification_get_closed_reason;
} // namespace Libs
} // namespace Platform

View file

@ -22,6 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "platform/linux/linux_libs.h" #include "platform/linux/linux_libs.h"
#include "platform/linux/linux_gdk_helper.h" #include "platform/linux/linux_gdk_helper.h"
#include "platform/linux/linux_libnotify.h"
namespace Platform { namespace Platform {
namespace Libs { namespace Libs {
@ -92,10 +93,16 @@ bool setupGtkBase(QLibrary &lib_gtk) {
if (!load(lib_gtk, "g_type_check_instance_cast", g_type_check_instance_cast)) return false; if (!load(lib_gtk, "g_type_check_instance_cast", g_type_check_instance_cast)) return false;
if (!load(lib_gtk, "g_type_check_instance_is_a", g_type_check_instance_is_a)) return false; if (!load(lib_gtk, "g_type_check_instance_is_a", g_type_check_instance_is_a)) return false;
if (!load(lib_gtk, "g_signal_connect_data", g_signal_connect_data)) return false; if (!load(lib_gtk, "g_signal_connect_data", g_signal_connect_data)) return false;
if (!load(lib_gtk, "g_signal_handler_disconnect", g_signal_handler_disconnect)) return false;
if (!load(lib_gtk, "g_object_ref_sink", g_object_ref_sink)) return false; if (!load(lib_gtk, "g_object_ref_sink", g_object_ref_sink)) return false;
if (!load(lib_gtk, "g_object_unref", g_object_unref)) return false; if (!load(lib_gtk, "g_object_unref", g_object_unref)) return false;
if (!load(lib_gtk, "g_free", g_free)) return false; if (!load(lib_gtk, "g_free", g_free)) return false;
if (!load(lib_gtk, "g_list_foreach", g_list_foreach)) return false;
if (!load(lib_gtk, "g_list_free", g_list_free)) return false;
if (!load(lib_gtk, "g_list_free_full", g_list_free_full)) return false;
if (!load(lib_gtk, "g_error_free", g_error_free)) return false;
if (!load(lib_gtk, "g_slist_free", g_slist_free)) return false; if (!load(lib_gtk, "g_slist_free", g_slist_free)) return false;
DEBUG_LOG(("Library gtk functions loaded!")); DEBUG_LOG(("Library gtk functions loaded!"));
@ -169,12 +176,14 @@ f_gtk_dialog_run gtk_dialog_run = nullptr;
f_g_type_check_instance_cast g_type_check_instance_cast = nullptr; f_g_type_check_instance_cast g_type_check_instance_cast = nullptr;
f_g_type_check_instance_is_a g_type_check_instance_is_a = nullptr; f_g_type_check_instance_is_a g_type_check_instance_is_a = nullptr;
f_g_signal_connect_data g_signal_connect_data = nullptr; f_g_signal_connect_data g_signal_connect_data = nullptr;
f_g_signal_handler_disconnect g_signal_handler_disconnect = nullptr;
f_app_indicator_new app_indicator_new = nullptr; f_app_indicator_new app_indicator_new = nullptr;
f_app_indicator_set_status app_indicator_set_status = nullptr; f_app_indicator_set_status app_indicator_set_status = nullptr;
f_app_indicator_set_menu app_indicator_set_menu = nullptr; f_app_indicator_set_menu app_indicator_set_menu = nullptr;
f_app_indicator_set_icon_full app_indicator_set_icon_full = nullptr; f_app_indicator_set_icon_full app_indicator_set_icon_full = nullptr;
f_gdk_init_check gdk_init_check = nullptr; f_gdk_init_check gdk_init_check = nullptr;
f_gdk_pixbuf_new_from_data gdk_pixbuf_new_from_data = nullptr; f_gdk_pixbuf_new_from_data gdk_pixbuf_new_from_data = nullptr;
f_gdk_pixbuf_new_from_file gdk_pixbuf_new_from_file = nullptr;
f_gtk_status_icon_new_from_pixbuf gtk_status_icon_new_from_pixbuf = nullptr; f_gtk_status_icon_new_from_pixbuf gtk_status_icon_new_from_pixbuf = nullptr;
f_gtk_status_icon_set_from_pixbuf gtk_status_icon_set_from_pixbuf = nullptr; f_gtk_status_icon_set_from_pixbuf gtk_status_icon_set_from_pixbuf = nullptr;
f_gtk_status_icon_new_from_file gtk_status_icon_new_from_file = nullptr; f_gtk_status_icon_new_from_file gtk_status_icon_new_from_file = nullptr;
@ -191,6 +200,10 @@ f_g_object_ref_sink g_object_ref_sink = nullptr;
f_g_object_unref g_object_unref = nullptr; f_g_object_unref g_object_unref = nullptr;
f_g_idle_add g_idle_add = nullptr; f_g_idle_add g_idle_add = nullptr;
f_g_free g_free = nullptr; f_g_free g_free = nullptr;
f_g_list_foreach g_list_foreach = nullptr;
f_g_list_free g_list_free = nullptr;
f_g_list_free_full g_list_free_full = nullptr;
f_g_error_free g_error_free = nullptr;
f_g_slist_free g_slist_free = nullptr; f_g_slist_free g_slist_free = nullptr;
#ifndef TDESKTOP_DISABLE_UNITY_INTEGRATION #ifndef TDESKTOP_DISABLE_UNITY_INTEGRATION
f_unity_launcher_entry_set_count unity_launcher_entry_set_count = nullptr; f_unity_launcher_entry_set_count unity_launcher_entry_set_count = nullptr;
@ -233,6 +246,7 @@ void start() {
if (gtkLoaded) { if (gtkLoaded) {
load(lib_gtk, "gdk_init_check", gdk_init_check); load(lib_gtk, "gdk_init_check", gdk_init_check);
load(lib_gtk, "gdk_pixbuf_new_from_data", gdk_pixbuf_new_from_data); load(lib_gtk, "gdk_pixbuf_new_from_data", gdk_pixbuf_new_from_data);
load(lib_gtk, "gdk_pixbuf_new_from_file", gdk_pixbuf_new_from_file);
load(lib_gtk, "gtk_status_icon_new_from_pixbuf", gtk_status_icon_new_from_pixbuf); load(lib_gtk, "gtk_status_icon_new_from_pixbuf", gtk_status_icon_new_from_pixbuf);
load(lib_gtk, "gtk_status_icon_set_from_pixbuf", gtk_status_icon_set_from_pixbuf); load(lib_gtk, "gtk_status_icon_set_from_pixbuf", gtk_status_icon_set_from_pixbuf);
load(lib_gtk, "gtk_status_icon_new_from_file", gtk_status_icon_new_from_file); load(lib_gtk, "gtk_status_icon_new_from_file", gtk_status_icon_new_from_file);
@ -266,6 +280,10 @@ void start() {
load(lib_unity, "unity_launcher_entry_set_count_visible", unity_launcher_entry_set_count_visible); load(lib_unity, "unity_launcher_entry_set_count_visible", unity_launcher_entry_set_count_visible);
} }
#endif // TDESKTOP_DISABLE_UNITY_INTEGRATION #endif // TDESKTOP_DISABLE_UNITY_INTEGRATION
if (gtkLoaded) {
startLibNotify();
}
} }
} // namespace Libs } // namespace Libs

View file

@ -247,14 +247,17 @@ extern f_gtk_dialog_run gtk_dialog_run;
typedef gulong (*f_g_signal_connect_data)(gpointer instance, const gchar *detailed_signal, GCallback c_handler, gpointer data, GClosureNotify destroy_data, GConnectFlags connect_flags); typedef gulong (*f_g_signal_connect_data)(gpointer instance, const gchar *detailed_signal, GCallback c_handler, gpointer data, GClosureNotify destroy_data, GConnectFlags connect_flags);
extern f_g_signal_connect_data g_signal_connect_data; extern f_g_signal_connect_data g_signal_connect_data;
inline gulong g_signal_connect_helper(gpointer instance, const gchar *detailed_signal, GCallback c_handler, gpointer data) { inline gulong g_signal_connect_helper(gpointer instance, const gchar *detailed_signal, GCallback c_handler, gpointer data, GClosureNotify destroy_data = nullptr) {
return g_signal_connect_data(instance, detailed_signal, c_handler, data, NULL, (GConnectFlags)0); return g_signal_connect_data(instance, detailed_signal, c_handler, data, destroy_data, (GConnectFlags)0);
} }
inline gulong g_signal_connect_swapped_helper(gpointer instance, const gchar *detailed_signal, GCallback c_handler, gpointer data) { inline gulong g_signal_connect_swapped_helper(gpointer instance, const gchar *detailed_signal, GCallback c_handler, gpointer data, GClosureNotify destroy_data = nullptr) {
return g_signal_connect_data(instance, detailed_signal, c_handler, data, NULL, G_CONNECT_SWAPPED); return g_signal_connect_data(instance, detailed_signal, c_handler, data, destroy_data, G_CONNECT_SWAPPED);
} }
typedef void (*f_g_signal_handler_disconnect)(gpointer instance, gulong handler_id);
extern f_g_signal_handler_disconnect g_signal_handler_disconnect;
typedef AppIndicator* (*f_app_indicator_new)(const gchar *id, const gchar *icon_name, AppIndicatorCategory category); typedef AppIndicator* (*f_app_indicator_new)(const gchar *id, const gchar *icon_name, AppIndicatorCategory category);
extern f_app_indicator_new app_indicator_new; extern f_app_indicator_new app_indicator_new;
@ -273,6 +276,9 @@ extern f_gdk_init_check gdk_init_check;
typedef GdkPixbuf* (*f_gdk_pixbuf_new_from_data)(const guchar *data, GdkColorspace colorspace, gboolean has_alpha, int bits_per_sample, int width, int height, int rowstride, GdkPixbufDestroyNotify destroy_fn, gpointer destroy_fn_data); typedef GdkPixbuf* (*f_gdk_pixbuf_new_from_data)(const guchar *data, GdkColorspace colorspace, gboolean has_alpha, int bits_per_sample, int width, int height, int rowstride, GdkPixbufDestroyNotify destroy_fn, gpointer destroy_fn_data);
extern f_gdk_pixbuf_new_from_data gdk_pixbuf_new_from_data; extern f_gdk_pixbuf_new_from_data gdk_pixbuf_new_from_data;
typedef GdkPixbuf* (*f_gdk_pixbuf_new_from_file)(const gchar *filename, GError **error);
extern f_gdk_pixbuf_new_from_file gdk_pixbuf_new_from_file;
typedef GtkStatusIcon* (*f_gtk_status_icon_new_from_pixbuf)(GdkPixbuf *pixbuf); typedef GtkStatusIcon* (*f_gtk_status_icon_new_from_pixbuf)(GdkPixbuf *pixbuf);
extern f_gtk_status_icon_new_from_pixbuf gtk_status_icon_new_from_pixbuf; extern f_gtk_status_icon_new_from_pixbuf gtk_status_icon_new_from_pixbuf;
@ -321,6 +327,18 @@ extern f_g_idle_add g_idle_add;
typedef void (*f_g_free)(gpointer mem); typedef void (*f_g_free)(gpointer mem);
extern f_g_free g_free; extern f_g_free g_free;
typedef void (*f_g_list_foreach)(GList *list, GFunc func, gpointer user_data);
extern f_g_list_foreach g_list_foreach;
typedef void (*f_g_list_free)(GList *list);
extern f_g_list_free g_list_free;
typedef void (*f_g_list_free_full)(GList *list, GDestroyNotify free_func);
extern f_g_list_free_full g_list_free_full;
typedef void (*f_g_error_free)(GError *error);
extern f_g_error_free g_error_free;
typedef void (*f_g_slist_free)(GSList *list); typedef void (*f_g_slist_free)(GSList *list);
extern f_g_slist_free g_slist_free; extern f_g_slist_free g_slist_free;

View file

@ -22,6 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "platform/linux/main_window_linux.h" #include "platform/linux/main_window_linux.h"
#include "platform/linux/linux_libs.h" #include "platform/linux/linux_libs.h"
#include "platform/platform_notifications_manager.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "application.h" #include "application.h"
#include "lang.h" #include "lang.h"
@ -63,22 +64,11 @@ gboolean _trayIconResized(GtkStatusIcon *status_icon, gint size, gpointer popup_
return FALSE; return FALSE;
} }
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
#define QT_RED 3
#define QT_GREEN 2
#define QT_BLUE 1
#define QT_ALPHA 0
#else
#define QT_RED 0 #define QT_RED 0
#define QT_GREEN 1 #define QT_GREEN 1
#define QT_BLUE 2 #define QT_BLUE 2
#define QT_ALPHA 3 #define QT_ALPHA 3
#endif
#define GTK_RED 2 #define GTK_RED 2
#define GTK_GREEN 1 #define GTK_GREEN 1
#define GTK_BLUE 0 #define GTK_BLUE 0
@ -262,13 +252,19 @@ void MainWindow::psSetupTrayIcon() {
trayIcon->setToolTip(str_const_toString(AppName)); trayIcon->setToolTip(str_const_toString(AppName));
connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(toggleTray(QSystemTrayIcon::ActivationReason)), Qt::UniqueConnection); 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())); connect(trayIcon, SIGNAL(messageClicked()), this, SLOT(showFromTray()));
App::wnd()->updateTrayMenu(); App::wnd()->updateTrayMenu();
} }
psUpdateCounter(); psUpdateCounter();
trayIcon->show(); trayIcon->show();
psUpdateDelegate();
} }
} }
@ -367,6 +363,10 @@ void MainWindow::psUpdateCounter() {
} }
} }
bool MainWindow::psHasNativeNotifications() {
return Notifications::supported();
}
void MainWindow::LibsLoaded() { void MainWindow::LibsLoaded() {
QString cdesktop = QString(getenv("XDG_CURRENT_DESKTOP")).toLower(); QString cdesktop = QString(getenv("XDG_CURRENT_DESKTOP")).toLower();
noQtTrayIcon = (cdesktop == qstr("pantheon")) || (cdesktop == qstr("gnome")); noQtTrayIcon = (cdesktop == qstr("pantheon")) || (cdesktop == qstr("gnome"));
@ -430,9 +430,6 @@ void MainWindow::LibsLoaded() {
#endif // TDESKTOP_DISABLE_UNITY_INTEGRATION #endif // TDESKTOP_DISABLE_UNITY_INTEGRATION
} }
void MainWindow::psUpdateDelegate() {
}
void MainWindow::psInitSize() { void MainWindow::psInitSize() {
setMinimumWidth(st::wndMinWidth); setMinimumWidth(st::wndMinWidth);
setMinimumHeight(st::wndMinHeight); setMinimumHeight(st::wndMinHeight);
@ -663,18 +660,6 @@ void MainWindow::psUpdateMargins() {
void MainWindow::psFlash() { void MainWindow::psFlash() {
} }
void MainWindow::psActivateNotify(NotifyWindow *w) {
}
void MainWindow::psClearNotifies(PeerId peerId) {
}
void MainWindow::psNotifyShown(NotifyWindow *w) {
}
void MainWindow::psPlatformNotify(HistoryItem *item, int32 fwdCount) {
}
MainWindow::~MainWindow() { MainWindow::~MainWindow() {
if (_trayIcon) { if (_trayIcon) {
Libs::g_object_unref(_trayIcon); Libs::g_object_unref(_trayIcon);

View file

@ -22,8 +22,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "window/main_window.h" #include "window/main_window.h"
class NotifyWindow;
namespace Platform { namespace Platform {
class MainWindow : public Window::MainWindow { class MainWindow : public Window::MainWindow {
@ -58,16 +56,9 @@ public:
return posInited; return posInited;
} }
void psActivateNotify(NotifyWindow *w);
void psClearNotifies(PeerId peerId = 0);
void psNotifyShown(NotifyWindow *w);
void psPlatformNotify(HistoryItem *item, int32 fwdCount);
void psUpdateCounter(); void psUpdateCounter();
bool psHasNativeNotifications() { bool psHasNativeNotifications();
return false;
}
virtual QImage iconWithCounter(int size, int count, style::color bg, bool smallIcon) = 0; virtual QImage iconWithCounter(int size, int count, style::color bg, bool smallIcon) = 0;
@ -76,8 +67,6 @@ public:
~MainWindow(); ~MainWindow();
public slots: public slots:
void psUpdateDelegate();
void psSavePosition(Qt::WindowState state = Qt::WindowActive); void psSavePosition(Qt::WindowState state = Qt::WindowActive);
void psShowTrayMenu(); void psShowTrayMenu();

Some files were not shown because too many files have changed in this diff Show more