/**************************************************************** * RetroShare is distributed under the following license: * * Copyright (C) 2006, 2007 crypton * * This program 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 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. ****************************************************************/ #include #include #include #include #include #include "EventReceiver.h" #include "gui/MainWindow.h" #include "gui/RetroShareLink.h" #ifdef WINDOWS_SYS #include #define OP_RETROSHARELINK 12000 #endif struct SharedMemoryInfo { #ifdef WINDOWS_SYS /* Store handle of the event window */ WId wid; #else long dummy; #endif }; EventReceiver::EventReceiver() { #ifdef WINDOWS_SYS setWindowTitle("RetroShare EventReceiver"); #endif /* Build unique name for the running instance */ QString name = QString("RetroShare-%1::EventReceiver").arg(QCoreApplication::applicationDirPath()); sharedMemory.setKey(name); } EventReceiver::~EventReceiver() { sharedMemory.detach(); } bool EventReceiver::start() { if (!sharedMemory.create(sizeof(SharedMemoryInfo))) { std::cerr << "EventReceiver::start() Cannot create shared memory !" << sharedMemory.errorString().toStdString() << std::endl; return false; } bool result = true; if (sharedMemory.lock()) { SharedMemoryInfo *info = (SharedMemoryInfo*) sharedMemory.data(); if (info) { #ifdef WINDOWS_SYS info->wid = winId(); #else info->dummy = 0; #endif } else { result = false; std::cerr << "EventReceiver::start() Shared memory returns a NULL pointer!" << std::endl; } sharedMemory.unlock(); } else { result = false; std::cerr << "EventReceiver::start() Cannot lock shared memory !" << std::endl; } return result; } bool EventReceiver::sendRetroShareLink(const QString& link) { if (!sharedMemory.attach()) { /* No running instance found */ return false; } bool result = true; if (sharedMemory.lock()) { SharedMemoryInfo *info = (SharedMemoryInfo*) sharedMemory.data(); if (info) { #ifdef WINDOWS_SYS if (info->wid) { QByteArray linkData(link.toUtf8()); COPYDATASTRUCT send; send.dwData = OP_RETROSHARELINK; send.cbData = link.length() * sizeof(char); send.lpData = (void*) linkData.constData(); SendMessage((HWND) info->wid, WM_COPYDATA, (WPARAM) 0, (LPARAM) (PCOPYDATASTRUCT) &send); } else { result = false; } #else Q_UNUSED(link); QMessageBox mb(QMessageBox::Critical, "RetroShare", QObject::tr("Start with a RetroShare link is only supported for Windows."), QMessageBox::Ok); mb.setWindowIcon(QIcon(":/images/rstray3.png")); mb.exec(); result = false; #endif } else { result = false; std::cerr << "EventReceiver::sendRetroShareLink() Cannot lock shared memory !" << std::endl; } sharedMemory.unlock(); } else { result = false; std::cerr << "EventReceiver::start() Cannot lock shared memory !" << std::endl; } sharedMemory.detach(); return result; } #ifdef WINDOWS_SYS bool EventReceiver::winEvent(MSG* message, long* result) { if (message->message == WM_COPYDATA ) { /* Extract the struct from lParam */ COPYDATASTRUCT *data = (COPYDATASTRUCT*) message->lParam; if (data && data->dwData == OP_RETROSHARELINK) { received(QString::fromUtf8((const char*) data->lpData, data->cbData)); /* Keep the event from Qt */ *result = 0; return true; } } /* Give the event to Qt */ return false; } #endif #ifdef WINDOWS_SYS //void SetForegroundWindowInternal(HWND hWnd) //{ // if (!::IsWindow(hWnd)) return; // // relation time of SetForegroundWindow lock // DWORD lockTimeOut = 0; // HWND hCurrWnd = ::GetForegroundWindow(); // DWORD dwThisTID = ::GetCurrentThreadId(), // dwCurrTID = ::GetWindowThreadProcessId(hCurrWnd,0); // // we need to bypass some limitations from Microsoft :) // if (dwThisTID != dwCurrTID) { // ::AttachThreadInput(dwThisTID, dwCurrTID, TRUE); // ::SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT,0,&lockTimeOut,0); // ::SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,0,0,SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE); // ::AllowSetForegroundWindow(ASFW_ANY); // } // ::SetForegroundWindow(hWnd); // if(dwThisTID != dwCurrTID) { // ::SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,0,(PVOID)lockTimeOut,SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE); // ::AttachThreadInput(dwThisTID, dwCurrTID, FALSE); // } //} void SetForegroundWindowInternal(HWND hWnd) { if (!::IsWindow(hWnd)) return; BYTE keyState[256] = {0}; // to unlock SetForegroundWindow we need to imitate Alt pressing if (::GetKeyboardState((LPBYTE)&keyState)) { if(!(keyState[VK_MENU] & 0x80)) { ::keybd_event(VK_MENU, 0, KEYEVENTF_EXTENDEDKEY | 0, 0); } } ::SetForegroundWindow(hWnd); if (::GetKeyboardState((LPBYTE)&keyState)) { if(!(keyState[VK_MENU] & 0x80)) { ::keybd_event(VK_MENU, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0); } } } #endif void EventReceiver::received(const QString &url) { RetroShareLink link(url); if (link.valid()) { MainWindow *window = MainWindow::getInstance(); if (window) { window->show(); window->raise(); #ifdef WINDOWS_SYS SetForegroundWindowInternal(window->winId()); #endif } emit linkReceived(link.toUrl()); } }