Related
I am trying to create a simple X11 window, which should display a PNG file with transparent areas. I want the window itself to have no (opaque) background, so that the transparent areas in the PNG shows what there is behind the window.
tl;dr I cannot put an image on a semi-transparent window; it gives "Bad Match".
I can successfully create a semi-transparent window using XCreateWindow and XMatchVisualInfo :
XSetWindowAttributes attr;
attr.colormap = XCreateColormap(display, DefaultRootWindow(display),
vinfo.visual, AllocNone);
attr.border_pixel = 0;
attr.background_pixel = 0x80800000; // Red, semi-transparent
Window window = XCreateWindow(display, DefaultRootWindow(display), 0, 0,
width, height, 0, vinfo.depth, InputOutput, vinfo.visual,
CWColormap | CWBorderPixel | CWBackPixel, &attr);
(Full source code below)
I then create an image using :
// "image32" is a generated image - see source code below
XImage *ximage = XCreateImage(display, visual, DefaultDepth(display,DefaultScreen(display)),
ZPixmap, 0, image32, width, height, 32, 0);
And display the image during the Expose event :
XPutImage(display, window, DefaultGC(display, 0), ximage,
0, 0, 0, 0, width, height);
I compile with gcc test.c -L/usr/X11R6/lib -lX11 -lXrandr -o test and run with ./test :
X Error of failed request: BadMatch (invalid parameter attributes)
Major opcode of failed request: 72 (X_PutImage)
Serial number of failed request: 11
Current serial number in output stream: 12
Note : If I replace the lines creating the window (XCreateWindow) with these :
Window window = XCreateSimpleWindow(display, RootWindow(display, 0), 0, 0,
width, height, 1, 0, 0);
It displays a window correctly; however, there is no transparency.
I read the docs about XCreateWindow, XPutImage, XCreateImage and tried playing around with multiple parameters, unsuccessfully.
I have read this SO question and tried playing around with color depth; since the docs mentionned "Bad Match" can be also thrown for incorrect visual, I have checked that the same visual was sent at all places in my code.
Any help is appreciated.
Thanks!
Full source code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
// Window size
int height = 256, width = 256;
XImage *CreateTrueColorImage(Display *display, Visual *visual)
{
int i, j;
unsigned char *image32=(unsigned char *)malloc(width*height*4);
unsigned char *p=image32;
for(i=0; i<width; i++)
{
for(j=0; j<height;j++)
{
*p++ = i;
*p++ = i;
*p++ = j;
*p++ = j; // alpha channel (should progressively get transparent towards left)
}
}
// Replacing "DefaultDepth(display,DefaultScreen(display))" with a hardcoded
// 24 or 32 still doesn't work with XCreateWindow. XCreateSimpleWindow works
// with hardcoded 24, but not 32.
return XCreateImage(display, visual, DefaultDepth(display,DefaultScreen(display)),
ZPixmap, 0, image32, width, height, 32, 0);
}
int main(int argc, char **argv)
{
XImage *ximage;
Display *display = XOpenDisplay(NULL);
Visual *visual = DefaultVisual(display, 0);
XVisualInfo vinfo;
XMatchVisualInfo(display, DefaultScreen(display), 32, TrueColor, &vinfo);
XSetWindowAttributes attr;
attr.colormap = XCreateColormap(display, DefaultRootWindow(display),
vinfo.visual, AllocNone);
attr.border_pixel = 0;
attr.background_pixel = 0x80800000; // Red, semi-transparent
//Window window = XCreateSimpleWindow(display, RootWindow(display, 0), 0, 0,
// width, height, 1, 0, 0);
Window window = XCreateWindow(display, DefaultRootWindow(display), 0, 0,
width, height, 0, vinfo.depth, InputOutput, vinfo.visual,
CWColormap | CWBorderPixel | CWBackPixel, &attr);
ximage = CreateTrueColorImage(display, vinfo.visual);
XSelectInput(display, window, ButtonPressMask|ExposureMask);
XMapWindow(display, window);
while(1)
{
XEvent event;
XNextEvent(display, &event);
switch(event.type)
{
case Expose:
XPutImage(display, window, DefaultGC(display, 0), ximage,
0, 0, 0, 0, width, height);
break;
case ButtonPress:
exit(0);
}
}
}
I managed to make it work by making two changes.
First, instead of using DefaultGC(display, 0) you should create a GC for your specific window.
GC gc = XCreateGC(display, window, 0, 0);
With that if you hardcode the depth of XCreateImage to 32 it should work correctly.
And you can also use the depth provided by XVisualInfo like so
XCreateImage(display, vinfo.visual, vinfo.depth,
ZPixmap, 0, image32, width, height, 32, 0);
I wrote a little SDL2 app that reacts on resizing by rearranging its contents. It works quite nice on Windows 10, but not on my Linux machine.
Here's the MCVE that (hopefully) reproduces the problem:
#include <SDL2/SDL.h>
int main(int argc, char **argv)
{
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *w = SDL_CreateWindow("MCVE",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 250, 250,
SDL_WINDOW_ALLOW_HIGHDPI|SDL_WINDOW_RESIZABLE);
SDL_Renderer *r = SDL_CreateRenderer(w, -1, SDL_RENDERER_ACCELERATED);
SDL_Surface *shape = SDL_CreateRGBSurface(0, 500, 500, 32, 0, 0, 0, 0);
SDL_Rect rect = { .x = 100, .y = 100, .h = 300, .w = 300 };
SDL_FillRect(shape, &rect, SDL_MapRGB(shape->format, 0xff, 0, 0));
SDL_Texture *t = SDL_CreateTextureFromSurface(r, shape);
SDL_RenderClear(r);
SDL_RenderCopy(r, t, 0, 0);
SDL_RenderPresent(r);
SDL_Event ev;
while (SDL_WaitEvent(&ev))
{
switch (ev.type)
{
case SDL_QUIT:
SDL_Quit();
return 0;
case SDL_WINDOWEVENT:
if (ev.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
{
SDL_RenderClear(r);
SDL_RenderCopy(r, t, 0, 0);
SDL_RenderPresent(r);
}
}
}
return 1;
}
compile command:
gcc -std=c11 -Wall -Wextra -Wno-unused-parameter -pedantic -osdlresize sdlresize.c -lSDL2main -lSDL2
Note any error checking and cleanup is skipped just for brevity, the real code is here for reference.
What I get on my Linux machine when resizing the window often looks like this:
In case you can't see the image: the content isn't properly refreshed, it shows some area to the right and the bottom with contents of whatever is below my window on the desktop.
Is there anything wrong in my handling of the SDL_WINDOWEVENT_SIZE_CHANGED? The same thing happens if I handle SDL_WINDOWEVENT_RESIZED instead...
I am trying to write a little application in order to understand how evas works with X11.
I haven't find a full example in the documentation only some parts that I try to use.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <Evas.h>
#include <Evas_Engine_Software_X11.h>
/*
gcc -o evas_software_x11 evas_software_x11.c $(pkg-config --libs --cflags x11 evas)
*/
#define WIDTH 640
#define HEIGHT 480
int main(int argc, char **argv)
{
Evas *canevas;
Evas_Engine_Info_Software_X11 *einfo;
Display * display;
Window win;
display = XOpenDisplay(NULL);
int s;
XEvent e;
s = DefaultScreen(display);
win = XCreateSimpleWindow( display,
RootWindow(display, s),
10,10,WIDTH,HEIGHT,1,
BlackPixel(display, s),
WhitePixel(display, s));
XSelectInput(display, win, ExposureMask | KeyPressMask);
evas_init();
/*Création et configuration du canevas*/
canevas = evas_new();
evas_output_method_set(canevas, evas_render_method_lookup("software_x11"));
evas_output_size_set(canevas, WIDTH, HEIGHT);
evas_output_viewport_set(canevas, 0, 0, WIDTH, HEIGHT);
einfo = NULL;
einfo = (Evas_Engine_Info_Software_X11 *) evas_engine_info_get(canevas);
if(!einfo)
{
printf("einfo not valide\n");
exit(EXIT_FAILURE);
}
einfo->info.display = display;
einfo->info.visual = DefaultVisual(display, DefaultScreen(display));
einfo->info.colormap = DefaultColormap(display, DefaultScreen(display));
einfo->info.drawable = win;
einfo->info.depth = DefaultDepth(display, DefaultScreen(display));
evas_engine_info_set(canevas, (Evas_Engine_Info *) einfo);
/*Création d'un fond et d'un rectangle pour l'exemple*/
Evas_Object * bg, *rect;
bg = evas_object_rectangle_add(canevas);
evas_object_move(bg, 0, 0);
evas_object_resize(bg, WIDTH, HEIGHT);
evas_object_color_set(bg, 0, 128, 0, 128); // 50% opaque vert
eavs_object_show(bg);
rect = evas_object_rectangle_add(canevas);
evas_object_move(rect, 20, 20);
evas_object_resize(rect, 100, 100);
evas_object_color_set(rect, 255, 0, 0, 255); // opaque rouge
eavs_object_show(rect);
evas_render(canevas);
while(1) {
XnextEvent(display, &e);
if (e.type == Expose)
{
}
if (e.type == KeyPress)
break;
}
evas_free(canevas);
evas_shutdown();
XCloseDisplay(d);
return EXIT_SUCCESS;
}
When I compile it I have this error:
gcc -o evas_software_x11 evas_software_x11.c $(pkg-config --libs --cflags evas x11)
evas_software_x11.c: In function ‘main’:
evas_software_x11.c:45:14: erreur: ‘struct <anonymous>’ has no member named ‘display’
einfo->info.display = display;
^
But the part einfo->info.display = display comes from the official documentation :
https://build.enlightenment.org/job/nightly_efl_gcc_x86_64/lastSuccessfulBuild/artifact/doc/html/group__Evas__Output__Method.html#details
Any idea on where I have done an error?
The documentation is not up to date.
The info structure have a member named connection instead of display ( see file
Evas_Engine_Software_X11.h and http://lists.enlightenment.fr/enlightenment-devel/att-27663/expedite_merge_1.diff ).
I have a code written in Allegro 4 and am converting it to Allegro 5, but I'm having serious problems with functions that no longer exist in allegro 5, one of them is "blit"
BITMAP *bTile; // Bitmap do tile;
BITMAP *bMapa; // Bitmap do mapa;
BITMAP *bTexturas[20]; // Vetor de bitmap das texturas;
BITMAP *bChar; // Bitmap do personagem;
BITMAP *bMario[3];
// ##########################################################
int main()
{
int vResolucao_x = 640;
int vResolucao_y = 480;
init(vResolucao_x, vResolucao_y);
BITMAP *buffer = create_bitmap(vResolucao_x, vResolucao_y);
bTile = load_bitmap("Tiles/tile.bmp", NULL);
bChar = load_bitmap("Tiles/mario.bmp", NULL);
bMapa = create_bitmap(vResolucao_x, vResolucao_y);
// ############# - Carrega imagens do mario - ############
bMario[0] = create_bitmap(vTile,vTile);
bMario[1] = create_bitmap(vTile,vTile);
bMario[2] = create_bitmap(vTile,vTile);
blit(bChar, bMario[0], 0, 0, 0, 0, vTile, vTile);
blit(bChar, bMario[1], 33, 0, 0, 0, vTile, vTile);
blit(bChar, bMario[2], 66, 0, 0, 0, vTile, vTile);
// #######################################################
install_int(fGravidade,5);
fCarrega_Sprites_Mapa();
fCarrega_Mapa();
fMostra_Mapa();
draw_sprite(screen, bMapa, 0, 0 );
while (!key[KEY_ESC]) {
Virtually nothing of this my old code works with Allegro 5, so I'm doing the conversion as I can learn, but this blit function, can not find its like in allegro 5, another function that I can not find your simulate is: install_int (...)
Allegro 5 is essentially a completely new library. Here's a line-by-line translation, as best as can be done. Note that Allegro 5 uses a fundamentally different concept (event loop) and you should really take the time to learn how that works before diving into trying to convert your code.
ALLEGRO_BITMAP *bMario[3];
// ##########################################################
int main()
{
int vResolucao_x = 640;
int vResolucao_y = 480;
init(vResolucao_x, vResolucao_y);
ALLEGRO_BITMAP *buffer = al_create_bitmap(vResolucao_x, vResolucao_y);
bTile = al_load_bitmap("Tiles/tile.bmp");
bChar = al_load_bitmap("Tiles/mario.bmp");
bMapa = al_create_bitmap(vResolucao_x, vResolucao_y);
// ############# - Carrega imagens do mario - ############
bMario[0] = al_create_bitmap(vTile,vTile);
bMario[1] = al_create_bitmap(vTile,vTile);
bMario[2] = al_create_bitmap(vTile,vTile);
al_set_target_bitmap(bMario[0]);
al_draw_bitmap(bchar, 0, 0, 0);
al_set_target_bitmap(bMario[1]);
al_draw_bitmap(bchar, 33, 0, 0);
al_set_target_bitmap(bMario[2]);
al_draw_bitmap(bchar, 66, 0, 0);
al_set_target_backbuffer(display);
// #######################################################
fGravidade = al_create_timer(5 / 1000.0); // ALLEGRO_TIMER*
ALLEGRO_EVENT_QUEUE *queue = al_create_event_queue();
al_register_event_source(queue, al_get_timer_event_source(gfGravidade));
al_register_event_source(queue, al_get_keyboard_event_source());
fCarrega_Sprites_Mapa();
fCarrega_Mapa();
fMostra_Mapa();
al_draw_bitmap(bMapa, 0, 0, 0);
al_flip_display();
while (true) {
ALLEGRO_EVENT event;
al_wait_for_event(queue, &event);
if (event.type == ALLEGRO_EVENT_TIMER) {
// fGravidade ticked
}
else if (event.type == ALLEGRO_EVENT_KEY_CHAR) {
if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) {
break;
}
}
}
I've got a simple Cairo program that attempts to draw a diagonal consisting of dots in a 600x600 PNG. However, the output appears to be truncated whenever I attempt to render all of the dots using a single call to cairo_stroke().
Specifically, consider the following program:
#include <cairo/cairo.h>
int main(int argc, char **argv)
{
cairo_surface_t *surface =
cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 300, 300);
cairo_t *cr = cairo_create(surface);
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_set_line_width(cr, 5);
for (double x = 0.0; x <= 300; x += 10) {
cairo_move_to(cr, x, x);
cairo_close_path(cr);
cairo_stroke(cr);
}
cairo_surface_write_to_png(surface, "output.png");
cairo_destroy(cr);
cairo_surface_destroy(surface);
return 0;
}
which generates the following correct output:
If I move the
cairo_stroke(cr);
outside of the for loop, then the following incorrect output is generated instead:
.
Can someone else explain why the second attempt fails? I suspect I must be doing something wrong here...
#include <cairo/cairo.h>
int main(int argc, char **argv)
{
cairo_surface_t *surface =
cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 300, 300);
cairo_t *cr = cairo_create(surface);
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_set_line_width(cr, 5);
for (double x = 0.0; x <= 300; x += 10) {
cairo_move_to(cr, x, x);
cairo_close_path(cr);
}
cairo_stroke(cr); /* moved here */
cairo_surface_write_to_png(surface, "output.png");
cairo_destroy(cr);
cairo_surface_destroy(surface);
return 0;
}
Moving cairo_stroke(cr) outside the for-loop seems to generate equal output with Cairo version 1.10.1.
Compiled as: gcc test.c `pkg-config --libs --cflags gtk+-2.0` -std=c99 -lcairo