win open with menu done, lang string for 0.7.9 added

This commit is contained in:
John Preston 2015-01-23 00:59:07 +03:00
parent 6302eeeb2b
commit 781c531964
6 changed files with 212 additions and 20 deletions

View file

@ -452,11 +452,17 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_new_authorization" = "{name},\nWe detected a login into your account from a new device on {day}, {date} at {time}\n\nDevice: {device}\nLocation: {location}\n\nIf this wasn't you, you can go to Settings — Terminate other sessions.\n\nThanks,\nThe Telegram Team";
"lng_new_version7007" = "Telegram Desktop was updated to version {version}\n\n — Tray icon added in Ubuntu\n\nFull version history is available here:\n{link}";
"lng_new_version7009" = "Telegram Desktop was updated to version {version}\n\n — Added Korean language\n — Quick «open with» menu on Windows and OS X\n\nFull version history is available here:\n{link}";
"lng_new_version7006_appstore" = "Telegram Desktop was updated to version {version}\n\n — Stickers support\n — Local caching for voice messages\n — Added new languages\n\nFull version history is available here:\n{link}";
// Wnd specific
"lng_wnd_choose_program_menu" = "Choose default program...";
// Mac specific
"lng_mac_choose_program_menu" = "Other...";
"lng_mac_choose_app" = "Choose Application";
"lng_mac_choose_text" = "Choose an application to open the document \"{file}\".";
"lng_mac_enable_filter" = "Enable:";

View file

