xlib get icon data to draw on a window - c

For my program i need other programs icons, which i have saved in a list:
Window *windowlist(Display *display, unsigned long *length)
{
Atom prop = XInternAtom(display, "_NET_CLIENT_LIST", False);
Atom type;
int form;
unsigned long remain;
unsigned char *list;
if(XGetWindowProperty(display, XDefaultRootWindow(display), prop, 0, 1024, False, XA_WINDOW, &type, &form, length, &remain, &list) != Success)
{
return 0;
}
return (Window*)list;
}
I could only find solutions using Imlib2, but am searching for an easier way if possible. Basically I only want to draw these icons on a window.
Atom prop = XInternAtom(display, "_NET_WM_ICON", False);
XGetWindowProperty(display, window, prop, 0, 1 or what i need to do here?, False, XA_CARDINAl, &actual_type_return, &actual_format_return, &nitems_return, &bytes_after_return, &data);
width = (int)data;
height = (int)data;
size = width * height;
XGetWindowProperty(display, window, prop, 2 ???, size, False, XA_CARDINAl, &actual_type_return, &actual_format_return, &nitems_return, &bytes_after_return, &data);
Pixmap = ....
I really have no clue what to do. Does someone have an example of how to get the right data or how to use it (e.g. for a pixmap)?
Thank you!
Edit:
Now i have a other solution (its in the source of libwnck) with XWMHints:
Pixmap icon;
int width, height;
XWMHints *hints;
hints = XGetWMHints(display, window);
if(hints)
{
if(hints->flags & IconPixmapHint)
icon = hints->icon_pixmap;
if(icon != 0)
{
get_pixmap_geometry(icon, &width, &height) //its just XGetGeometry stuff
XCopyArea(display, icon, drawable, gc, 0, 0, width, height 0, 0);
}
}
Something like that.

Use this
gulong i=0;
int result;
Atom type;
int format;
gulong bytes_after;
gulong *data;
gulong nitems;
XGetWindowProperty (display,
w,
prop,
0, G_MAXLONG,
False, XA_CARDINAL , &type, &format, &nitems,
&bytes_after, ((guchar **)&data));

Related

SDL - Update Surface in C

i use SDL Lib and SDL_TTF Lib
I have a code that allows you to enter text
And then display the text on my window
so here the code
TTF_Init();
SDL_Init(SDL_INIT_VIDEO);
TTF_Font * font = TTF_OpenFont("C:\\Windows\\Fonts\\Arial.ttf", 25);
SDL_Color color = { 255, 255, 255 };
SDL_Surface * surface = TTF_RenderText_Solid(font,"", color);
SDL_Window * window = SDL_CreateWindow("SDL_ttf in SDL2",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640,
480, 0);
SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);
SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, surface);
int texW = 200;
int texH = 200;
SDL_QueryTexture(texture, NULL, NULL, &texW, &texH);
SDL_Rect dstrect = { 200, 200, texW, texH };
SDL_RenderCopy(renderer, texture, NULL, &dstrect);
SDL_RenderPresent(renderer);
while (program_launched)
{
SDL_bool has_type = SDL_FALSE;
SDL_WaitEvent(&event);
if(event.type == SDL_QUIT)
program_launched = SDL_FALSE;
else if( event.type == SDL_KEYDOWN)
{
if(event.key.keysym.sym == SDLK_BACKSPACE && len)
{
rep[len - 1] = 0;
len--;
has_type = SDL_TRUE;
}
if(event.key.keysym.sym == SDLK_v && (SDL_GetModState() & KMOD_CTRL) && SDL_HasClipboardText())
{
char *tmp = SDL_GetClipboardText();
size_t l = strlen(tmp);
size_t l_copy = len + l < LEN_MAX ? l : LEN_MAX - len;
strncpy(rep + len, tmp, l_copy);
len += l_copy;
SDL_free(tmp);
has_type = SDL_TRUE;
}
if(event.key.keysym.sym == SDLK_c && (SDL_GetModState() & KMOD_CTRL))
SDL_SetClipboardText(rep);
}
else if(event.type == SDL_TEXTINPUT)
{
size_t l = strlen(event.text.text);
size_t l_copy = len + l < LEN_MAX ? l : LEN_MAX - len;
strncpy(rep + len, event.text.text, l_copy);
len += l_copy;
has_type = SDL_TRUE;
}
if(has_type)
surface = TTF_RenderText_Solid(font,rep, color);
texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_QueryTexture(texture, NULL, NULL, &texW, &texH);
SDL_Rect dstrect = { 0, 0, texW, texH };
SDL_RenderCopy(renderer, texture, NULL, &dstrect);
SDL_RenderPresent(renderer);
}
It's to (has-type) that I display the buff (rep)
But my problem is here:
I can write and display in the window a text
But if i do a backspace and i write
The texts overlap because the window, at least the rectangle is not updated
Is it possible to delete the content of my window (to display the buff without overlapping) ?
I use this documentation
https://www.libsdl.org/projects/SDL_ttf/docs/SDL_ttf.pdf
I had tried with this function: SDL_UpdateWindowSurface(window);
But nothing helps
Compiler: GCC
OS: Windows
It's because once you've outputed something to the screen, it stays there unless you clear it or put something above it.
Think of it as a painter plotting things on his canvas. If you want to overwrite something, you have to overwrite the previous shape.
The simplest way to deal with this would be to call SDL_RenderClear at the beginning of every draw, it clears the whole screen clean, and then every time you render something it'll never overlap the previous stuff.

