Ivan
Ivan

Reputation: 4234

Draw an icon on a title bar in XLIB

My purpose is to draw an icon into the title bar of a basic wm i'm trying to create.

I already googled, and tried different solutions, but so far none is working (maybe just because of my lack of knowledge), i managed to display something from an icon, but it is not even close to what the icon is:

Current output

The icon was a floppy disk (with colours) So the code i used to display it is the following:

void get_system_icon(char* icon_name, Display *display, Window win){
    printf("Placeholder");
    unsigned int img_h;
    unsigned int img_w;
    unsigned int hotspot_x;
    unsigned int hotspot_y;

    Pixmap icon;
    XTextProperty icon_name_property;
    
    int width, height;
    int h_x, h_y;
    char *filename = "../default.ico";
    Imlib_Image img;
    img = imlib_load_image(filename);
    if(img == NULL){
            printf("Error loading imlibimage");
    }
    ScreenInfos infos = get_screen_informations(display);
    Screen *screen = DefaultScreenOfDisplay(display);
    imlib_context_set_image(img);
    img_w = imlib_image_get_width();
    img_h = imlib_image_get_height();
    printf("Img size: %d - %d\n", img_w, img_h);
    imlib_blend_image_onto_image(img,0,0,0, img_w, img_h, 0,0, infos.width,infos.height);
    Pixmap my_pix;
    my_pix = XCreatePixmap(display, win, img_w, img_h, DefaultDepthOfScreen(screen));
    imlib_context_set_display(display);
    imlib_context_set_visual(DefaultVisualOfScreen(screen));
    imlib_context_set_colormap(DefaultColormapOfScreen(screen));
    imlib_context_set_drawable(my_pix);
    imlib_render_image_on_drawable(0, 0);

    XSizeHints* win_size_hints;
    XWMHints* win_hints;
    int return_code;
    return_code = XStringListToTextProperty(&icon_name,
                               1,
                               &icon_name_property);
    if(return_code == 0) {
        printf("Error");
    }
    XSetWMIconName(display, win, &icon_name_property);
    win_hints = XAllocWMHints();
    if (!win_size_hints) {
        fprintf(stderr, "XAllocSizeHints - out of memory\n");
        exit(1);
    }
    win_hints->flags = IconPixmapHint | StateHint | IconPositionHint;
    win_hints->icon_pixmap = my_pix;
    win_hints->initial_state = IconicState;
    win_hints->icon_x = 0;
    win_hints->icon_y = 0;

    /* pass the hints to the window manager. */
    XSetWMHints(display, win, win_hints);

    /* finally, we can free the WM hints structure. */
    GC gc;
    gc = XCreateGC(display, win, 0, NULL);
    //XPutImage(display, win, gc, 
    XSetBackground(display, gc, WhitePixel(display, DefaultScreen(display)));   
    //WhitePixel(display, DefaultScreen(display));

    XCopyPlane(display, my_pix, win, gc,
                0, 0,
                30, 30,
                0, 0,
                1); 

    XFree(win_hints);
XFlush(display);
}

there are several question that i didn't found an answer anywhere,

So I'm pretty sure that my code is all wrong, but i can't find anywhere a good example of how to draw an icon on a window, can someone help me please?

Upvotes: 1

Views: 733

Answers (1)

Ivan
Ivan

Reputation: 4234

So finally after more than one year I found a solution (more or less) to this issue.

I found the answer on a similar SO question: How to load bmp file using x11 window background

So basically the first part of my code was pretty correct (the image loading using imlib).

But the wholse WM_Hints part was not necessary, and also to draw the pixmap i was using a GC (probably there is a way to draw with it too, but i don't know).

Tshe only thing needed once the image is loaded is to use XSetWindowBackgroundPixmap:

XSetWindowBackgroundPixmap(dpy, root, pix);

So the updated function now is:

void get_system_icon(char* icon_name, Display *display, Window win){
    unsigned int img_h;
    unsigned int img_w;
    char *filename = "../default.bmp";
    Pixmap my_pix;
    Imlib_Image img;

    img = imlib_load_image(filename);
    if(img == NULL){
            printf("Error loading imlibimage");
    }
    Screen *screen = DefaultScreenOfDisplay(display);
    imlib_context_set_image(img);
    img_w = imlib_image_get_width();
    img_h = imlib_image_get_height();
    printf("Img size: %d - %d\n", img_w, img_h);
    my_pix = XCreatePixmap(display, win, img_w, img_h, DefaultDepthOfScreen(screen));
    imlib_context_set_display(display);
    imlib_context_set_visual(DefaultVisualOfScreen(screen));
    imlib_context_set_colormap(DefaultColormapOfScreen(screen));
    imlib_context_set_drawable(my_pix);
    imlib_render_image_on_drawable(0, 0);
    XSetWindowBackgroundPixmap(display, win, my_pix);
    XClearWindow(display, win);
    XFreePixmap(display, my_pix);
    imlib_free_image();
}

It basically:

  • loads an image using imlib (in this case is default.bmp)
  • It creates a pixmap on the window win of the size of the image
  • sets the X drawable to which images will be rendered as the pixmap created.
  • Set the pixmap as a background of the window.
  • It frees the resources once done

In this way the image is showed correctly on the window. I don't know if it isn't the correct way to do it, but at least it is working.

Upvotes: 0

Related Questions