@ -699,8 +699,8 @@ void Application::startApp() {
QNetworkProxyFactory::setUseSystemConfiguration(true);
if (Local::oldMapVersion() < AppVersion) {
psRegisterCustomScheme();
if (Local::oldMapVersion() && Local::oldMapVersion() < 7007 && (cPlatform() == dbipLinux32 || cPlatform() == dbipLinux64)) {
QString versionFeatures(lng_new_version7007(lt_version, QString::fromStdWString(AppVersionStr), lt_link, qsl("https://desktop.telegram.org/#changelog")));
if (Local::oldMapVersion() && Local::oldMapVersion() < 7009) {
QString versionFeatures(lng_new_version7009(lt_version, QString::fromStdWString(AppVersionStr), lt_link, qsl("https://desktop.telegram.org/#changelog")));
if (!versionFeatures.isEmpty()) {
window->serviceNotification(versionFeatures);
}

View file

@ -685,6 +685,8 @@ void MTPautoConnection::onSocketDisconnected() {
}
void MTPautoConnection::sendData(mtpBuffer &buffer) {
if (status == FinishedWork) return;
if (buffer.size() < 3) {
LOG(("TCP Error: writing bad packet, len = %1").arg(buffer.size() * sizeof(mtpPrime)));
TCP_LOG(("TCP Error: bad packet %1").arg(mb(&buffer[0], buffer.size() * sizeof(mtpPrime)).str()));
@ -722,6 +724,8 @@ void MTPautoConnection::httpSend(mtpBuffer &buffer) {
}
void MTPautoConnection::disconnectFromServer() {
if (status == FinishedWork) return;
Requests copy = requests;
requests.clear();
for (Requests::const_iterator i = copy.cbegin(), e = copy.cend(); i != e; ++i) {
@ -737,7 +741,7 @@ void MTPautoConnection::disconnectFromServer() {
sock.close();
httpStartTimer.stop();
status = WaitingBoth;
status = FinishedWork;
}
void MTPautoConnection::connectToServer(const QString &addr, int32 port) {
@ -758,10 +762,12 @@ void MTPautoConnection::connectToServer(const QString &addr, int32 port) {
}
bool MTPautoConnection::isConnected() {
return !address.isEmpty();
return status != FinishedWork && !address.isEmpty();
}
void MTPautoConnection::requestFinished(QNetworkReply *reply) {
if (status == FinishedWork) return;
reply->deleteLater();
if (reply->error() == QNetworkReply::NoError) {
requests.remove(reply);
@ -820,6 +826,8 @@ void MTPautoConnection::requestFinished(QNetworkReply *reply) {
}
void MTPautoConnection::socketPacket(mtpPrime *packet, uint32 size) {
if (status == FinishedWork) return;
mtpBuffer data = _handleTcpResponse(packet, size);
if (data.size() == 1) {
if (status == WaitingBoth) {
@ -884,6 +892,8 @@ QString MTPautoConnection::transport() const {
}
void MTPautoConnection::socketError(QAbstractSocket::SocketError e) {
if (status == FinishedWork) return;
_handleTcpError(e, sock);
if (status == WaitingBoth) {
status = WaitingHttp;
@ -2498,8 +2508,8 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt
}
if (badTime) {
DEBUG_LOG(("Message Error: bad time in updates cons"));
return -1;
DEBUG_LOG(("Message Error: bad time in updates cons, must create new session"));
return -2;
}
mtpBuffer update(end - from);

View file

@ -213,6 +213,7 @@ private:
HttpReady,
UsingHttp,
UsingTcp,
FinishedWork
};
Status status;
MTPint128 tcpNonce, httpNonce;

View file

@ -520,7 +520,7 @@ int64 objc_idleTime() { // taken from https://github.com/trueinteractions/tint/i
}
[menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
}
NSMenuItem *item = [menu insertItemWithTitle:@"Other..." action:@selector(itemChosen:) keyEquivalent:@"" atIndex:index++];
NSMenuItem *item = [menu insertItemWithTitle:objc_lang(lng_mac_choose_program_menu).s() action:@selector(itemChosen:) keyEquivalent:@"" atIndex:index++];
[item setTarget:self];
[menu popUpMenuPositioningItem:nil atLocation:CGPointMake(x, y) inView:nil];

View file

@ -25,6 +25,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
#include <Shobjidl.h>
#include <dbghelp.h>
#include <shellapi.h>
#include <Shlwapi.h>
#include <Strsafe.h>
#include <shlobj.h>
#include <Windowsx.h>
@ -56,6 +57,7 @@ namespace {
bool frameless = true;
bool useDWM = false;
bool useTheme = false;
bool useOpenWith = false;
bool useOpenAs = false;
bool themeInited = false;
bool finished = true;
@ -605,22 +607,31 @@ namespace {
QColor _shActive(0, 0, 0), _shInactive(0, 0, 0);
typedef BOOL (FAR STDAPICALLTYPE *f_dwmDefWindowProc)(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, _Out_ LRESULT *plResult);
f_dwmDefWindowProc dwmDefWindowProc;
f_dwmDefWindowProc dwmDefWindowProc = 0;
typedef HRESULT (FAR STDAPICALLTYPE *f_dwmSetWindowAttribute)(HWND hWnd, DWORD dwAttribute, _In_ LPCVOID pvAttribute, DWORD cbAttribute);
f_dwmSetWindowAttribute dwmSetWindowAttribute;
f_dwmSetWindowAttribute dwmSetWindowAttribute = 0;
typedef HRESULT (FAR STDAPICALLTYPE *f_dwmExtendFrameIntoClientArea)(HWND hWnd, const MARGINS *pMarInset);
f_dwmExtendFrameIntoClientArea dwmExtendFrameIntoClientArea;
f_dwmExtendFrameIntoClientArea dwmExtendFrameIntoClientArea = 0;
typedef HRESULT (FAR STDAPICALLTYPE *f_setWindowTheme)(HWND hWnd, LPCWSTR pszSubAppName, LPCWSTR pszSubIdList);
f_setWindowTheme setWindowTheme;
f_setWindowTheme setWindowTheme = 0;
typedef HRESULT (FAR STDAPICALLTYPE *f_openAs_RunDLL)(HWND hWnd, HINSTANCE hInstance, LPCWSTR lpszCmdLine, int nCmdShow);
f_openAs_RunDLL openAs_RunDLL;
f_openAs_RunDLL openAs_RunDLL = 0;
typedef HRESULT (FAR STDAPICALLTYPE *f_shOpenWithDialog)(HWND hwndParent, const OPENASINFO *poainfo);
f_shOpenWithDialog shOpenWithDialog;
f_shOpenWithDialog shOpenWithDialog = 0;
typedef HRESULT (FAR STDAPICALLTYPE *f_shAssocEnumHandlers)(PCWSTR pszExtra, ASSOC_FILTER afFilter, IEnumAssocHandlers **ppEnumHandler);
f_shAssocEnumHandlers shAssocEnumHandlers = 0;
typedef HRESULT(FAR STDAPICALLTYPE *f_shCreateItemFromParsingName)(PCWSTR pszPath, IBindCtx *pbc, REFIID riid, void **ppv);
f_shCreateItemFromParsingName shCreateItemFromParsingName = 0;
typedef HRESULT(FAR STDAPICALLTYPE *f_shLoadIndirectString)(LPCWSTR pszSource, LPWSTR pszOutBuf, UINT cchOutBuf, void **ppvReserved);
f_shLoadIndirectString shLoadIndirectString = 0;
template <typename TFunction>
bool loadFunction(HINSTANCE dll, LPCSTR name, TFunction &func) {
@ -638,7 +649,7 @@ namespace {
frameless = !useDWM;
setupUx();
setupOpenAs();
setupShell();
}
void setupDWM() {
HINSTANCE procId = LoadLibrary(L"DWMAPI.DLL");
@ -654,9 +665,20 @@ namespace {
if (!loadFunction(procId, "SetWindowTheme", setWindowTheme)) return;
useTheme = true;
}
void setupOpenAs() {
void setupShell() {
HINSTANCE procId = LoadLibrary(L"SHELL32.DLL");
setupOpenWith(procId);
setupOpenAs(procId);
}
void setupOpenWith(HINSTANCE procId) {
if (!loadFunction(procId, "SHAssocEnumHandlers", shAssocEnumHandlers)) return;
if (!loadFunction(procId, "SHCreateItemFromParsingName", shCreateItemFromParsingName)) return;
useOpenWith = true;
HINSTANCE otherProcId = LoadLibrary(L"SHLWAPI.DLL");
if (otherProcId) loadFunction(otherProcId, "SHLoadIndirectString", shLoadIndirectString);
}
void setupOpenAs(HINSTANCE procId) {
if (!loadFunction(procId, "SHOpenWithDialog", shOpenWithDialog) && !loadFunction(procId, "OpenAs_RunDLLW", openAs_RunDLL)) return;
useOpenAs = true;
}
@ -998,6 +1020,7 @@ void PsMainWindow::psUpdateWorkmode() {
}
HICON qt_pixmapToWinHICON(const QPixmap &);
HBITMAP qt_pixmapToWinHBITMAP(const QPixmap &, int hbitmapFormat);
static HICON _qt_createHIcon(const QIcon &icon, int xSize, int ySize) {
if (!icon.isNull()) {
const QPixmap pm = icon.pixmap(icon.actualSize(QSize(xSize, ySize)));
@ -2170,6 +2193,162 @@ void psPostprocessFile(const QString &name) {
}
}
namespace {
struct OpenWithApp {
OpenWithApp(const QString &name, HBITMAP icon, IAssocHandler *handler) : name(name), icon(icon), handler(handler) {
}
OpenWithApp(const QString &name, IAssocHandler *handler) : name(name), icon(0), handler(handler) {
}
void destroy() {
if (icon) DeleteBitmap(icon);
if (handler) handler->Release();
}
QString name;
HBITMAP icon;
IAssocHandler *handler;
};
bool OpenWithAppLess(const OpenWithApp &a, const OpenWithApp &b) {
return a.name < b.name;
}
HBITMAP _iconToBitmap(LPWSTR icon, int iconindex) {
if (!icon) return 0;
WCHAR tmpIcon[4096];
if (icon[0] == L'@' && shLoadIndirectString && SUCCEEDED(shLoadIndirectString(icon, tmpIcon, 4096, 0))) {
icon = tmpIcon;
}
int32 w = GetSystemMetrics(SM_CXSMICON), h = GetSystemMetrics(SM_CYSMICON);
HICON ico = ExtractIcon(0, icon, iconindex);
if (!ico) {
if (!iconindex) { // try to read image
QImage img(QString::fromWCharArray(icon));
if (!img.isNull()) {
return qt_pixmapToWinHBITMAP(QPixmap::fromImage(img.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)), /* HBitmapAlpha */ 2);
}
}
return 0;
}
HDC screenDC = GetDC(0), hdc = CreateCompatibleDC(screenDC);
HBITMAP result = CreateCompatibleBitmap(screenDC, w, h);
HGDIOBJ was = SelectObject(hdc, result);
DrawIconEx(hdc, 0, 0, ico, w, h, 0, NULL, DI_NORMAL);
SelectObject(hdc, was);
DeleteDC(hdc);
ReleaseDC(0, screenDC);
DestroyIcon(ico);
return (HBITMAP)CopyImage(result, IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE | LR_CREATEDIBSECTION);
// return result;
}
}
bool psShowOpenWithMenu(int x, int y, const QString &file) {
if (!useOpenWith || !App::wnd()) return false;
bool result = false;
QList<OpenWithApp> handlers;
IShellItem* pItem = nullptr;
if (SUCCEEDED(shCreateItemFromParsingName(QDir::toNativeSeparators(file).toStdWString().c_str(), nullptr, IID_PPV_ARGS(&pItem)))) {
IEnumAssocHandlers *assocHandlers = 0;
if (SUCCEEDED(pItem->BindToHandler(nullptr, BHID_EnumAssocHandlers, IID_PPV_ARGS(&assocHandlers)))) {
HRESULT hr = S_FALSE;
do
{
IAssocHandler *handler = 0;
ULONG ulFetched = 0;
hr = assocHandlers->Next(1, &handler, &ulFetched);
if (FAILED(hr) || hr == S_FALSE || !ulFetched) break;
LPWSTR name = 0;
if (SUCCEEDED(handler->GetUIName(&name))) {
LPWSTR icon = 0;
int iconindex = 0;
if (SUCCEEDED(handler->GetIconLocation(&icon, &iconindex)) && icon) {
handlers.push_back(OpenWithApp(QString::fromWCharArray(name), _iconToBitmap(icon, iconindex), handler));
CoTaskMemFree(icon);
} else {
handlers.push_back(OpenWithApp(QString::fromWCharArray(name), handler));
}
CoTaskMemFree(name);
} else {
handler->Release();
}
} while (hr != S_FALSE);
assocHandlers->Release();
}
if (!handlers.isEmpty()) {
HMENU menu = CreatePopupMenu();
std::sort(handlers.begin(), handlers.end(), OpenWithAppLess);
for (int32 i = 0, l = handlers.size(); i < l; ++i) {
MENUITEMINFO menuInfo = { 0 };
menuInfo.cbSize = sizeof(menuInfo);
menuInfo.fMask = MIIM_STRING | MIIM_DATA | MIIM_ID;
menuInfo.fType = MFT_STRING;
menuInfo.wID = i + 1;
if (handlers.at(i).icon) {
menuInfo.fMask |= MIIM_BITMAP;
menuInfo.hbmpItem = handlers.at(i).icon;
}
QString name = handlers.at(i).name;
if (name.size() > 512) name = name.mid(0, 512);
WCHAR nameArr[1024];
name.toWCharArray(nameArr);
nameArr[name.size()] = 0;
menuInfo.dwTypeData = nameArr;
InsertMenuItem(menu, GetMenuItemCount(menu), TRUE, &menuInfo);
}
MENUITEMINFO sepInfo = { 0 };
sepInfo.cbSize = sizeof(sepInfo);
sepInfo.fMask = MIIM_STRING | MIIM_DATA;
sepInfo.fType = MFT_SEPARATOR;
InsertMenuItem(menu, GetMenuItemCount(menu), true, &sepInfo);
MENUITEMINFO menuInfo = { 0 };
menuInfo.cbSize = sizeof(menuInfo);
menuInfo.fMask = MIIM_STRING | MIIM_DATA | MIIM_ID;
menuInfo.fType = MFT_STRING;
menuInfo.wID = handlers.size() + 1;
QString name = lang(lng_wnd_choose_program_menu);
if (name.size() > 512) name = name.mid(0, 512);
WCHAR nameArr[1024];
name.toWCharArray(nameArr);
nameArr[name.size()] = 0;
menuInfo.dwTypeData = nameArr;
InsertMenuItem(menu, GetMenuItemCount(menu), TRUE, &menuInfo);
int sel = TrackPopupMenu(menu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_LEFTBUTTON | TPM_RETURNCMD, x, y, 0, App::wnd()->psHwnd(), 0);
DestroyMenu(menu);
if (sel > 0) {
if (sel <= handlers.size()) {
IDataObject *dataObj = 0;
IEnumAssocHandlers *assocHandlers = 0;
if (SUCCEEDED(pItem->BindToHandler(nullptr, BHID_DataObject, IID_PPV_ARGS(&dataObj))) && dataObj) {
handlers.at(sel - 1).handler->Invoke(dataObj);
dataObj->Release();
result = true;
}
}
} else {
result = true;
}
for (int i = 0, l = handlers.size(); i < l; ++i) {
handlers[i].destroy();
}
}
pItem->Release();
}
return result;
}
void psOpenFile(const QString &name, bool openWith) {
std::wstring wname = QDir::toNativeSeparators(name).toStdWString();
@ -2305,10 +2484,6 @@ void psExecTelegram() {
}
}
bool psShowOpenWithMenu(int x, int y, const QString &file) {
return false;
}
void _manageAppLnk(bool create, bool silent, int path_csidl, const wchar_t *args, const wchar_t *description) {
WCHAR startupFolder[MAX_PATH];
HRESULT hres = SHGetFolderPath(0, path_csidl, 0, SHGFP_TYPE_CURRENT, startupFolder);