Xlib image grab fails in XGetImage

Cookie cuttered (from supposedly working code) a trivial C program to perform a Xlib image grab using XGetImage(). At this point I'm not trying to process the image, this is just a proof-of-concept to see if the image grab works - and it doesn't. The XGetImage() call fails like:
X Error of failed request: BadMatch (invalid parameter attributes)
Major opcode of failed request: 73 (X_GetImage)
Serial number of failed request: 21
Current serial number in output stream: 21
I spent a fair amount of time researching this and apparently this problem has plagued other developers and no definitive answer was ever arrived at. Does someone know how I could go about resolving this? I can tell from the printf that the window of interest was correctly identified. The XMapRaised() is a suggestion from a prior thread on this problem, but doesn't seem to help. Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "/usr/include/X11/Xlib.h"
Window findScidWindow(Display *display )
{
Bool found = False;
Window rootWindow = RootWindow(display, DefaultScreen(display));
Atom atom = XInternAtom(display, "_NET_CLIENT_LIST", True);
Atom actualType;
int format;
unsigned long numItems;
unsigned long bytesAfter;
unsigned char *data = '\0';
Window *list;
char *windowName;
int status = XGetWindowProperty(display, rootWindow, atom, 0L, (~0L), False,
AnyPropertyType, &actualType, &format, &numItems, &bytesAfter, &data);
list = (Window *)data;
if (status >= Success && numItems)
{
for (int i = 0; i < numItems; ++i)
{
status = XFetchName(display, list[i], &windowName);
if (status >= Success)
{
if(strstr(windowName, "Scid vs. PC") != NULL)
{
XFree(windowName);
XFree(data);
return list[i];
}
}
}
}
}
void
main( int argc, char*argv )
{
Display* d = XOpenDisplay(":0.0");
XImage *image;
Window root = (Window)0x0560003b; /* obtained via 'wmctrl -l -G' */
Window ScidWindow = findScidWindow(d);
XWindowAttributes attrib;
XGetWindowAttributes(d, ScidWindow, &attrib);
int width = attrib.width;
int height = attrib.height;
printf("width: %d height: %d\n",width,height);
XMapRaised(d, root);
/* coordinates 438,110 obtained via 'wmctrl -l -G' */
image = XGetImage( d, ScidWindow, 438, 110, width, height, AllPlanes, ZPixmap);
}
The issue is
image = XGetImage( d, ScidWindow, 438, 110, width, height, AllPlanes, ZPixmap);
uses x = 438 and y = 110 that is particular a problem if x + width is actually bigger as the window width (same for the height)
So here I have to assume you're not attempting to crop the window image but rather want to take a plain raw screenshot, then you just need to pass 0 for x and y:
image = XGetImage( d, ScidWindow, 0, 0, width, height, AllPlanes, ZPixmap);
The explanation is that the coordination system is not the full display or screen but the one of the window you are grabbing. Means the window starts at (0, 0).
This took me also some time to figure out.

XGetImage is mangled for chrome, firefox, electron, when using XCompositeRedirectWindow

