2013-08-12 13 views
8

Vorrei sapere se il mio QMainWindow è attualmente visibile e non sovrapposto a un'altra finestra di un'altra applicazione.Controlla se la mia QMainWindow è attualmente visibile in Qt

Ho bisogno di ottenere questo per Windows, Linux e Mac.

+0

Specificare la piattaforma di destinazione. Perché non ci sono modi multipiattaforma. –

+0

hai provato 'isVisible()' dal QWidget ereditato? – Joum

+0

Sulla maggior parte delle piattaforme, la "finestra attiva" è visibile sopra tutte le altre finestre, ma questo è solo un criterio sufficiente. Se questo è sufficiente per te, controlla 'QWidget :: isActiveWindow()'. – arne

risposta

5

Ho scritto una piccola libreria un po 'indietro per leggere le informazioni in primo piano o in primo piano, principalmente il titolo della finestra, su Windows, Mac OS X e Linux. È possibile trovare il codice sorgente qui: https://github.com/pcmantinker/Qt-Window-Title-Reader

ho utilizzare l'API Windows nativo per Windows, librerie X11 per Linux, e Cocoa su Mac OS X.

Ecco un piccolo esempio di come ottenere Windows Active in Mac OS X usando Objective-C++:
Mac.h

/* 
    Mac/Cocoa specific code for obtaining information about the frontmost window 
*/ 

#ifndef MAC_H 
#define MAC_H 
#include <QtCore> 
#include "windowinfo.h" 

class Mac { 
public: 
    Mac(); 
    QList<WindowInfo> getActiveWindows(); 
}; 

#endif // MAC_H 

Mac.mm

/* 
    Mac/Cocoa specific code for obtaining information about the frontmost window 
*/ 

#include "mac.h" 
#include "Cocoa/Cocoa.h" 

Mac::Mac() 
{ 

} 

QList<WindowInfo> Mac::getActiveWindows() 
{ 
    QList<WindowInfo> windowTitles; 

    // get frontmost process for currently active application 
    ProcessSerialNumber psn = { 0L, 0L }; 
    OSStatus err = GetFrontProcess(&psn); 

    CFStringRef processName = NULL; 
    err = CopyProcessName(&psn, &processName); 

    NSString *pname = (NSString *)processName; 

    // loop through all application windows 
    CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, kCGNullWindowID); 
    for (NSMutableDictionary* entry in (NSArray*)windowList) 
    { 
     NSString* ownerName = [entry objectForKey:(id)kCGWindowOwnerName]; 
     NSString *name = [entry objectForKey:@"kCGWindowName" ]; 
     NSInteger ownerPID = [[entry objectForKey:(id)kCGWindowOwnerPID] integerValue]; 
     NSInteger layer = [[entry objectForKey:@"kCGWindowLayer"] integerValue]; 
     if(layer == 0) 
     { 
      if([ownerName isEqualToString:pname]) 
      { 
       NSRange range; 
       range.location = 0; 
       range.length = [ownerName length]; 

       unichar *chars = new unichar[range.length]; 
       [ownerName getCharacters:chars range:range]; 
       QString owner = QString::fromUtf16(chars, range.length); 

       range.length = [name length]; 

       chars = new unichar[range.length]; 
       [name getCharacters:chars range:range]; 
       QString windowTitle = QString::fromUtf16(chars, range.length); 
       delete[] chars; 

       long pid = (long)ownerPID; 

       WindowInfo wi; 
       wi.setProcessName(owner); 
       wi.setWindowTitle(windowTitle); 
       wi.setPID(pid); 
       windowTitles.append(wi); 
      } 
     } 
    } 
    CFRelease(windowList); 
    CFRelease(processName); 

    return windowTitles; 
} 

Si prega di notare che in Cocoa, non c'è un modo diretto per ottenere solo la finestra più in alto. Ottieni una collezione di finestre e fai un ciclo attraverso di loro per trovare quello che vuoi.
ecco il codice per l'API di Windows:
win.h

/* 
    Windows API specific code for obtaining information about the frontmost window 
*/ 

#ifndef WIN_H 
#define WIN_H 
#include <QtCore> 
#include "qt_windows.h" 
#include "psapi.h" 
#include "windowinfo.h" 

