Drawables and Pixmaps

A pixmap is an off-screen buffer you can draw graphics into. After drawing into a pixmap, you can copy it to a window, causing it to appear on the screen (when the window is visible). (You can also draw into a window directly, of course. Using a pixmap as a buffer allows you to rapidly update the screen without repeating a series of primitive drawing operations.) Pixmaps are also good to store image data loaded from disk, such as icons and logos. You can then copy the image to a window. In GDK, the pixmap type is called GdkPixmap. A pixmap with a single bit representing each pixel is called a bitmap; GDK's bitmap type is GdkBitmap. "Bitmap" is not really a separate type; from X's point of view, it is simply a pixmap with a depth of 1. Like windows, pixmaps are server-side resources.

In X terminology, a drawable is anything you can draw graphics on. GDK has a corresponding type, called GdkDrawable. Drawables include windows, pixmaps, and bitmaps. Here is how the types are defined in GDK:


typedef struct _GdkWindow GdkWindow;
typedef struct _GdkWindow GdkPixmap;
typedef struct _GdkWindow GdkBitmap;
typedef struct _GdkWindow GdkDrawable;

On the client side, pixmaps and bitmaps are just GdkWindows with type GDK_WINDOW_PIXMAP. GdkDrawable is used in function declarations when either a window or a pixmap is an acceptable argument. Functions that draw graphics take either type; functions that move windows around or set window manager hints accept only windows. Only windows can receive events. GDK_INPUT_ONLY windows are a special case; they are not drawables and you can't draw on them.

Three of the four logical combinations of "window features" and drawability actually exist:


                       Drawable             Not Drawable
Window Features      Normal Window         Input Only Window
No Window Features   Pixmap/Bitmap            ---

Unfortunately, all three of these logically distinct cases appear the same from a type-checking point of view. So be careful not to use the wrong one. Also keep in mind that a normal window is not drawable until it actually appears on the screen; you should wait until you receive an expose event before you draw. Expose events are covered in the section called Expose Events.

Like GdkWindow, a GdkPixmap is merely a client-side handle for an object located on the X server. Because of this, some things are entirely infeasible from a performance point of view; notably, if you are doing anything which requires significant manipulation of individual pixels, drawables will be far too slow. On the other hand, copying a pixmap to a window is not as slow as you might think, because both objects are on the same machine.

Creating a pixmap is much easier than creating a window, because most of the window attributes are not relevant to pixmaps. The function is gdk_pixmap_new() (Figure 4). It accepts an initial size, and a bit depth. If a depth of -1 is given, the depth is copied from its GdkWindow argument. You can't choose an arbitrary number for the depth---the server will not support all depths, and the pixmap's depth must match the depth of any windows you plan to copy it to. To destroy a pixmap, call gdk_pixmap_unref().

The GdkWindow argument to gdk_pixmap_new() may not seem strictly necessary. However, the function wraps XCreatePixmap(), which takes an X window as an argument. It uses this argument to determine which screen to create the window on; some X servers have multiple displays. Screens are an Xlib concept totally concealed by GDK; GDK supports only one screen at a time. Thus the window argument to gdk_pixmap_new() seems mysterious from a GDK point of view.

#include <gdk/gdk.h>

GdkPixmap* gdk_pixmap_new(GdkWindow* window, gint width, gint height, gint depth);

void gdk_pixmap_unref(GdkPixmap* pixmap);

Figure 4. GdkPixmap Constructor