2010-05-18 69 views
10

我有過程(和名稱)的PID,我想把它帶到Linux(Ubuntu)的前端。在Mac上,我只是做SetFrontProcess(pid),在窗口上我列舉了窗口,挑出了我想要的,然後打電話給SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);,但是我在linux上做了些什麼。我已經看了一下X Lib,但是大多數/所有這些函數似乎在你的進程中的窗口上運行。如何將進程窗口帶到X Windows的前臺? (C++)


編輯:使用BDK的回答我說這些助手到我的代碼來獲取窗口

bool searchHelper(Display* display, Window w, Atom& atomPID, unsigned long pid, Window& result) 
{ 
    bool ret = false; 

    Atom atomType; 
    int format; 
    unsigned long nItems; 
    unsigned long bytesAfter; 
    unsigned char* propPID = 0; 
    if (Success == XGetWindowProperty(display,w,atomPID,0,1,False,XA_CARDINAL,&atomType,&format,&nItems,&bytesAfter,&propPID)) 
    { 
     if (propPID != 0) 
     { 
      if (pid == *((unsigned long *)propPID)) 
      { 
       result = w; 
       ret = true; 
      } 
      XFree(propPID); 
     } 
    } 

    if (ret) 
     return ret; //we found we can stop 

    //check the children of the window 
    Window wRoot; 
    Window wParent; 
    Window *wChild=NULL; 
    unsigned nChildren=0; 
    if (XQueryTree(display, w, &wRoot, &wParent, &wChild, &nChildren) != 0) 
    { 
     for (unsigned i=0; i<nChildren; ++i) 
     { 
      ret = searchHelper(display, wChild[i], atomPID, pid, result); 
      if (ret) 
       break; 
     } 
    } 
    return ret; 
} 

bool getWindowFromPid(unsigned long pid, Display* display, Window& result) 
{ 
    Window window = XDefaultRootWindow(display); 
    Atom atomPID = XInternAtom(display, "_NET_WM_PID", true); 
    if (atomPID == None) 
    { 
     qDebug("XInternAtom failure"); 
     return false; 
    } 
    return searchHelper(display, window, atomPID, pid, result); 
} 

現在,我順利拿到窗口,但是當我做了以下

if (getWindowFromPid(pid,display,window)) 
{ 
    qDebug("Found window ID:%d", window); 
    int result = XRaiseWindow(display,window); 
    qDebug("XRaiseWindow returned:%d", result); 
} 

XRaiseWindow返回1(BadRequest)。 XRaiseWindow的文檔沒有提到BadRequest的返回代碼是一個可能的結果。我不確定什麼是錯的。我不允許在另一個過程中將它稱爲窗口嗎?這種重點防止鋼材會妨礙我嗎?有什麼想法嗎?

編輯編輯:

所以看着就當你與-frame所謂xwininfo.c它,我改變了我的代碼如下所示基於BDK的建議。

if (getWindowFromPid(pid,display,window)) 
    { 
     qDebug("Found window ID:%d", window); 

     //Need the windowmanger frame (or parent) id not window id 
     Window root, parent; 
     Window *childlist; 
     unsigned int ujunk; 
     int status = XQueryTree(display, window, &root, &parent, &childlist, &ujunk); 
     if (status && parent && parent != root) 
     { 
      qDebug("Found frame window ID:%d",parent); 
      window = parent; 
     } 

     XSetWindowAttributes xswa; 
     xswa.override_redirect=True; 
     int result = XChangeWindowAttributes (display,window,CWOverrideRedirect,&xswa); 
     qDebug("XChangeWindowAttributes returned:%d", result); 
     result = XRaiseWindow(display,window); 
     qDebug("XRaiseWindow returned:%d", result); 
    } 
    else 
     qDebug("unable to find the window for the pid"); 

在這一點上我確實覺得窗框ID,但我得到來自XChangeWindowAttributes和XRaiseWindow的「1」的返回代碼。我只是不允許修改另一個流程的窗口嗎?

+1

您將通過詢問「如何將進程窗口帶到X Windows上的前景?」獲得更好的結果。 – 2010-05-18 14:42:57

+0

@Vulcan謝謝,我編輯了問題標題。 (注意最初的問題:「我如何在Linux(C++)中將流程引入前臺?」) – Lorenz03Tx 2010-05-18 14:46:27

+0

如果你想獲得技術,標題仍然是錯誤的 - 沒有「X Windows」這樣的東西。這是「X窗口系統」(但「窗口」不應該複數化)。 – 2010-05-18 15:00:11

回答

6

我還沒有嘗試過這個自己,但只是這兩種方法可以一起工作:Xlib中

的XRaiseWindow API調用,您可以提升一個窗口前,如果你知道了窗口ID。

http://www.unix.com/man-page/Linux/3/XRaiseWindow/