class win : public QObject 
{ 
    Q_OBJECT 

public: 
    win(); 
    QList<WindowInfo> getActiveWindows(); 

private: 
    TCHAR buf[255]; 
}; 

#endif // WIN_H 

win.cpp

#include "win.h" 

win::win() 
{ 
} 

QList<WindowInfo> win::getActiveWindows() 
{ 
    QList<WindowInfo> windowTitles; 
    HWND foregroundWindow = GetForegroundWindow(); 
    DWORD* processID = new DWORD; 
    GetWindowText(foregroundWindow, buf, 255); 
    GetWindowThreadProcessId(foregroundWindow, processID); 
    DWORD p = *processID; 
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | 
            PROCESS_VM_READ, 
            FALSE, p); 
    TCHAR szProcessName[MAX_PATH]; 

    if (NULL != hProcess) 
    { 
     HMODULE hMod; 
     DWORD cbNeeded; 

     if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), 
           &cbNeeded)) 
     { 
      GetModuleBaseName(hProcess, hMod, szProcessName, 
           sizeof(szProcessName)/sizeof(TCHAR)); 
     } 
    } 
    CloseHandle(hProcess); 
    long pid = (long)p; 
    QString windowTitle, processName; 
#ifdef UNICODE 
    windowTitle = QString::fromUtf16((ushort*)buf); 
    processName = QString::fromUtf16((ushort*)szProcessName); 
#else 
    windowTitle = QString::fromLocal8Bit(buf); 
    processName = QString::fromLocal8Bit(szProcessName); 
#endif 

    WindowInfo wi; 
    wi.setPID(pid); 
    wi.setWindowTitle(windowTitle); 
    wi.setProcessName(processName); 
    windowTitles.append(wi); 
    return windowTitles; 
} 

Ecco il codice per Linux/X11:
linux_x11. h

/* 
    Linux/X11 specific code for obtaining information about the frontmost window 
*/ 

#ifndef LINUX_X11_H 
#define LINUX_X11_H 

#include <QtCore> 
#include <X11/X.h> 
#include <X11/Xlib.h> 
#include <X11/Xutil.h> 
#include <X11/Xatom.h> 
#include "windowinfo.h" 

class linux_x11 
{ 
public: 
    linux_x11(); 
    QList<WindowInfo> getActiveWindows(); 

private: 
    Window* active(Display *disp, unsigned long *len); 
    char *name (Display *disp, Window win); 
    int *pid(Display *disp, Window win); 
    QString processName(long pid); 
}; 

#endif // LINUX_X11_H 

linux_x11.cpp

/* 
    Linux/X11 specific code for obtaining information about the frontmost window 
*/ 

#include "linux_x11.h" 
#include <sstream> 
#include <stdlib.h> 
#include <stdio.h> 

linux_x11::linux_x11() 
{ 
} 

/** 
    * Returns the window name for a specific window on a display 
***/ 
char *linux_x11::name (Display *disp, Window win) { 
    Atom prop = XInternAtom(disp,"WM_NAME",False), type; 
    int form; 
    unsigned long remain, len; 
    unsigned char *list; 

    if (XGetWindowProperty(disp,win,prop,0,1024,False,AnyPropertyType, &type,&form,&len,&remain,&list) != Success) 
     return NULL; 

    return (char*)list; 
} 

/** 
    * Returns the pid for a specific window on a display 
***/ 
int* linux_x11::pid(Display *disp, Window win) { 
    Atom prop = XInternAtom(disp,"_NET_WM_PID",False), type; 
    int form; 
    unsigned long remain, len; 
    unsigned char *list; 

    if (XGetWindowProperty(disp,win,prop,0,1024,False,AnyPropertyType, &type,&form,&len,&remain,&list) != Success) 
     return NULL; 

    return (int*)list; 
} 

/** 
    * Returns the active window on a specific display 
***/ 
Window * linux_x11::active (Display *disp, unsigned long *len) { 
    Atom prop = XInternAtom(disp,"_NET_ACTIVE_WINDOW",False), type; 
    int form; 
    unsigned long remain; 
    unsigned char *list; 

    if (XGetWindowProperty(disp,XDefaultRootWindow(disp),prop,0,1024,False,XA_WINDOW, &type,&form,len,&remain,&list) != Success) 
     return NULL; 

    return (Window*)list; 
} 

