Setting X11 root window pixmap - c

The code below is supposed to make root window white, but does nothing. Compiles and runs with no errors. I omitted only includes and variable definitions.
int
main(int argc, char **argv) {
dpy = XOpenDisplay(NULL);
if (!dpy) {
fputs("cannot open display\n", stderr);
return EXIT_FAILURE;
}
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
vis = DefaultVisual(dpy, screen);
depth = DefaultDepth(dpy, screen);
height = DisplayHeight(dpy, screen);
width = DisplayWidth(dpy, screen);
img = malloc(depth/8 * height * width);
if (img == NULL) {
perror("malloc() failed");
return EXIT_FAILURE;
}
memset(img, 0xFF, depth/8 * height * width);
ximg = XCreateImage(dpy, vis, depth, ZPixmap, 0, img, width, height, 32, 0);
pm = XCreatePixmap(dpy, root, width, height, depth);
gc = XCreateGC(dpy, pm, 0, NULL);
XPutImage(dpy, pm, gc, ximg, 0, 0, 0, 0, width, height);
XSetWindowBackgroundPixmap(dpy, root, pm);
XClearWindow(dpy, root);
XFlush(dpy);
XDestroyImage(ximg);
XFreePixmap(dpy, pm);
XFreeGC(dpy, gc);
XCloseDisplay(dpy);
return EXIT_SUCCESS;
}
How do I even start troubleshooting this? removing XClearWindow(dpy, root); does not help.

Apparently XSetWindowBackgroundPixmap() needs some prior atom setup. This borrowed function fixed the issue.
// Adapted from fluxbox' bsetroot
int
setRootAtoms(Pixmap pixmap)
{
Atom atom_root, atom_eroot, type;
unsigned char *data_root, *data_eroot;
int format;
unsigned long length, after;
atom_root = XInternAtom(display, "_XROOTMAP_ID", True);
atom_eroot = XInternAtom(display, "ESETROOT_PMAP_ID", True);
// doing this to clean up after old background
if (atom_root != None && atom_eroot != None) {
XGetWindowProperty(display, RootWindow(display, screen), atom_root, 0L, 1L, False, AnyPropertyType, &type, &format, &length, &after, &data_root);
if (type == XA_PIXMAP) {
XGetWindowProperty(display, RootWindow(display, screen), atom_eroot, 0L, 1L, False, AnyPropertyType, &type, &format, &length, &after, &data_eroot);
if (data_root && data_eroot && type == XA_PIXMAP && *((Pixmap *) data_root) == *((Pixmap *) data_eroot))
XKillClient(display, *((Pixmap *) data_root));
}
}
atom_root = XInternAtom(display, "_XROOTPMAP_ID", False);
atom_eroot = XInternAtom(display, "ESETROOT_PMAP_ID", False);
if (atom_root == None || atom_eroot == None)
return 0;
// setting new background atoms
XChangeProperty(display, RootWindow(display, screen), atom_root, XA_PIXMAP, 32, PropModeReplace, (unsigned char *) &pixmap, 1);
XChangeProperty(display, RootWindow(display, screen), atom_eroot, XA_PIXMAP, 32, PropModeReplace, (unsigned char *) &pixmap, 1);
return 1;
}

Related

Using multiple threads with GTK?

