2013-08-12 21 views
8

Tôi muốn biết liệu QMainWindow của tôi hiện có hiển thị và không bị chồng chéo bởi các cửa sổ khác của một ứng dụng khác không.Kiểm tra xem QMainWindow của tôi hiện có hiển thị trong Qt

Tôi cần đạt được điều này cho Windows, Linux và Mac.

+0

Vui lòng chỉ định nền tảng đích. Bởi vì không có cách thức đa nền tảng. –

+0

bạn đã thử 'isVisible()' từ QWidget kế thừa chưa? – Joum

+0

Trên hầu hết các nền tảng, "cửa sổ hoạt động" hiển thị trên tất cả các cửa sổ khác, nhưng đó chỉ là một tiêu chí đầy đủ. Nếu điều đó là đủ cho bạn, hãy kiểm tra 'QWidget :: isActiveWindow()'. – arne

Trả lời

5

Tôi đã viết một thư viện nhỏ một chút để đọc thông tin cửa sổ trước hoặc trên cùng, chủ yếu là tiêu đề cửa sổ, trên Windows, Mac OS X và Linux. Bạn có thể tìm thấy mã nguồn ở đây: https://github.com/pcmantinker/Qt-Window-Title-Reader

tôi sử dụng Windows API bản dành cho Windows, thư viện X11 cho Linux, và Cocoa trên Mac OS X.

Đây là một ví dụ nhỏ về làm thế nào để có được các cửa sổ hoạt động trong Mac OS X sử dụng mục tiêu-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; 
} 

Xin lưu ý rằng trong Cocoa, không có cách trực tiếp để chỉ nhận được cửa sổ trên cùng. Bạn nhận được một bộ sưu tập các cửa sổ và lặp lại chúng để tìm ra cửa sổ bạn muốn.
Đây là mã cho Windows API:
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; 
} 

Dưới đây là đoạn code cho 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; 
} 

X11 mã có thể nhận được khá xấu xí và khó hiểu, nhưng điều này sẽ giúp bạn bắt đầu. Nó đã được khá một thời gian kể từ khi tôi đã xử lý với X11 trực tiếp vì vậy tôi không thể chính xác cho bạn biết những gì từng phương pháp trợ giúp hiện nay.

Tôi trừu tượng mã sao cho mỗi phần nền tảng cụ thể của mã có cùng chữ ký phương thức. Sau đó, tôi kiểm tra xem nó đã được biên soạn trên Mac OS X, Windows hay Linux và khởi tạo các lớp chính xác chưa. Đây là cách nó được tất cả các ràng buộc với nhau:

#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(); 
} 

Bạn có thể thay đổi tốc độ làm tươi đến một tốc độ làm tươi chậm hơn nếu bạn muốn, nhưng tôi đang chạy các bản cập nhật mỗi 10ms để có được một cập nhật thời gian thực gần trên cửa sổ lấy nét.

Tôi chủ yếu viết thư viện này để đọc tiêu đề cửa sổ trình duyệt web và trò chơi video để tôi có thể ước tính thời gian mọi người chơi trò chơi nhất định trên máy tính của họ. Tôi đã viết bài này như một phần của ứng dụng số liệu chơi trò chơi mà tôi đang xây dựng.

Các vấn đề liên quan