I am attempting to create a thumbnailer (for i3wm on linux) which generates an icon from a screenshot for all the available windows. The aim being to replicate something like how windows uses Alt-Tab to produce a pane of windows to choose from;
The current prototype uses pygtk to generate the dialog, and it creates thumbnails of the windows in the _NET_CLIENT_LIST using XGetImage where the windows have been redirected using XCompositeRedirectWindow. It works pretty well except for that images captured from windows which are browsers, (e.g. firefox, chrome, electron) are mangled, or wrong;
Basically, tools like xwd, scrot and import don't work for the hidden windows in i3, presumably because they are unmapped. So I have pulled some code together to create the thumbnails. The core of it is based on an example using XCompositeRedirectWindow from X11/extensions/Xcomposite.h from here.
My attempt at creating a short example is here;
https://gist.github.com/tolland/4bb1e97db258b92618adfb783ce66fac
it can be compiled with;
$ gcc example.c -lX11 -lXcomposite -lXrender -lpng -o example
and then to output png files for each of the windows;
$ mkdir -p /tmp/png_out && ./example
will produce pngs for each of the images
window found was 58720312
found window name for 58720312 : build : sudo
filename /tmp/png_out/58720312_test3.png
window found was 79691781
found window name for 79691781 : .xsession-errors - glogg
filename /tmp/png_out/79691781_test3.png
window found was 62914576
found window name for 62914576 : Edit - Stack Overflow - Mozilla Firefox
filename /tmp/png_out/62914576_test3.png
So the code I am currently using to walk the _NET_CLIENT_LIST is this;
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <libpng16/png.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xrender.h>
//Compile hint: gcc -shared -O3 -lX11 -fPIC -Wl,-soname,prtscn -o prtscn.so prtscn.c
typedef int bool;
#define true 1
#define false 0
const int DEBUG = 0;
void getScreen2(const int, const int, const int, const int, const XID);
void write_png_for_image(XImage *image, XID xid, int width, int height,
char *filename);
typedef int (*handler)(Display *, XErrorEvent *);
XID getWindows(Display *display, Window parent, Window window, XID xid,
int depth);
int main() {
Display *display = XOpenDisplay(NULL);
Window root = DefaultRootWindow(display);
uint nwindows;
Window root_return, parent_return, *windows;
Atom a = XInternAtom(display, "_NET_CLIENT_LIST", true);
Atom actualType;
int format;
unsigned long numItems, bytesAfter;
unsigned char *data = 0;
int status = XGetWindowProperty(display, root, a, 0L, (~0L),
false,
AnyPropertyType, &actualType, &format, &numItems, &bytesAfter, &data);
char* window_name_return;
if (status >= Success && numItems) {
long *array = (long*) data;
for (long k = 0; k < numItems; k++) {
Window window = (Window) array[k];
//not finding chrome window name
printf("window found was %d \n", window);
if (XFetchName(display, window, &window_name_return)) {
printf("found window name for %d : %s \n", window,
window_name_return);
}
//XMapWindow(display, parent);
XMapWindow(display, window);
XWindowAttributes attr;
Status status = XGetWindowAttributes(display, window, &attr);
if (status == 0)
printf("Fail to get window attributes!\n");
getScreen2(0, 0, attr.width, attr.height, window);
}
XFree(data);
}
return 0;
}
which calls this function to map the window and call XCompositeRedirectWindow;
void getScreen2(const int xx, const int yy, const int W, const int H,
const XID xid) {
Display *display = XOpenDisplay(NULL);
Window root = DefaultRootWindow(display);
// turn on --sync to force error on correct method
//https://www.x.org/releases/X11R7.6/doc/man/man3/XSynchronize.3.xhtml
XSynchronize(display, True);
int counter = 1;
// select which xid to operate on, the winder or its parent
//XID xwid = fparent;
XID xwid = xid;
// Requests the X server to direct the hierarchy starting at window to off-screen storage
XCompositeRedirectWindow(display, xwid, CompositeRedirectAutomatic);
XWindowAttributes attr;
Status status = XGetWindowAttributes(display, xwid, &attr);
int width = attr.width;
int height = attr.height;
int depth = attr.depth;
Pixmap xc_pixmap = XCompositeNameWindowPixmap(display, xwid);
if (!xc_pixmap) {
printf("xc_pixmap not found\n");
}
//XWriteBitmapFile(display, "test1.xpm", pixmap, W, H, -1, -1);
XRenderPictFormat *format = XRenderFindVisualFormat(display, attr.visual);
XRenderPictureAttributes pa;
pa.subwindow_mode = IncludeInferiors;
Picture picture = XRenderCreatePicture(display, xwid, format,
CPSubwindowMode, &pa);
char buffer[50];
int n;
int file_counter = 1;
n = sprintf(buffer, "/tmp/%d_test%d.xpm", xid, file_counter++);
XWriteBitmapFile(display, buffer, xc_pixmap, W, H, -1, -1);
n = sprintf(buffer, "/tmp/%d_test%d.xpm", xid, file_counter++);
XWriteBitmapFile(display, buffer, xid, W, H, -1, -1);
XImage *image = XGetImage(display, xid, 0, 0, W, H, AllPlanes, ZPixmap);
if (!image) {
printf("XGetImage failed\n");
}
char filename[255];
int n2;
n2 = sprintf(filename, "/tmp/png_out/%d_test%d.png", xid, file_counter++);
printf("filename %s \n", filename);
write_png_for_image(image, xid, W, H, filename);
//XFree(image);
XDestroyImage(image);
XDestroyWindow(display, root);
XCloseDisplay(display);
}
and then this to write out the png;
void write_png_for_image(XImage *image, XID xid, int width, int height,
char *filename) {
int code = 0;
FILE *fp;
png_structp png_ptr;
png_infop png_info_ptr;
png_bytep png_row;
char buffer[50];
int n;
n = sprintf(buffer, filename, xid);
// Open file
fp = fopen(buffer, "wb");
if (fp == NULL) {
fprintf(stderr, "Could not open file for writing\n");
code = 1;
}
// Initialize write structure
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) {
fprintf(stderr, "Could not allocate write struct\n");
code = 1;
}
// Initialize info structure
png_info_ptr = png_create_info_struct(png_ptr);
if (png_info_ptr == NULL) {
fprintf(stderr, "Could not allocate info struct\n");
code = 1;
}
// Setup Exception handling
if (setjmp(png_jmpbuf (png_ptr))) {
fprintf(stderr, "Error during png creation\n");
code = 1;
}
png_init_io(png_ptr, fp);
// Write header (8 bit colour depth)
png_set_IHDR(png_ptr, png_info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
// Set title
char *title = "Screenshot";
if (title != NULL) {
png_text title_text;
title_text.compression = PNG_TEXT_COMPRESSION_NONE;
title_text.key = "Title";
title_text.text = title;
png_set_text(png_ptr, png_info_ptr, &title_text, 1);
}
png_write_info(png_ptr, png_info_ptr);
// Allocate memory for one row (3 bytes per pixel - RGB)
png_row = (png_bytep) malloc(3 * width * sizeof(png_byte));
unsigned long red_mask = image->red_mask;
unsigned long green_mask = image->green_mask;
unsigned long blue_mask = image->blue_mask;
// Write image data
//int xxx, yyy;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
unsigned long pixel = XGetPixel(image, x, y);
unsigned char blue = pixel & blue_mask;
unsigned char green = (pixel & green_mask) >> 8;
unsigned char red = (pixel & red_mask) >> 16;
png_byte *ptr = &(png_row[x * 3]);
ptr[0] = red;
ptr[1] = green;
ptr[2] = blue;
}
png_write_row(png_ptr, png_row);
}
// End write
png_write_end(png_ptr, NULL);
// Free
fclose(fp);
if (png_info_ptr != NULL)
png_free_data(png_ptr, png_info_ptr, PNG_FREE_ALL, -1);
if (png_ptr != NULL)
png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
if (png_row != NULL)
free(png_row);
}
However when the windows is browser based, the image is mangled like so;
Do I need to do something special to get browser windows working?
References;
https://www.talisman.org/~erlkonig/misc/x11-composite-tutorial/
Get a screenshot of a window that is cover or not visible or minimized with Xcomposite extension for X11