/** 
    * Returns process name from pid (processes output from /proc/<pid>/status) 
***/ 
QString linux_x11::processName(long pid) 
{ 
    // construct command string 
    QString command = "cat /proc/" + QString("%1").arg(pid) + "/status"; 
    // capture output in a FILE pointer returned from popen 
    FILE * output = popen(command.toStdString().c_str(), "r"); 
    // initialize a buffer for storing the first line of the output 
    char buffer[1024]; 
    // put the contents of the buffer into a QString 
    QString line = QString::fromUtf8(fgets(buffer, sizeof(buffer), output)); 
    // close the process pipe 
    pclose(output); 
    // take right substring of line returned to get process name 
    return line.right(line.length() - 6).replace("\n", ""); 
} 

QList<WindowInfo> linux_x11::getActiveWindows() 
{ 
    QList<WindowInfo> windowTitles; 
    unsigned long len; 
    Display *disp = XOpenDisplay(NULL); 
    Window *list; 
    char *n; 
    int* p; 

    list = (Window*)active(disp,&len); 
    if((int)len > 0) 
    { 
     for (int i=0;i<(int)len;i++) { 
      n = name(disp,list[i]); 
      p = pid(disp, list[i]); 
      long p_id = 0; 
      QString pName; 
      QString windowTitle; 

      if(p!=NULL) 
      { 
       p_id = *p; // dereference pointer for obtaining pid 
       pName = processName(p_id); 
      } 

      if(n!=NULL) 
       windowTitle = QString::fromUtf8(n); 

      WindowInfo wi; 
      wi.setWindowTitle(windowTitle); 
      wi.setProcessName(pName); 
      wi.setPID(p_id); 
      windowTitles.append(wi); 
      delete n; 
      delete p; 
     } 
    } 
    delete list; 
    XCloseDisplay (disp); 
    return windowTitles; 
} 

codice X11 può ottenere abbastanza brutto e difficile da capire, ma questo dovrebbe iniziare. È passato un po 'di tempo da quando mi sono occupato direttamente di X11, quindi non posso dirvi esattamente cosa fa ogni metodo di supporto adesso.

Astraggo il codice in modo tale che ogni pezzo specifico del codice della piattaforma abbia la stessa firma del metodo. Poi controllo se è stato compilato su Mac OS X, Windows o Linux e istanzio le classi corrette. Ecco come è tutto legato insieme:

#include "windowtitlereader.h" 

WindowTitleReader::WindowTitleReader() 
{ 
    qDebug() << "WindowTitleReader::WindowTitleReader()"; 
    // refresh window reading every 10ms 
    timer = new QTimer(this); 
    timer->setInterval(10); 
    timer->start(); 
    connect(timer, SIGNAL(timeout()), this, SLOT(getWindowTitle())); 
} 

WindowTitleReader::~WindowTitleReader() 
{ 
    delete timer; 
    delete m_pid; 
    delete m_processName; 
} 
void WindowTitleReader::getWindowTitle() 
{ 
    qDebug() << "WindowTitleReader::getWindowTitle()"; 
#ifdef Q_WS_WIN 
    win w; 
    m_activeWindows = w.getActiveWindows(); 
#endif 

#ifdef Q_WS_MACX 
    Mac m; 
    m_activeWindows = m.getActiveWindows(); 
#endif 

#ifdef Q_WS_X11 
    linux_x11 l; 
    m_activeWindows = l.getActiveWindows(); 
#endif 
    for(int i = 0; i < m_activeWindows.count(); i++) 
     qDebug() << "PID: " << m_activeWindows[i].getPID() << " Process Name: " << m_activeWindows[i].getProcessName() << " Window Title: " << m_activeWindows[i].getWindowTitle(); 
} 

È possibile modificare la frequenza di aggiornamento a una frequenza di aggiornamento più lento se si vuole, ma sto correndo gli aggiornamenti ogni 10 ms per ottenere un aggiornamento quasi in tempo reale nella finestra di messa a fuoco.

Ho principalmente scritto questa libreria per leggere i titoli delle finestre dei browser Web e dei videogiochi in modo da ottenere una stima di quanto tempo le persone giocano determinati giochi sui loro computer. L'ho scritto come parte di un'app di metriche di gioco che sto costruendo.

Problemi correlati