這個計算器的回答解釋瞭如何從一個PID獲取窗口ID:

How to get an X11 Window from a Process ID?

編輯:

我已經有限的成功與XRaiseWindow。以下程序在twm窗口管理器下工作,但不是我通常使用的離子。窗口管理器必須有防止應用程序「彈出」的方法。爲了做到這一點,我還必須將窗口管理器框架的Window ID傳遞給窗口,而不是窗口本身。運行xwininfo -frame並單擊窗口,然後獲得框架ID,然後使用gcc test.c -lX編譯該程序,並在命令行上將它傳遞給hexid,它將引發窗口。

#include <stdio.h> 
#include <stdlib.h> 
#include <X11/Xlib.h> 

int main(int argc, char **argv) 
{ 
    Display *dsp = XOpenDisplay(NULL); 
    long id = strtol(argv[1], NULL, 16); 
    XSetWindowAttributes xswa; 
    xswa.override_redirect=True; 
    XChangeWindowAttributes (dsp,id,CWOverrideRedirect, &xswa); 
    XRaiseWindow (dsp, id); 
    XCloseDisplay (dsp); 
} 
+0

因此,使用該代碼來枚舉窗口並匹配PID讓我的窗口沒有問題。當我通過窗口int XRaiseWindow它什麼都不做,並返回1. 1 == BadRequest ....我不知道這是如何適用於爲xRaiseWindow文檔sugest它可以返回BadWindow(3),但沒有提及任何BadRequest。 – Lorenz03Tx 2010-05-18 16:06:29

+0

我上面編輯了我的答案。我想我已經超越了你遇到麻煩的地步,但XRaiseWindow的行爲似乎依賴於窗口管理器,所以你的milage可能會有所不同。 – bdk 2010-05-18 18:28:06

+0

是的,即使有框架窗口ID,我仍然得到1的返回碼。我猜我的窗口管理器不會讓我用其他窗口弄髒...我如何繞過這個?我的焦點鋼鐵是不好的,但這實際上是關注給予。這不應該被允許嗎? – Lorenz03Tx 2010-05-18 19:22:40

2

從bash命令行,你也可以使用了不起xdotool,它可以讓你指定下列提高XBMC窗口並輸入一個反斜槓到它:

xdotool search --name 'XBMC Media Center' windowactivate --sync key backslash 

這個程序有一個在它下面的實際庫,libxdo2,如果XRaiseWindow失敗,您可以使用它。我明白,無論windowmanager如何,libxdo都會竭盡全力來提升窗口。

3

我在我的應用程序中也有這個問題,所以這裏是解決方案。

要提高窗口,不僅需要提高窗口,還需要通知WM有關它。下面的代碼可用於:

 // This is how to get it in Qt; if you don't use it, 
     // you can call XOpenDisplay and get it from there; 
     Display * display = x11Info().display(); 

     // Main window identifier of your application 
     WId win = winId(); 

     XEvent event = { 0 }; 
     event.xclient.type = ClientMessage; 
     event.xclient.serial = 0; 
     event.xclient.send_event = True; 
     event.xclient.message_type = XInternAtom(display, "_NET_ACTIVE_WINDOW", False); 
     event.xclient.window = win; 
     event.xclient.format = 32; 

     XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &event); 
     XMapRaised(display, win); 
+0

除非我錯過了這是在你的應用程序的根窗口上進行操作。即提高自己。問題是如何提高另一個流程的窗口(即不在您的應用程序中)。 – Lorenz03Tx 2015-02-16 13:40:21

+0

是的,這是正確的。但問題的標題並不那麼具體 - 它可以解釋爲如何將您的流程窗口放在前面。所以我把它放在這裏尋找相同的人,因爲他們可能會像我一樣來到這裏。 – 2015-02-25 04:03:22

0

我想這將是容易的,因爲的/ proc看似具有所需的數據,但因爲它通常是誰真正擁有父的孩子/proc/${pid}/environ不提供正確的窗口ID進程正在運行的窗口。要獲得正確的windowid,您需要解析xwininfo輸出,然後您可以使用xdotool更改焦點。

CMD_PID=<your pid here> && while IFS= read -r -d '' var; do 
if grep -q "^WINDOWID=" <<< "$var"; then 
winid=$(printf '0x%x\n' $(sed 's/WINDOWID=//' <<< "${var}")) 
child_cnt=0 && IFS=$(echo -en "\n\b") && for a in $(xwininfo -root -tree | tac | sed -n "/${winid}/,\$p"); do 
grep -q -i "children" <<< "${a}" && let child_cnt+=1 
((${child_cnt} == 2)) && real_winid=$(grep -o '0x[^ ]*' <<< "${last_line}") && break 
last_line="${a}" 
done 
xdotool windowraise ${real_winid} 
break 
fi 
done < /proc/${CMD_PID}/environ