How can i add line breaks when rendering Text using X11,

I am making an application that renders texts according to style mentioned on screen using X Windows System and Xft. My code is working fine as shown below.
#include <X11/Xlib.h>
#include <X11/Xft/Xft.h>
char * nowShowing()
{
return strdup("This is a sample text This is rendered with new Driver installed This is a sample text his is rendered with new Driver installed");
}
int main()
{
XftFont *font;
XftDraw *draw;
XRenderColor render_color;
XftColor xft_color;
char *str;
str = nowShowing();
int x = 70;
int y = 150;
Display *dis = XOpenDisplay (0);
int screen = DefaultScreen (dis);
Window w = XCreateSimpleWindow (dis, RootWindow (dis, screen),
0, 0, 1200, 300, 1,
BlackPixel (dis, screen),
WhitePixel (dis, screen));
XEvent ev;
render_color.red = 0;
render_color.green =0;
render_color.blue = 0;
render_color.alpha = 0xffff;
XftColorAllocValue (dis,
DefaultVisual(dis, screen),
DefaultColormap(dis, screen),
&render_color,
&xft_color);
//font = XftFontOpen(dis, screen,
// XFT_FAMILY, XftTypeString, "charter",
// XFT_SIZE, XftTypeDouble, 20.0,
// NULL);
font = XftFontOpenName(dis,screen,"URW Palladio L:style=Bold Italic"); //it takes a Fontconfig pattern string
draw = XftDrawCreate(dis, w,
DefaultVisual(dis, screen),
DefaultColormap(dis, screen));
XSelectInput (dis, w, ExposureMask);
XMapWindow (dis, w);
for (;;)
{
XNextEvent (dis, &ev);
if (ev.type == Expose)
XftDrawString8(draw, &xft_color, font, x, y, (XftChar8 *) str,
strlen(str));
}
return 0;
}
But i am wondering that how can i add line breaks in the text entered. I tried using "/n" and also tried to make array and used loops but it didn't work.
New line "\n" will not be rendered by Xft. You need to render each line separately with proper offset, depending on font size and desired spacing.
I have modified the ending block of your code with sample text rendered two times on separate lines.
if (ev.type == Expose)
{
int fonth = font->ascent + font->descent;
XftDrawString8(draw, &xft_color, font, x, y, (XftChar8 *) str,
strlen(str));
XftDrawString8(draw, &xft_color, font, x, y+fonth, (XftChar8 *) str,
strlen(str));
}