How do I use multiple threads in GTK? I have 2 threads, one initializes the GUI and then continuously runs gtk_main() to draw my gui and my other thread does all my program logic and computing, however when my program logic thread updates a GtkImage it will randomly and inconsistently stop updating and freeze and will not draw the anything on the form anymore.
I have read and been told to only call GTK functions from the gtk thread but that is impossible as once you call gtk_main() it will be stuck there until the program exits.
Anyone know how I can get my program and gui cooperating together and show me an example of how it would work with my existing program?
I have been stuck on this for hours now and need to finish this script for a company soon so they can use it to help automate one of their tasks at their manufacturing facility.
Ex.
static GtkWidget* gtk_image;
void my_thread()
{
while (1) {
//wait for input
//do program logic
//update gtk_image to new image
}
}
void gui_thread() {
//initialize gui
//call gtk_main //it never exits this function until program is closed so you can see how its impossible to make any drawing calls from this thread
}
my actual code looks like this (where cam_main and main_gtk are the threads I was mentioning):
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdarg.h>
#include <gphoto2/gphoto2-camera.h>
#include <gphoto2/gphoto2-context.h>
#include <wiringPi.h>
#include <gtk/gtk.h>
#include <pthread.h>
//program
static int running = 1;
//libgphoto2
static CameraList* list;
static Camera** cams;
static GPContext* context;
static const char *name, *value;
static int ret, count;
static int pic = 0;
static int front = 1;
static const char* workingDir;
//GTK
static GtkWidget *window, *vbox,*hboxDir, *hboxCamLabels, *hboxFrontPics, *hboxBackPics, *hboxStatus, *lblDir, *btnConfigDir, *lblCams, *lblFront, *lblBack, *lblCurrentStatus;
static GtkWidget *front_cams[3];
static GtkWidget *back_cams[3];
static GdkPixbuf *pxbscaled = NULL;
static GdkPixbuf *pixbuf = NULL;
static GError* err = NULL;
static void btnConfigDir_ConfigureDirectory(GtkWidget* widget, gpointer data) {
GtkWidget *dialog;
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
gint res;
dialog = gtk_file_chooser_dialog_new ("Open File", window,
action,
"_Cancel",
GTK_RESPONSE_CANCEL,
"_Open",
GTK_RESPONSE_ACCEPT,
NULL);
res = gtk_dialog_run (GTK_DIALOG (dialog));
if (res == GTK_RESPONSE_ACCEPT)
{
char *filename;
GtkFileChooser *chooser = GTK_FILE_CHOOSER (dialog);
workingDir = gtk_file_chooser_get_filename (chooser);
}
//gtk_label_set_text((GTK_LABEL)lblDir, workingDir);
gtk_widget_destroy (dialog);
}
void* main_gtk() {
//GTK WIDGET QUEUE REDRAW WOULD REDRAW AT APPROPRIATE TIME
//INIT GTK
gtk_init(NULL, NULL);
//SETUP WINDOW
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
//button1=gtk_button_new_with_label("Click me");
//gtk_button_set_label(GTK_BUTTON(button1), "click me 1");
g_signal_connect(window,"delete-event", G_CALLBACK(gtk_main_quit), NULL);
workingDir = "/media/pi/SD CARD";
lblDir = gtk_label_new("Save to: dir\t");
btnConfigDir = gtk_button_new_with_label("Configure Directory");
g_signal_connect(btnConfigDir, "clicked", G_CALLBACK(btnConfigDir_ConfigureDirectory), NULL);
lblCams = gtk_label_new("\t\t\t\t\t\t\t\tCAM 1\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tCAM2\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tCAM3");
lblFront = gtk_label_new("Front");
lblBack = gtk_label_new("Back ");
lblCurrentStatus = gtk_label_new("Current Status: Idle");
//SET WINDOW SIZE AND TITLE
//gtk_widget_set_size_request(window, 600, 400);
gtk_window_set_title(GTK_WINDOW(window), "CaptureGui");
//RESIZE IMAGES
//image
front_cams[0] = gtk_image_new();
front_cams[1] = gtk_image_new();
front_cams[2] = gtk_image_new();
back_cams[0] = gtk_image_new();
back_cams[1] = gtk_image_new();
back_cams[2] = gtk_image_new();
GdkPixbuf* pxb;
pxb = gdk_pixbuf_new(0, 0, 8, 500, 300);
gtk_image_set_from_pixbuf(GTK_IMAGE(front_cams[0]), pxb);
gtk_image_set_from_pixbuf(GTK_IMAGE(front_cams[1]), pxb);
gtk_image_set_from_pixbuf(GTK_IMAGE(front_cams[2]), pxb);
gtk_image_set_from_pixbuf(GTK_IMAGE(back_cams[0]), pxb);
gtk_image_set_from_pixbuf(GTK_IMAGE(back_cams[1]), pxb);
gtk_image_set_from_pixbuf(GTK_IMAGE(back_cams[2]), pxb);
//g_print("1");
//front_cams[0] = gtk_image_new_from_file("/media/pi/SD CARD/cam-1_0_a_front.jpg");
//set_image_scaled(front_cams[0], "/media/pi/SD CARD/cam-1_1_a_front.jpg");
//set_image_scaled(front_cams[1], "/media/pi/SD CARD/cam-1_1_a_front.jpg");
//set_image_scaled(front_cams[2], "/media/pi/SD CARD/cam-1_1_b_back.jpg");
//PACK
hboxDir = gtk_box_new(0, 0);
hboxCamLabels = gtk_box_new(0, 0);
hboxFrontPics = gtk_box_new(0, 0);
hboxBackPics = gtk_box_new(0, 0);
hboxStatus = gtk_box_new(0, 0);
vbox = gtk_vbox_new(0, 10);
gtk_box_pack_end(GTK_BOX(hboxDir), btnConfigDir, 0, 0, 0);
gtk_box_pack_end(GTK_BOX(hboxDir), lblDir, 0, 0, 0);
gtk_box_pack_start(GTK_BOX(hboxCamLabels), lblCams, 0, 0, 0);
gtk_box_pack_start(GTK_BOX(hboxFrontPics), lblFront, 0, 0, 0);
gtk_box_pack_start(GTK_BOX(hboxFrontPics), front_cams[0], 0, 0, 10);
gtk_box_pack_start(GTK_BOX(hboxFrontPics), front_cams[1], 0, 0, 10);
gtk_box_pack_start(GTK_BOX(hboxFrontPics), front_cams[2], 0, 0, 10);
gtk_box_pack_start(GTK_BOX(hboxBackPics), lblBack, 0, 0, 0);
gtk_box_pack_start(GTK_BOX(hboxBackPics), back_cams[0], 0, 0, 10);
gtk_box_pack_start(GTK_BOX(hboxBackPics), back_cams[1], 0, 0, 10);
gtk_box_pack_start(GTK_BOX(hboxBackPics), back_cams[2], 0, 0, 10);
gtk_box_pack_start(GTK_BOX(hboxStatus), lblCurrentStatus, 0, 0, 10);
gtk_box_pack_start(GTK_BOX(vbox), hboxDir, 0, 0, 0);
gtk_box_pack_start(GTK_BOX(vbox), hboxCamLabels, 0, 0, 0);
gtk_box_pack_start(GTK_BOX(vbox), hboxFrontPics, 0, 0, 0);
gtk_box_pack_start(GTK_BOX(vbox), hboxBackPics, 0, 0, 0);
gtk_box_pack_start(GTK_BOX(vbox), hboxStatus, 0, 0, 0);
//gtk_box_pack_start(GTK_BOX(hbox), front_cams[0], 0, 0, 0);
//gtk_box_pack_start(GTK_BOX(hbox), front_cams[1], 0, 0, 0);
//gtk_box_pack_start(GTK_BOX(hbox), front_cams[2], 0, 0, 0);
//gtk_box_pack_start(GTK_BOX(hbox), back_cams[0], 0, 0, 0);
//gtk_box_pack_start(GTK_BOX(hbox), back_cams[1], 0, 0, 0);
//gtk_box_pack_start(GTK_BOX(hbox), back_cams[2], 0, 0, 0);
gtk_container_add(GTK_CONTAINER(window), vbox);
//ADD ELEMENTS TO GUI
//gtk_container_add(GTK_CONTAINER(window), image1);
//gtk_container_add(GTK_CONTAINER(window), image2);
//image2 = gtk_image_new_from_file("/media/pi/SD CARD/cam-1_0_b_back.jpg");
//gtk_container_add(GTK_CONTAINER(window), image2);
//SHOW GUI
gtk_widget_show_all(window);
gtk_main();
}
void set_image_scaled(GtkWidget* img, const char* path) {
pixbuf = gdk_pixbuf_new_from_file(path, &err);
g_assert_no_error(err);
pxbscaled = gdk_pixbuf_scale_simple(pixbuf, 500, 300, GDK_INTERP_BILINEAR);
gtk_image_set_from_pixbuf(GTK_IMAGE(img), pxbscaled);
g_object_unref(pixbuf);
g_object_unref(pxbscaled);
}
void* cam_main() {
while (running == 1) {
if (digitalRead(4) == 0)
{
printf("taking pics of %s item %i\n", (front == 1) ? "front" : "back", pic);
for (int i = 0; i < count; i++)
{
int fd, retval;
CameraFile *file;
CameraFilePath cfPath;
strcpy(cfPath.folder, "/");
strcpy(cfPath.name, "foo1.jpg");
printf("Capturing cam%i...\n", i + 1);
int res = gp_camera_capture(cams[i], GP_CAPTURE_IMAGE, &cfPath, context);
//printf(gp_port_result_as_string(res));
printf("capture result: %i\n", res);
//Camera won't take pic if busy and will continue to program end
char buf[256];
snprintf(buf, sizeof(buf), "%s/cam-%i_%i_%s.jpg", workingDir, i + 1, pic, (front == 1) ? "a_front" : "b_back"); //a_ to make front come before back otherwise systems will order incorrectly
fd = open(buf, O_CREAT | O_WRONLY, 0644);
retval = gp_file_new_from_fd(&file, fd);
retval = gp_camera_file_get(cams[i], cfPath.folder, cfPath.name, GP_FILE_TYPE_NORMAL, file, context);
retval = gp_camera_file_delete(cams[i], cfPath.folder, cfPath.name, context);
gp_file_free(file);
//debug
//if (front == 1 && i == 0)
// set_image_scaled(front_cams[0], buf);
if (front == 1)
set_image_scaled(front_cams[i], buf);
else
set_image_scaled(back_cams[i], buf);
}
if (front == 1)
front = 0;
else
{
front = 1;
pic += 1;
}
printf("pics taken...\n");
}
}
}
int main(int argc, char **argv)
{
//Kill any processes using cams
system("pkill -f gphoto2");
//Wiring pi init
wiringPiSetupGpio();
//Init
context = gp_context_new();
detect_cams();
pthread_t logic_thread_handle, gui_thread_handle;
pthread_create(&logic_thread_handle, NULL, cam_main, NULL);
pthread_create(&gui_thread_handle, NULL, main_gtk, NULL);
pthread_join(gui_thread_handle, 0);
pthread_join(logic_thread_handle, 0);
//Deinit
for (int i = 0; i < count; i++)
{
gp_camera_exit(cams[i], context);
gp_camera_free(cams[i]);
}
return 0;
}
void detect_cams() {
//Detecting all cameras and loading them into mem
//Detecting all cameras
ret = gp_list_new(&list);
if (ret < GP_OK) return 1;
gp_list_reset(list);
count = gp_camera_autodetect(list, context);
if (count < 1)
{
printf("No cameras detected.\n");
return 1;
}
//Open all cameras
printf("Number of cameras: %d\n", count);
cams = calloc(sizeof (Camera*), count);
for (int i = 0; i < count; i++)
{
gp_list_get_name(list, i, &name);
gp_list_get_value(list, i, &value);
ret = open_cam(&cams[i], name, value, context);
if (ret < GP_OK)
fprintf(stderr, "Camera %s on port %s failed to open\n", name, value);
}
}
int open_cam(Camera ** camera, const char *model, const char *port, GPContext *context) {
GPPortInfoList *portinfolist = NULL;
CameraAbilitiesList *abilities = NULL;
int ret, m, p;
CameraAbilities a;
GPPortInfo pi;
ret = gp_camera_new (camera);
if (ret < GP_OK) return ret;
if (!abilities) {
/* Load all the camera drivers we have... */
ret = gp_abilities_list_new (&abilities);
if (ret < GP_OK) return ret;
ret = gp_abilities_list_load (abilities, context);
if (ret < GP_OK) return ret;
}
/* First lookup the model / driver */
m = gp_abilities_list_lookup_model (abilities, model);
if (m < GP_OK) return ret;
ret = gp_abilities_list_get_abilities (abilities, m, &a);
if (ret < GP_OK) return ret;
ret = gp_camera_set_abilities (*camera, a);
if (ret < GP_OK) return ret;
if (!portinfolist) {
/* Load all the port drivers we have... */
ret = gp_port_info_list_new (&portinfolist);
if (ret < GP_OK) return ret;
ret = gp_port_info_list_load (portinfolist);
if (ret < 0) return ret;
ret = gp_port_info_list_count (portinfolist);
if (ret < 0) return ret;
}
/* Then associate the camera with the specified port */
p = gp_port_info_list_lookup_path (portinfolist, port);
switch (p) {
case GP_ERROR_UNKNOWN_PORT:
fprintf (stderr, "The port you specified "
"('%s') can not be found. Please "
"specify one of the ports found by "
"'gphoto2 --list-ports' and make "
"sure the spelling is correct "
"(i.e. with prefix 'serial:' or 'usb:').",
port);
break;
default:
break;
}
if (p < GP_OK) return p;
ret = gp_port_info_list_get_info (portinfolist, p, &pi);
if (ret < GP_OK) return ret;
ret = gp_camera_set_port_info (*camera, pi);
if (ret < GP_OK) return ret;
return GP_OK;
}
I have read and been told to only call GTK functions from the gtk thread but that is impossible as once you call gtk_main() it will be stuck there until the program exits.
No, it's not impossible. Control is returned to your program even while gtk_main() is active, by means of callbacks. In your thread, you can schedule a callback to be called in the GTK thread using gdk_threads_add_idle(). See GTK3 and multithreading, replacing deprecated functions for more information.

