So I was trying to display one translucent farbfeld image on top of another, often opaque farbfeld image (named f2.ff and f.ff in order) with the use of XRender to get the alpha compositing but due to the lack of examples on XRender and me being new to Xlib it does not work :)
and the translucent image which should have been displayed on top(f2.ff) is flickering weirdly.
Here is the code :
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include "stb_image_resize.h"
#include <string.h>
#include <X11/Xlib.h>
#include <X11/extensions/Xrender.h>
typedef struct XWindow XWindow;
struct XWindow
{
Display * dpy;
Window root;
Visual * vis;
Colormap cmap;
XWindowAttributes attr;
XSetWindowAttributes swa;
Window win;
int screen;
unsigned int width;
unsigned int height;
Atom wm_delete_window;
};
struct head
{
char ma [7];
unsigned int w;
unsigned int h;
};
unsigned char * ffread(const char * path,unsigned int * w,unsigned int * h)
{
struct head * hh;
size_t filelen;
unsigned char * buffer;
unsigned short temp=0;
size_t i=0;
FILE * file;
file=fopen(path,"rb");
if(file == NULL)
{
puts("cant open the file");
exit(1);
}
hh=malloc(16*sizeof(unsigned short));
fread(hh,2,15,file);
if(strcmp("farbfeld",hh->ma))
{
puts("Invalid file format");
exit(1);
}
*w=ntohl(hh->w);
*h=ntohl(hh->h);
printf("%d %d\n",*w,*h);
filelen=(*w)*(*h)*4;
buffer=malloc(filelen*sizeof(char));
fseek(file,16,SEEK_SET);
for(; i<filelen; i++)
{
fread(&temp,2,1,file);
if(i%4==0||i==0)
{
buffer[i+2]=(ntohs(temp)/257);
}
else if(i%2==0)
{
buffer[i-2]=(ntohs(temp)/257);
}
else
{
buffer[i]=(ntohs(temp)/257);
}
}
fclose(file);
return buffer;
}
int main(void)
{
XWindow xw;
unsigned char * data;
unsigned char * bdata;
unsigned char * im2;
unsigned int wim=0,him=0, w=0,h=0, wim2=0,him2 =0;
XImage * image;
Pixmap pix;
Picture pic;
Picture picdst;
GC gc;
XImage * imagebg;
Pixmap pix2;
Picture pic2bg;
memset(&xw, 0, sizeof xw);
xw.dpy = XOpenDisplay(NULL);
if(!xw.dpy) puts("Could not open a display; perhaps $DISPLAY is not set?");
xw.root = DefaultRootWindow(xw.dpy);
xw.screen = XDefaultScreen(xw.dpy);
xw.vis = XDefaultVisual(xw.dpy, xw.screen);
xw.cmap = XCreateColormap(xw.dpy,xw.root,xw.vis,AllocNone);
xw.swa.colormap = xw.cmap;
xw.swa.event_mask =
ExposureMask | KeyPressMask | KeyReleaseMask |
ButtonPress | ButtonReleaseMask| ButtonMotionMask |
Button1MotionMask | Button3MotionMask | Button4MotionMask | Button5MotionMask|
PointerMotionMask | KeymapStateMask;
h=DisplayHeight(xw.dpy,xw.screen);
w=DisplayWidth(xw.dpy,xw.screen);
xw.win = XCreateWindow(xw.dpy, xw.root, 0, 0, w, h, 0,
XDefaultDepth(xw.dpy, xw.screen), InputOutput,
xw.vis, CWEventMask | CWColormap, &xw.swa);
XStoreName(xw.dpy, xw.win, "X11");
XMapWindow(xw.dpy, xw.win);
xw.wm_delete_window = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False);
XSetWMProtocols(xw.dpy, xw.win, &xw.wm_delete_window, 1);
XGetWindowAttributes(xw.dpy, xw.win, &xw.attr);
xw.width = (unsigned int)xw.attr.width;
xw.height = (unsigned int)xw.attr.height;
data=ffread("./f.ff",&wim,&him);
bdata=(unsigned char *)malloc(w*h*4);
stbir_resize_uint8(data,wim,him,0,bdata,w,h,0,4);
im2=ffread("./f2.ff",&wim2,&him2);
picdst=XRenderCreatePicture(xw.dpy,xw.win,XRenderFindStandardFormat(xw.dpy, PictStandardRGB24),0,0);
image=XCreateImage(xw.dpy,CopyFromParent,32,ZPixmap, 0,(char *)im2,wim2, him2,4*8, 4 * wim2);
pix=XCreatePixmap(xw.dpy,xw.win,wim2,him2,32);
gc=XCreateGC(xw.dpy,pix,0,NULL);
XPutImage(xw.dpy,pix,gc,image,0,0,0,0,wim2,him2);
pic=XRenderCreatePicture(xw.dpy,pix,XRenderFindStandardFormat(xw.dpy, PictStandardARGB32),0,0);
imagebg =XCreateImage(xw.dpy,CopyFromParent,32,ZPixmap, 0,(char *)bdata,w, h,4*8, 4 * w);
pix2=XCreatePixmap(xw.dpy,xw.win,w,h,32);
gc=XCreateGC(xw.dpy,pix2,0,NULL);
XPutImage(xw.dpy,pix2,gc,imagebg,0,0,0,0,w,h);
pic2bg=XRenderCreatePicture(xw.dpy,pix2,XRenderFindStandardFormat(xw.dpy, PictStandardARGB32),0,0);
while(1)
{
pic2bg=XRenderCreatePicture(xw.dpy,pix2,XRenderFindStandardFormat(xw.dpy, PictStandardARGB32),0,0);
picdst=XRenderCreatePicture(xw.dpy,xw.win,XRenderFindStandardFormat(xw.dpy, PictStandardRGB24),0,0);
pic=XRenderCreatePicture(xw.dpy,pix,XRenderFindStandardFormat(xw.dpy, PictStandardARGB32),0,0);
XRenderComposite(xw.dpy,PictOpSrc,pic,None,picdst,0,0,0,0,0,0,wim2,him2);
XRenderComposite(xw.dpy,PictOpSrc,pic2bg,None,picdst,0,0,0,0,0,0,w,h);
XRenderFreePicture(xw.dpy,picdst);
XRenderFreePicture(xw.dpy,pic2bg);
XRenderFreePicture(xw.dpy,pic);
}
}
I have a Linux desktop with 2 open windows: a terminal and a browser. I'm trying to get the name of those windows with libxcb. Here's my code based on examples I found at https://www.systutorials.com/docs/linux/man/3-xcb_query_tree_reply/
Here's my code:
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <xcb/xcb.h>
void get_children(xcb_connection_t* c, xcb_window_t window, xcb_window_t** children, int* count)
{
*count = 0;
*children = NULL;
auto cookie = xcb_query_tree(c, window);
auto reply = xcb_query_tree_reply(c, cookie, NULL);
if (reply)
{
*count = xcb_query_tree_children_length(reply);
*children = xcb_query_tree_children(reply);
free(reply);
}
}
void get_name(xcb_connection_t* c, xcb_window_t window, char** name, int* length)
{
*length = 0;
*name = NULL;
auto cookie = xcb_get_property(c, 0, window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 0, 0);
auto reply = xcb_get_property_reply(c, cookie, NULL);
if (reply)
{
*length = xcb_get_property_value_length(reply);
*name = (char*)xcb_get_property_value(reply);
free(reply);
}
}
int main()
{
auto c = xcb_connect(":0.0", NULL);
auto screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
auto rootWindow = screen->root;
int nChildren;
xcb_window_t* children;
get_children(c, screen->root, &children, &nChildren);
for (int i = 0; i < nChildren; i++)
{
auto wid = children[i];
int length;
char* name;
get_name(c, wid, &name, &length);
printf("%u %d\n", wid, length);
}
return 0;
}
This returns 40 windows all with their name's length of 0. For example:
20971989 0
20971802 0
20972112 0
20972308 0
... (truncated for brevity)
I'm trying to get something like the output of wmctrl -l.
What am I doing wrong?
I figured out the problem. I needed to add a length to the xcb_get_property function call. The following code works.
auto cookie = xcb_get_property(c, 0, window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 0, 1000);
First post, so will try and be brief until need to add more. Ported an app from macOS to NI LabWindows/CVI, in "C", then to port to GTK3 and trying to grasp the updating GUI from external thread concept. I've read the gnome documentation and searched on here, and everywhere, but not finding similar usage, or not grasping the updating the GUI from separate thread. I have experimented with g_idle_add() as follows.
int main(int argc, char* argv[])
{
gtk_init(&argc, &argv); // init Gtk
gtk_start_button = GTK_WIDGET(gtk_builder_get_object(builder,"start_button"));
gtk_main();
return EXIT_SUCCESS;
}
void start_button_clicked_cb(GtkWidget *widget, gpointer data)
{
printf("\nStart Button Pressed\n");
run_tests();
}
void run_tests( void )
{
GThread *start_testing_thread;
start_testing_thread = g_thread_new("", &start_testing, NULL);
}
void *start_testing (void *data)
{
pause(5);
}
void pause( double pause_time)
{
char string[33];
while( (double)pause_time > (double)0 )
{
sprintf( string, "Pausing %02.1f", pause_time );
printf(string);
//test_name( string );
g_idle_add(test_name_gui, string);
g_usleep(100000); // uSecs for 100 mSecs
pause_time -= 0.1;
}
}
void test_name_gui(gpointer user_data)
{
GtkTextBuffer* buffer = gtk_text_buffer_new(NULL);
char temp[99];
int error = -1;
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW (gtktextview_test_name));
sprintf(temp,"\n%s gui\n",(char*)user_data);
printf(temp);
if(!g_utf8_validate(user_data,-1,NULL))
{
error = 3;
}
gtk_text_buffer_set_text (buffer, (char*)user_data, -1);
printf("\nTest Name gui\n");
g_object_unref(buffer);
return G_SOURCE_REMOVE;
}
Context: I am currently trying to practice my C skills a little bit with the SDL 2.0.7 and SDL2_image-2.0.2.
Problem: I get an error message during the execution of my program "IMG_Load: Couldn't open xxx.png". The error seems stupid as it is very explicit: "i can't find the image", but as the image is in the appropriate folder... I think I need a fresh eye to spot the stupid mistake.
Platform: Windows 10
IDE: Visual Studio 2017
Steps done to solve the problem:
1) Tried to reduce my code lenght/functionalities to its minimum. Result: Error is still here.
2) I created a new project and copy/pasted the simplified code. Result: On the new project, there is no error, everything is working fine.
3) I compared project's options and the folder. To me they are the same:
It shouldn't be useful but just in case, here is my:
Code sample:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_render.h>
#include "SDL_timer.h"
int main(int argc, char *argv[])
{
printf("argc = %d\n", argc);
for (int i = 0; i < argc; ++i)
{
printf("argv[ %d ] = %s\n", i, argv[i]);
}
SDL_Window* pWindow = NULL;
SDL_Renderer* pRenderer = NULL;
SDL_Texture* pTexture = NULL;
SDL_Surface* pLoadedSurface = NULL;
SDL_Rect* tileClipsArray = NULL;
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER))
{
fprintf(stderr, "Erreur d'initialisation de la SDL : %s\n", SDL_GetError());
}
//Initialize PNG loading
int imgFlags = IMG_INIT_PNG;
if (!(IMG_Init(imgFlags) & imgFlags))
{
printf("IMG_Load: %s\n", IMG_GetError());
}
pWindow = SDL_CreateWindow("TestLoadingImage",
SDL_WINDOWPOS_CENTERED, // initial X position.
SDL_WINDOWPOS_CENTERED, // Initial Y position.
640, // Width, in pixels.
480, // Height, in pixels.
SDL_WINDOW_OPENGL); // Window flags
assert(NULL != pWindow);
//Create renderer for the window
pRenderer = SDL_CreateRenderer(pWindow,
-1, // Index of the rendering driver to initialize, -1 to initialize the first one supporting the requested flags.
SDL_RENDERER_ACCELERATED
| SDL_RENDERER_PRESENTVSYNC); // RendererFlags
assert(NULL != pRenderer);
//Initialize renderer color
SDL_SetRenderDrawColor(pRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
pLoadedSurface = IMG_Load("GroundTiles.png");
if (NULL == pLoadedSurface)
{
printf("IMG_Load: %s\n", IMG_GetError());
assert(NULL != pLoadedSurface);
}
//Create texture from surface pixels
pTexture = SDL_CreateTextureFromSurface(pRenderer, pLoadedSurface);
assert(NULL != pTexture);
//Get image dimensions
const int textureWidth = pLoadedSurface->w;
const int textureHeight = pLoadedSurface->h;
const int tileClipWidth = 128;
const int tileClipHeight = 128;
const int nbLines = textureHeight / tileClipHeight;
const int nbColumns = textureWidth / tileClipWidth;
const int nbTileClips = nbLines + nbColumns;
tileClipsArray = malloc(nbTileClips * sizeof(SDL_Rect));
int tileClipIndex = 0;
for (int tileClipLineIndex = 0; tileClipLineIndex < nbLines; ++tileClipLineIndex)
{
for (int tileClipColumnIndex = 0; tileClipColumnIndex < nbColumns; ++tileClipColumnIndex)
{
tileClipsArray[tileClipIndex].x = tileClipColumnIndex * tileClipWidth;
tileClipsArray[tileClipIndex].y = tileClipLineIndex * tileClipHeight;
tileClipsArray[tileClipIndex].w = tileClipWidth;
tileClipsArray[tileClipIndex].h = tileClipHeight;
++tileClipIndex;
}
}
//Get rid of old loaded surface
SDL_FreeSurface(pLoadedSurface);
pLoadedSurface = NULL;
int canLoop = 1;
SDL_Event event;
int lastUpdate = SDL_GetTicks();
int now = 0;
int timeToSpendPerClip = 5000;
int timeSpentwithThisClip = 0;
int clipToUse = 0;
while (canLoop)
{
now = SDL_GetTicks();
if (now - lastUpdate > 16)
{
timeSpentwithThisClip += now - lastUpdate;
lastUpdate = now;
// We are processing all the events received this frame.
while (SDL_PollEvent(&event))
{
// We need to know what kind of event we are dealing with.
switch (event.type)
{
case SDL_QUIT:
canLoop = 0;
break;
}
}
SDL_RenderClear(pRenderer);
if (timeSpentwithThisClip > timeToSpendPerClip)
{
clipToUse = rand() % 4;
timeSpentwithThisClip = 0;
}
// Set rendering space and render to screen.
SDL_Rect renderQuad;
renderQuad.x = 50;
renderQuad.y = 50;
renderQuad.w = tileClipsArray[clipToUse].w;
renderQuad.h = tileClipsArray[clipToUse].h;
SDL_RenderCopyEx(pRenderer, pTexture, &tileClipsArray[clipToUse], &renderQuad, 0.0, NULL, SDL_FLIP_NONE);
SDL_RenderPresent(pRenderer);
}
}
SDL_DestroyTexture(pTexture);
free(tileClipsArray);
SDL_DestroyRenderer(pRenderer);
pRenderer = NULL;
SDL_DestroyWindow(pWindow);
pWindow = NULL;
IMG_Quit();
SDL_Quit();
return EXIT_SUCCESS;
}
I'm probably going to copy/paste all my files from the project 1 into the project 2, but I would like to understand my mistake!
I'm writing a very simple battery status icon using GTK.
It's a GtkStatusIcon that shows the current battery status in a tooltip.
In order to obtain battery info I parse the output of the commandacpithat is usually similar to:
Battery 0: Discharging, 70%, 01:00:00 remaining
My battery status icon runs just fine but when I suspend my computer and then I resume it, my program crashes with segmentation fault.
The whole code is this (I've commented it):
#include <gtk/gtk.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#define DEFAULT_ARRAY_SIZE 3
#define DEFAULT_TIME_UPDATE 5
const gchar * acpi_command = "acpi";
typedef enum batteryState{
CHARGING,
DISCHARGING,
} BatteryState;
typedef struct batteryTray {
GtkStatusIcon * tray_icon;
gchar * tooltip;
gchar * icon;
} BatteryTray;
typedef struct battery {
gchar * status;
gint percentage;
gchar * extra;
BatteryTray batteryTray;
BatteryState batteryState;
} Battery;
static void update_status_battery(Battery * battery);
static gboolean update_status_tray(Battery * battery);
static gchar * get_status_icon_name(Battery * battery);
static void create_tray_icon(Battery * battery);
static void parse_acpi_output(Battery * battery, gchar * acpi_output);
static char * get_acpi_output(const gchar * acpi_command);
static void update_status_battery(Battery * battery)
{
if(strcmp(battery->status, "Charging") == 0)
battery->batteryState = CHARGING;
else if(strcmp(battery->status, "Discharging") == 0)
battery->batteryState = DISCHARGING;
}
static gboolean update_status_tray(Battery * battery)
{
gchar * icon_name = get_status_icon_name(battery);
gchar * acpi_out = get_acpi_output(acpi_command);
parse_acpi_output(battery, acpi_out);
update_status_battery(battery);
battery->batteryTray.tooltip = g_strdup_printf("%s (%d%%) %s",
battery->status,
battery->percentage,
battery->extra);
gtk_status_icon_set_tooltip_text(battery->batteryTray.tray_icon,
battery->batteryTray.tooltip);
gtk_status_icon_set_from_icon_name(battery->batteryTray.tray_icon,
icon_name);
return TRUE;
}
static gchar * get_status_icon_name(Battery * battery)
{
GString * icon_name = g_string_new("notification-battery");
if (battery->percentage < 20)
g_string_append(icon_name, "-low");
else if (battery->percentage < 40)
g_string_append(icon_name, "-020");
else if (battery->percentage < 80)
g_string_append(icon_name, "-060");
else
g_string_append(icon_name, "-100");
if(battery->batteryState == CHARGING) {
g_string_append(icon_name, "-plugged");
}
return icon_name->str;
}
static void create_tray_icon(Battery * battery)
{
/* create the gtkstatusicon and call the function
`update_status_tray` every 5 seconds */
battery->batteryTray.tray_icon = gtk_status_icon_new();
battery->batteryTray.tooltip = "battery";
gtk_status_icon_set_tooltip(battery->batteryTray.tray_icon,
battery->batteryTray.tooltip);
gtk_status_icon_set_visible(battery->batteryTray.tray_icon,
TRUE);
update_status_tray(battery);
g_timeout_add_seconds(DEFAULT_TIME_UPDATE, (GSourceFunc) update_status_tray, battery);
}
static void parse_acpi_output(Battery * battery, gchar * acpi_output)
{
/* acpi output is like:
Battery 0: Discharging, 70%, 01:00:00 remaining
In this function I assign "Discharging" to battery->status
70 to battery->percentage
and "01:00:00 remaining" to battery->extra
I use strtok to split the acpi output into tokens delimited by ',' and
then, if there's a blank character ' ' in front of a token, i 'remove' it.
*/
gint i = 0;
gchar * t;
gchar ** values_array;
/* find the position of ':' in the string */
int pos = strchr(acpi_output, ':') - acpi_output;
t = strtok(acpi_output + pos + 1, ",");
values_array = malloc(DEFAULT_ARRAY_SIZE * sizeof(gchar));
while(t != NULL) {
/* 'remove' the blank character */
values_array[i++] = t[0] == ' ' ? t + 1 : t;
t = strtok(NULL, ",");
}
/* remove newline */
if(values_array[2][strlen(values_array[2]) - 1] == '\n') {
values_array[2][strlen(values_array[2]) - 1] = '\0';
}
battery->status = values_array[0];
battery->percentage = atoi(values_array[1]);
battery->extra = values_array[2];
free(values_array);
}
static gchar * get_acpi_output(const gchar * acpi_command)
{
gchar * output;
GError * error = NULL;
/* assign the output of the acpi command to 'output' */
g_spawn_command_line_sync(acpi_command, &output, NULL, NULL, &error);
return output;
}
int main(int argc, char ** argv)
{
Battery battery;
gtk_init(&argc, &argv);
create_tray_icon(&battery);
gtk_main();
return 0;
}
I hope that someone can help me because I really can't understand.
There are a number of places where you could do more error checking; perhaps something outside of your code fails during wakeup. For example, you don't check the results of g_spawn_command_line_sync -- you assume that output is pointing to a valid string on return, but perhaps it's not always. And you assume, but don't actually confirm, that the output of the tool you run has a certain number of tokens in it, but perhaps it's not always.