How to Zoom with Poppler

Language C, UI library: GTK, renderer: poppler
I'm newbie in GTK/Poppler programming and a bit stuck with understanding how to solve Zoom issue with poppler.
When I use the function below everything is ok, except zooming (hence - scrollbars).
I've tried to get the ideas from here, but it seems, I don't get how the screen/doc is rendered at all :(.
PopplerPage *ppage_P2 = NULL;
PopplerDocument *document_P2 = NULL;
cairo_surface_t *surface_P2 = NULL;
/* pdf_doc__view_page
* page - page number;
* zoom - floating nomber, 1.0 is 'no zoom'
*/
void pdf_doc__view_page (int page, float _zoom){
int err;
int w, h;
double width, height;
cairo_t *cr;
if(document_P2==NULL) /
return;
ppage_P2 = poppler_document_get_page (document_P2, page);
if(ppage_P2==NULL)
return;
poppler_page_get_size (ppage_P2, &width, &height);
w = (int) ceil(width);
h = (int) ceil(height);
if(surface_P2)
cairo_surface_destroy (surface_P2);
surface_P2 = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w*zoom_P2, h*zoom_P2);
cr = cairo_create (surface_P2);
poppler_page_render (ppage_P2, cr);
cairo_destroy (cr);
if(drawarea_P2==NULL)
return;
gtk_widget_set_size_request (drawarea_P2, w*zoom_P2, h*zoom_P2);
gtk_widget_queue_draw (drawarea_P2);
// self.SetScrollbars(u, u, (self.width*self.scale)/u, (self.height*self.scale)/u)
update_statusbar();
}
To have 'scrollers', you have to put the viewer in a GtkScrolledWindow, which I suspect you already did.
To have them actually working, once poppler rendered the page, you can ask poppler for the size of the render, then set the viewer to that size. Until then, the scrollbars don't know the size of drawing:
viewer_page = poppler_document_get_page(viewer_doc, 0);
// add a test to see if page was rendered correctly
poppler_page_get_size(viewer_page, &width, &height);
gtk_widget_set_size_request(viewer.drawingarea, (int)width, (int)height);
This is the answer. (but I still did not get how to create scrollers properly).
cr = cairo_create (surface_P2);
cairo_scale(cr, zoom_P1 , zoom_P1);
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
cairo_paint(cr);
poppler_page_render(ppage_P2, cairo);
cairo_destroy(cr);
cairo_surface_destroy(surface_P2);
g_object_unref(G_OBJECT(ppage_P2));
if(drawarea_P2==NULL)
return;
gtk_widget_set_size_request (drawarea_P2, w, h);
gtk_widget_queue_draw (drawarea_P2);
// self.SetScrollbars(u, u, (self.width*self.scale)/u, (self.height*self.scale)/u)
update_statusbar();
}

Resources