GIMP-Exported png remembers deleted layers

I've made a set of similar images in GIMP. For each new image, I traced over the previous image and drew a different letter in the center, getting rid of the letter of the previous image. This is what my image looks like:
I have a C program which uses libpng to load the image, then displays it as a texture in OpenGL. This is what I get:
The letter from the previous image is behind the one for this image. It doesn't show up in GIMP anymore (or Atom), and I only have one layer. Why might this be happening?
Code that might be suspect:
int load_texture(const char* filename, GLuint* ptexture) {
FILE* fp = fopen(filename, "rb");
if (!fp) {
return LOAD_TEXTURE__FILE_NOT_FOUND;
}
unsigned char bytes[8];
fread(bytes, 1, 8, fp);
bool is_png = !png_sig_cmp(bytes, 0, 8);
if (!is_png) {
return LOAD_TEXTURE__FILE_NOT_PNG;
}
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr) {
return LOAD_TEXTURE__PNG_READ_STRUCT_FAILURE;
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
png_destroy_read_struct(&png_ptr, (png_infopp)(NULL), (png_infopp)(NULL));
return LOAD_TEXTURE__PNG_INFO_PTR_FAILURE;
}
png_infop end_info = png_create_info_struct(png_ptr);
if (!end_info) {
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)(NULL));
return LOAD_TEXTURE__PNG_END_INFO_FAILURE;
}
if (setjmp(png_jmpbuf(png_ptr))) {
return LOAD_TEXTURE__PNG_JMPBUF_FAILURE;
}
png_init_io(png_ptr, fp);
png_set_sig_bytes(png_ptr, 8);
png_read_info(png_ptr, info_ptr);
int width = png_get_image_width(png_ptr, info_ptr);
int height = png_get_image_height(png_ptr, info_ptr);
png_byte color_type = png_get_color_type(png_ptr, info_ptr);
png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr);
int number_of_passes = png_set_interlace_handling(png_ptr);
png_read_update_info(png_ptr, info_ptr);
if (setjmp(png_jmpbuf(png_ptr))) {
return LOAD_TEXTURE__PNG_JMPBUF_FAILURE;
}
png_bytep* row_pointers = (png_bytep*)(malloc(sizeof(png_bytep) * height));
for (int y = 0; y < height; y++) {
row_pointers[y] = (png_byte*)(malloc(png_get_rowbytes(png_ptr,info_ptr)));
}
png_read_image(png_ptr, row_pointers);
unsigned char* data = malloc(height * png_get_rowbytes(png_ptr, info_ptr));
fclose(fp);
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
memcpy(data + (i * width * 4 + j * 4), &row_pointers[i][j * 4], 4);
}
}
for (int y = 0; y < height; y++) {
free(row_pointers[y]);
}
free(row_pointers);
GLuint texture_id = 0;
glGenTextures(1, &texture_id);
glBindTexture(GL_TEXTURE_2D, texture_id);
GLuint gl_color_type = glColorTypeFromPngColorType(color_type);
glTexImage2D (
GL_TEXTURE_2D, 0, gl_color_type, // GL_RGBA8
width, height, 0, GL_RGBA,
GL_UNSIGNED_BYTE, data
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
free(data);
*ptexture = texture_id;
return LOAD_TEXTURE__SUCCESS;
}

