Xlib tutorial part 11 -- Menus

by Alan at Mon 23rd Mar 2009 1:00AM EST

Hello, and welcome to part 11 of this Xlib tutorial.

This week, I'm introducing a lot of new code. You can get it here. I'm not going to show every little change since I'm not introducing much in the way of new concepts. If you have questions, post a comment below.

What I am going to do is describe some of what I was thinking when I was writing this code. And to describe how menus work in X.

I was trying to build a modular piece of code so that each type of object has its own .c file. So, app.c, button.c, menu.c, and menubar.c.

getResources.c and xc2b.c are similar to the same files in last week. I've added a caching system to getResources.c and a debugging function from xc2b.c. Look through the code to see what I mean, neither of them is specific to X, though it means that the getResources won't have as many X requests if you are reusing fonts and colours a lot. And you should be.

In funcs.h, I've created a C struct and a C union that describes the types of objects in the system. This is not an object oriented system, per say, but has some of it's advantages. If you want an object oriented system in C you can move up to Xt, or switch to C++ which has linguistic support for object oriented programming. Even better is Lisp, if you're willing to really change languages. Much of what I describe as far as understanding the protocol will still be applicable even if you are using another language.

In button.c, I've added some code to create a menubutton. Menubuttons are just like buttons except they live inside of other objects (menus or menubars).

Inside menubar.c is an object that that represents the menubar across the top of the application which is in app.c. Most of what's in app.c is an abstraction of part of what used to be in the main .c file.

Inside menu.c is the meat for this week. Menu windows are special types of windows. They are not at all like the button from last week, or the menubar from this week. Those windows were parented inside the main app window, which in turn, the window manager decorated. Menus are top level windows that we don't want decorated. So, when we create a menu, we need to pass some things to the window creation call that we have not yet done. We need to use the XSetWindowAttributes structure and XCreateWindow()



Window newMenu(char *progname, Display *dpy, XrmDatabase db,
        XContext ctxt, char *name){
    Window win;
    Menu *menu;
    Window parent = DefaultRootWindow(dpy);
    XSetWindowAttributes xswa;

    xswa.save_under = True;
    xswa.override_redirect = True;

    menu = calloc(sizeof(*menu), 1);
    if (!menu){
        fprintf(stderr, "unable to allocate any space for %s menu, dieing
", name);
        exit(32);
    }
    menu->ctxt = ctxt;
    menu->funcs = MenuFuncs;
    win = XCreateWindow(dpy, parent, 0, 0, 100, 100,
        0, CopyFromParent, CopyFromParent, CopyFromParent,
         CWOverrideRedirect|CWSaveUnder , &xswa);

    XSelectInput(dpy, win, StructureNotifyMask);
    XSaveContext(dpy, win, ctxt, (XPointer)menu);
    return win;
}

Notice the xswa.save_under = True and xswa.override_redirect=True. Then the CWOverrideRedirect|CWSaveUnder, &xswa arguments to XCreateWindow. What that did was tell the X server that we want to set the override redirect (IE don't tell the window manager that about this window, keep it a secret between us and the X server) and we suggest saving anything this windw obsures, because this is window probably won't be up very long. If the X server supports save under, it means less expose events for other X clients.

As a side note, when I was first learning to program for X, I thought this override redirect bit was great and gave me a lot of power. I went off on a tangent and wrote a few programmes that used it for the oddest things. Eventually I discovered that they really didn't work very well with the established programmes and window managers. They just weren't right. Learn from my mistake. Only use override redirect for menus. It's what it's for. Anything else and you're misusing it. At least until you've learned much more than I have to teach you. And if you have, you can stop reading my tutorial.

Anyway, I'm not going to harp on this anymore. We've completed our quick tour of the code changes for this week.

Things to try:

Comments are closed.