static void kvi_ipcLoadAtoms() { if(g_bIpcAtomsLoaded) return; g_bIpcAtomsLoaded = true; g_uLocalInstanceId = (kvi_u64_t)::getpid(); kvi_sentinel_id.sprintf("pane tonno e mistero - %d", getuid()); kvi_atom_ipc_sentinel_window = XInternAtom(kvi_ipc_get_xdisplay(), "XA_KVI4_IPC_SENTINEL_WINDOW", False); kvi_atom_ipc_remote_command = XInternAtom(kvi_ipc_get_xdisplay(), "XA_KVI4_IPC_REMOTE_COMMAND", False); kvi_atom_ipc_remote_message = XInternAtom(kvi_ipc_get_xdisplay(), "XA_KVI4_IPC_REMOTE_MESSAGE", False); }
bool kvi_sendIpcMessage(const char * message) { #if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW) HWND hSentinel = kvi_win_findIpcSentinel(); if(hSentinel != NULL) { COPYDATASTRUCT cpd; cpd.cbData = strlen(message)+1; cpd.dwData = KVI_WINDOWS_IPC_MESSAGE; cpd.lpData = (void *)message; DWORD_PTR dwResult; if(!::SendMessageTimeout(hSentinel,WM_COPYDATA,(WPARAM)NULL,(LPARAM)&cpd,SMTO_BLOCK,1000,&dwResult)) { qDebug("Failed to send IPC message: error code 0x%x",::GetLastError()); } return true; } #else #if defined(COMPILE_X11_SUPPORT) && defined(COMPILE_QX11INFO_SUPPORT) kvi_ipcLoadAtoms(); Window sentinel = kvi_x11_findIpcSentinel(kvi_ipc_get_xrootwin()); if(sentinel != 0) { // XChangeProperty(kvi_ipc_get_xdisplay(),sentinel,kvi_atom_ipc_remote_command,XA_STRING,8, // PropModeReplace,(const unsigned char *)message,kvi_strLen(message)); kvi_ipcSetRemoteCommand(sentinel,message); #if (QT_VERSION < 0x050000) XEvent e; KviMemory::set(&e,0,sizeof(XEvent)); e.type = ClientMessage; e.xclient.display = kvi_ipc_get_xdisplay(); e.xclient.window = sentinel; e.xclient.message_type = kvi_atom_ipc_remote_message; e.xclient.format = 8; Status ret = XSendEvent(kvi_ipc_get_xdisplay(),sentinel,False,0,&e); #else // On Qt5 the ClientMessage events aren't propagated at all.. we have to rely on the property change only #endif return true; } #endif //!COMPILE_NO_X #endif return false; }
bool KviIpcSentinel::x11GetRemoteMessage() { Atom type; int format; unsigned long nItems, after; unsigned char * data = nullptr; KviCString szData; if(XGetWindowProperty(kvi_ipc_get_xdisplay(), winId(), kvi_atom_ipc_remote_command, 0, 1024, false, XA_STRING, &type, &format, &nItems, &after, &data) == Success) { if((type == XA_STRING) && (format == 8) && (nItems > 8) && data) { kvi_u32_t uSenderId = *((kvi_u32_t *)(data)); if(uSenderId != g_uLocalInstanceId) szData = (char *)(data + 8); XFree((char *)data); } } if(szData.isEmpty()) return false; // no command, or our own command kvi_ipcSetRemoteCommand(winId(), ""); if(g_pApp) g_pApp->ipcMessage(szData.ptr()); return true; }
KviIpcSentinel::KviIpcSentinel() : QWidget(0) { setObjectName("kvirc4_ipc_sentinel"); #if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW) setWindowTitle("kvirc4_ipc_sentinel"); setWindowFlags(Qt::FramelessWindowHint); #else #if defined(COMPILE_X11_SUPPORT) && defined(COMPILE_QX11INFO_SUPPORT) kvi_ipcLoadAtoms(); XChangeProperty(kvi_ipc_get_xdisplay(),winId(),kvi_atom_ipc_sentinel_window,XA_STRING,8, PropModeReplace,(const unsigned char *)kvi_sentinel_id.ptr(),kvi_sentinel_id.len()); kvi_ipcSetRemoteCommand(winId(),""); #endif //!COMPILE_NO_X #endif move(-50,-50); resize(1,1); #if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW) // we need to show the window once otherwise it will never get "realized" // and we will not be able to find it via FindWindow() show(); #endif hide(); }
static Window kvi_x11_findIpcSentinel(Window win) { Atom type; int format; unsigned long nItems, after; unsigned char * data = nullptr; if(XGetWindowProperty(kvi_ipc_get_xdisplay(), win, kvi_atom_ipc_sentinel_window, 0, 32, false, XA_STRING, &type, &format, &nItems, &after, &data) == Success) { if((type == XA_STRING) && (format == 8)) { if((nItems == ((unsigned long)(kvi_sentinel_id.len()))) && data) { if(kvi_strEqualCSN((const char *)data, kvi_sentinel_id.ptr(), kvi_sentinel_id.len())) { XFree((char *)data); return win; } } } } Window root, parent; Window * children; unsigned int nChildren; if(!XQueryTree(kvi_ipc_get_xdisplay(), win, &root, &parent, &children, &nChildren)) { if(children) XFree((char *)children); return 0; } Window found = 0; for(size_t i = 0; !found && i < nChildren; ++i) found = kvi_x11_findIpcSentinel(children[i]); if(children) XFree((char *)children); return found; }
static void kvi_ipcSetRemoteCommand(Window w, const char * command) { if(!command) return; int len = kvi_strLen(command) + 1; char * buffer = (char *)::malloc(len + 8); *((kvi_u64_t *)buffer) = g_uLocalInstanceId; ::memcpy(buffer + 8, command, len); XChangeProperty(kvi_ipc_get_xdisplay(), w, kvi_atom_ipc_remote_command, XA_STRING, 8, PropModeReplace, (const unsigned char *)buffer, len + 8); ::free(buffer); }