My code won't display sprite SDL2

The screen is always black. Tell me how to display the sprites correctly.
This is my code:
#define SHAPE_SIZE 32
void aff_map(SDL_Renderer *renderer)
{
SDL_Surface *img;
SDL_Texture *Tfloor
int x = 0;
int y = 0;
int map[4][8] = {{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0}};
SDL_Rect SrcR;
SDL_Rect DestR;
DestR.x = 0;
DestR.y = 0;
DestR.w = SHAPE_SIZE;
DestR.h = SHAPE_SIZE;
img = IMG_Load("floor.bmp");
Tfloor = SDL_CreateTextureFromSurface(renderer, img);
while (y < 4)
{
x = 0;
while (x < 8)
{
if (map[y][x] == 0)
SDL_RenderCopy(renderer, Tfloor, NULL, &DestR);
x++;
DestR.x = DestR.x + 32;
}
DestR.x = 0;
DestR.y = DestR.y + 32;
y++;
}
SDL_RenderPresent(renderer);
}
int main()
{
SDL_Window *screen;
SDL_Event evenements;
SDL_Renderer *renderer;
screen = SDL_CreateWindow("Zappy", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 8 * SHAPE_SIZE -32, 4 * SHAPE_SIZE, 0);
renderer = SDL_CreateRenderer(screen, -1, SDL_RENDERER_ACCELERATED);
SDL_RenderClear(renderer);
while (42)
{
SDL_WaitEvent(&evenements);
if (evenements.window.event == SDL_WINDOWEVENT_CLOSE ||
evenements.key.keysym.sym == SDLK_ESCAPE)
{
SDL_DestroyWindow(screen);
SDL_Quit();
break;
}
aff_map(renderer);
}
return 0;
}
The error message is explicit.
It says that the "floor.bmp" has not been converted to a surface.
It means that 'img' parameter is NULL.
Try the following :
Specify the full path to your picture in IMG_Load(), for example "/home/quentin/floor.bmp"
Check the return value of IMG_Load().

