7

im trying to write a C code to get the title of the Active Window in my Linux System, but the Function XFetchName always returnes zero, i also tried XGetWMName, same result... but using xprop, i can see that there is a string in the "WM_NAME" property

can anyone tell me whats wrong with my code?

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


int main( int argc, char* argv[] )
{
      Display *display;
      Window focus;
      char *window_name;
      int revert;

      display = XOpenDisplay(NULL);
      XGetInputFocus(display, &focus, &revert);
      int ret = XFetchName(display, focus, &window_name);
      printf("ret = %d\n", ret);
      if (window_name) printf("Title = %s\n", window_name);
      return 0;
}

thanks.

killercode
  • 1,666
  • 5
  • 29
  • 42
  • 1
    Your code works perfectly fine on the machine I'm currently using (OSX Lion) when run from an Xterm (which by default has the name `xterm` set). In addition, I added a call to `XStoreName()` to set it to something else first and that worked as expected as well with your code retrieving the new name just fine. This is of course after renaming `_main()` to `main()` - How are you running your program? – Brian Roach Jan 11 '12 at 20:07
  • the '_' is just to define an entry point name with the command line "-Wl,-e__main" because im not using stdlib, i dont think this has to do anything. and still when executed from Ubuntu's Terminal it returns 0, but works from xterm, is there a reason for this? – killercode Jan 12 '12 at 01:44

3 Answers3

7

You can try using XGetWMName function. Although the discriptions of XGetWMName and XFetchName both say they will return the WM_NAME property, it seems that they are different from each other. Some times, they return the same name. Some times, only XGetWMName returns the name.

You can also use xwininfo -root -tree to get all the windows' name, and compare with the result of XFetchName and XGetWMName.

This code can list all the windows and print the window id and result of XFetchName and XGetWMName. You can use the window id to look up in the output of xwininfo -root -tree.

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

void enum_windows(Display* display, Window window, int depth) {
  int i;

  XTextProperty text;
  XGetWMName(display, window, &text);
  char* name;
  XFetchName(display, window, &name);
  for (i = 0; i < depth; i++)
    printf("\t");
  printf("id=0x%x, XFetchName=\"%s\", XGetWMName=\"%s\"\n", window, name != NULL ? name : "(no name)", text.value);

  Window root, parent;
  Window* children;
  int n;
  XQueryTree(display, window, &root, &parent, &children, &n);
  if (children != NULL) {
    for (i = 0; i < n; i++) {
      enum_windows(display, children[i], depth + 1);
    }
    XFree(children);
  }
}

int main() {
  Display* display = XOpenDisplay(NULL);
  Window root = XDefaultRootWindow(display);
  enum_windows(display, root, 0);
}

Here's a piece of output showing that the result of two functions may be different.

id=0x2c7, XFetchName="(no name)", XGetWMName="(null)"
    id=0x400001, XFetchName="(no name)", XGetWMName="(null)"
    id=0x800036, XFetchName="(no name)", XGetWMName="(null)"
        id=0x1400001, XFetchName="(no name)", XGetWMName="c - XFetchName always returns 0 - Stack Overflow - Chromium"
    id=0x1000001, XFetchName="terminator", XGetWMName="terminator"
        id=0x1000002, XFetchName="(no name)", XGetWMName="(null)"
    id=0x1200001, XFetchName="chromium", XGetWMName="chromium"
        id=0x1200002, XFetchName="(no name)", XGetWMName="(null)"

Here's a piece of the output of xwininfo -root -tree showing the name of these windows. xwininfo: Window id: 0x2c7 (the root window) (has no name)

  Root window id: 0x2c7 (the root window) (has no name)
  Parent window id: 0x0 (none)
     29 children:
     0x1200001 "chromium": ("chromium" "Chromium")  10x10+10+10  +10+10
        1 child:
        0x1200002 (has no name): ()  1x1+-1+-1  +9+9
     0x1000001 "terminator": ("terminator" "Terminator")  10x10+10+10  +10+10
        1 child:
        0x1000002 (has no name): ()  1x1+-1+-1  +9+9
     0x800036 (has no name): ()  1364x741+0+25  +0+25
        1 child:
        0x1400001 "c - XFetchName always returns 0 - Stack Overflow - Chromium": ("Chromium" "Chromium")  1364x741+0+0  +1+26
     0x400001 (has no name): ()  10x10+-20+-20  +-20+-20
Haoshu
  • 832
  • 7
  • 19
0
 /*
  * The following functions are internationalized substitutions
  * for XFetchName and XGetIconName using XGetWMName and
  * XGetWMIconName.  
  *
  * Please note that the third arguments have to be freed using free(), 
  * not XFree().
  */
 Status
 I18N_FetchName(dpy, w, winname)
     Display *dpy;
     Window w;
     char ** winname;
 {
     int    status;
     XTextProperty text_prop;
     char **list;
     int    num;

     status = XGetWMName(dpy, w, &text_prop);
     if (!status || !text_prop.value || !text_prop.nitems) return 0;
     status = XmbTextPropertyToTextList(dpy, &text_prop, &list, &num);
     if (status < Success || !num || !*list) return 0;
     XFree(text_prop.value);
     *winname = (char *)strdup(*list);
     XFreeStringList(list);
     return 1;
 }

//XFetchName uses XGetWMName

see: enter link description here

-1

The XFetchName function returns the name of the specified window. If it succeeds, it returns a nonzero status; otherwise, no name has been set for the window, and it returns zero.

You need to set a name for your window.

I started an xterm session and executed you code and got the following output:

sangeeth@home:~/work/test$ ./a.out 
ret = 1 
Title = sangeeth@home: ~/work/test
sangeeth@home:~/work/test$ 

OTOH, I tried compiling your program and got the following error:

(.text+0x18): undefined reference to `main'

You need to change

int _main( int argc, char* argv[] )

to

int main(int argc, char* argv[]) 
Sangeeth Saravanaraj
  • 16,027
  • 21
  • 69
  • 98