X11 XImage manipulation

I'm trying to pick up an image from my brand new window and then draw it back to the same window, just to train on XLib.
Here is my code :
#include<stdio.h>
#include<stdlib.h>
#include<stdint.h>
#include<X11/Xlib.h>
#include<X11/Xutil.h>
#include<sys/stat.h>
#include<sys/time.h>
#include<sys/types.h>
#include<unistd.h>
int main(int argc, char *argv[]) {
fd_set eventset;
fd_set zeroset;
// struct timeval timeout = {0, 0};
Display *display = 0;
int screen;
Window wnd;
XVisualInfo vinfo;
XSetWindowAttributes attr;
XEvent event;
XImage *bg;
Atom WM_message[2];
int run = 1;
FD_ZERO(&eventset);
FD_ZERO(&zeroset);
if(!(display = XOpenDisplay(0))) {
/* Display not found */
printf("Fail display.\n");
return 0;
}
screen = XDefaultScreen(display);
if(!XMatchVisualInfo(display, screen, 32, TrueColor, &vinfo)) {
if(!XMatchVisualInfo(display, screen, 24, TrueColor, &vinfo)) {
/* No proper color depth available */
XCloseDisplay(display); /* Close X communication */
printf("No found color display. Sorry.\n");
return 0;
}
}
attr.colormap = XCreateColormap(display, DefaultRootWindow(display), vinfo.visual, AllocNone);
attr.border_pixel = 0;
attr.background_pixel = 0x80000000;
attr.bit_gravity = NorthWestGravity;
attr.win_gravity = NorthWestGravity;
wnd = XCreateWindow(display, DefaultRootWindow(display), 0, 0, 300, 300, 0,
vinfo.depth, InputOutput, vinfo.visual,
CWColormap | CWBorderPixel | CWBackPixel | CWBitGravity | CWWinGravity, &attr);
/* Subscribe to window closing event */
WM_message[0] = XInternAtom(display, "WM_PROTOCOLS", 1);
WM_message[1] = XInternAtom(display, "WM_DELETE_WINDOW", 1);
XSetWMProtocols(display, wnd, WM_message, 2);
XFreeColormap(display, attr.colormap);
XSelectInput(display, wnd, ExposureMask | ButtonPressMask | KeyPressMask);
XMapWindow(display, wnd);
bg = XGetImage(display, XDefaultRootWindow(display), 0, 0, 300, 300, AllPlanes, ZPixmap);
// bg = XGetImage(display, wnd, 100, 100, 100, 100, AllPlanes, ZPixmap);
/* int x;
for(x = 0; x < 10000; x++) {
bg->data[x] = 0x80;
} */
XPutImage(display, wnd, XDefaultGC(display, screen), bg, 0, 0, 0, 0, 300, 300);
// XPutImage(display, wnd, XDefaultGC(display, screen), bg, 100, 100, 100, 100, 100, 100);
XMapWindow(display, wnd);
XFlush(display);
while(run) {
XNextEvent(display, &event);
switch(event.type) {
case Expose:
printf("w = %d, h = %d\n", event.xexpose.width, event.xexpose.height);
break;
case DestroyNotify:
run = 0;
break;
case ClientMessage:
{
if(event.xclient.message_type == WM_message[0]) {
if(event.xclient.data.l[0] == WM_message[1]) {
run = 0;
}
}
}
default:;
}
}
XDestroyImage(bg);
XDestroyWindow(display, wnd);
XCloseDisplay(display);
return 0;
}
This crash my program either on porteus and mobaxterm.
But this lines:
// bg = XGetImage(display, wnd, 100, 100, 100, 100, AllPlanes, ZPixmap);
/* int x;
for(x = 0; x < 10000; x++) {
bg->data[x] = 0x80;
} */
// XPutImage(display, wnd, XDefaultGC(display, screen), bg, 100, 100, 100, 100, 100, 100);
Doesn't crash my program... it just render nothing.
Can someone help me understand why do I experiment this weird behavior of X?
This is the error message I am getting:
X Error of failed request: BadMatch (invalid parameter attributes)
Major opcode of failed request: 72 (X_PutImage) Serial number of
failed request: 16 Current serial number in output stream: 18
After further reasearches and tries, I finnally found 2 facts :
First my post is mistaken :
this doesn't crash :
XPutImage(display, XDefaultRootWindow(display), XDefaultGC(display, screen), bg, 100, 100, 100, 100, 100, 100);
Those lines crash :
XPutImage(display, wnd, XDefaultGC(display, screen), bg, 0, 0, 0, 0, 300, 300);
XPutImage(display, wnd, XDefaultGC(display, screen), bg, 100, 100, 100, 100, 100, 100);
Second :
Writing on root window with default gc is alright because default gc is a gc corresponding to the default root window.
But using this GC for my own window is an error since I used color depth that can differ from root window.
So I have now this running well:
#include<stdio.h>
#include<stdlib.h>
#include<stdint.h>
#include<X11/Xlib.h>
#include<X11/Xutil.h>
#include<sys/stat.h>
#include<sys/time.h>
#include<sys/types.h>
#include<unistd.h>
int main(int argc, char *argv[]) {
fd_set eventset;
fd_set zeroset;
// struct timeval timeout = {0, 0};
Display *display = 0;
int screen;
Window wnd;
XVisualInfo vinfo;
XSetWindowAttributes attr;
XEvent event;
XImage *bg;
GC mainGC;
Atom WM_message[2];
int run = 1;
FD_ZERO(&eventset);
FD_ZERO(&zeroset);
if(!(display = XOpenDisplay(0))) {
/* Display not found */
printf("Fail display.\n");
return 0;
}
screen = XDefaultScreen(display);
if(!XMatchVisualInfo(display, screen, 32, TrueColor, &vinfo)) {
if(!XMatchVisualInfo(display, screen, 24, TrueColor, &vinfo)) {
/* No proper color depth available */
XCloseDisplay(display); /* Close X communication */
printf("No found color display. Sorry.\n");
return 0;
}
}
attr.colormap = XCreateColormap(display, DefaultRootWindow(display), vinfo.visual, AllocNone);
attr.border_pixel = 0;
attr.background_pixel = 0x80000000;
attr.bit_gravity = NorthWestGravity;
attr.win_gravity = NorthWestGravity;
wnd = XCreateWindow(display, DefaultRootWindow(display), 0, 0, 300, 300, 0,
vinfo.depth, InputOutput, vinfo.visual,
CWColormap | CWBorderPixel | CWBackPixel | CWBitGravity | CWWinGravity, &attr);
/* Subscribe to window closing event */
WM_message[0] = XInternAtom(display, "WM_PROTOCOLS", 1);
WM_message[1] = XInternAtom(display, "WM_DELETE_WINDOW", 1);
XSetWMProtocols(display, wnd, WM_message, 2);
XFreeColormap(display, attr.colormap);
XSelectInput(display, wnd, ExposureMask | ButtonPressMask | KeyPressMask);
XMapWindow(display, wnd);
XFlush(display);
mainGC = XCreateGC(display, wnd, 0, 0);
bg = XGetImage(display, wnd, 0, 0, 100, 100, AllPlanes, ZPixmap);
int x;
for(x = 0; x < 10000; x++) {
bg->data[x] = 0x80;
}
XPutImage(display, wnd, mainGC, bg, 0, 0, 100, 100, 100, 100);
while(run) {
XNextEvent(display, &event);
switch(event.type) {
case Expose:
printf("w = %d, h = %d\n", event.xexpose.width, event.xexpose.height);
break;
case DestroyNotify:
run = 0;
break;
case ClientMessage:
{
if(event.xclient.message_type == WM_message[0]) {
if(event.xclient.data.l[0] == WM_message[1]) {
run = 0;
}
}
}
default:;
}
}
XDestroyImage(bg);
XDestroyWindow(display, wnd);
XCloseDisplay(display);
return 0;
}

libX11: XPutImage first call

I've created XImage using XCreateImage and use XPutImage to display it on window, but XPutImage shows this picture only on second call of it. Why this happens?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
void draw(char *rgb_out, int w, int h)
{
int i = 0;
for (i = 0;i < w*h;i += 4) {
rgb_out[i + 1] = 0;
rgb_out[i + 2] = 0;
rgb_out[i + 3] = 0;
}
return;
}
XImage *create_ximage(Display *display, Visual *visual, int width, int height)
{
char *image32 = (char *)malloc(width * height * 4);
draw(image32, width, height);
return XCreateImage(display, visual, 24,
ZPixmap, 0, image32,
width, height, 32, 0);
}
int main(int argc, char **argv)
{
int win_b_color;
int win_w_color;
XEvent xev;
Window window;
GC gc;
Display *display = XOpenDisplay(NULL);
Visual *visual;
XImage *ximage;
win_b_color = BlackPixel(display, DefaultScreen(display));
win_w_color = BlackPixel(display, DefaultScreen(display));
window = XCreateSimpleWindow(display,
DefaultRootWindow(display),
0, 0, 600, 400, 0,
win_b_color, win_w_color);
gc = XCreateGC(display, window, 0, NULL);
visual = DefaultVisual(display, 0);
XMapWindow(display, window);
XFlush(display);
ximage = create_ximage(display, visual, 100, 100);
while (1) {
int r;
r = XPutImage(display, window,
gc, ximage, 0, 0, 0, 0,
100, 100);
printf("RES: %i\n", r);
XSync(display, 1);
XFlush(display);
getchar();
}
return 0;
}
The trick is to wait that the windows is mapped. You can do this by Expose event.
int main(int argc, char **argv)
{
int win_b_color;
int win_w_color;
XEvent xev;
Window window;
GC gc;
Display *display = XOpenDisplay(NULL);
Visual *visual;
XImage *ximage;
win_b_color = BlackPixel(display, DefaultScreen(display));
win_w_color = BlackPixel(display, DefaultScreen(display));
window = XCreateSimpleWindow(display,
DefaultRootWindow(display),
0, 0, 600, 400, 0,
win_b_color, win_w_color);
visual = DefaultVisual(display, 0);
XSelectInput(display, window, ExposureMask | KeyPressMask);
XMapWindow(display, window);
XFlush(display);
gc = XCreateGC(display, window, 0, NULL);
ximage = create_ximage(display, visual, 100, 100);
XEvent event;
bool exit = false;
while (!exit) {
int r;
XNextEvent(display, &event);
if (event.type == Expose)
{
r = XPutImage(display, window,
gc, ximage, 0, 0, 0, 0,
100, 100);
printf("RES: %i\n", r);
}
else if (event.type == KeyPress)
exit = true;
}
return 0;
}

Resources