I am sorry my bad english. I work with Raspberry pi 3's sample code. I try run sample code on Code Blocks and I work for learn. I configured debug setting based on Makefile of sample code. I configure linker setting. When I build the code on Code Blocks, it doesn't show error. But when I run code. I taked error on console. Error this:
Font_example: /home/pi/Desktop/Font_example/main.c: 101: main:Assertion 's==0' failed.
I remarked line. Code this:
// Test app for VG font library.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include "/opt/vc/src/hello_pi/libs/vgfont/bcm_host.h"
#include "/opt/vc/src/hello_pi/libs/vgfont/vgfont.h"
static const char *strnchr(const char *str, size_t len, char c)
{
const char *e = str + len;
do {
if (*str == c) {
return str;
}
} while (++str < e);
return NULL;
}
int32_t render_subtitle(GRAPHICS_RESOURCE_HANDLE img, const char *text, const int skip, const uint32_t text_size, const uint32_t y_offset)
{
uint32_t text_length = strlen(text)-skip;
uint32_t width=0, height=0;
const char *split = text;
int32_t s=0;
int len = 0; // length of pre-subtitle
uint32_t img_w, img_h;
graphics_get_resource_size(img, &img_w, &img_h);
if (text_length==0)
return 0;
while (split[0]) {
s = graphics_resource_text_dimensions_ext(img, split, text_length-(split-text), &width, &height, text_size);
if (s != 0) return s;
if (width > img_w) {
const char *space = strnchr(split, text_length-(split-text), ' ');
if (!space) {
len = split+1-text;
split = split+1;
} else {
len = space-text;
split = space+1;
}
} else {
break;
}
}
// split now points to last line of text. split-text = length of initial text. text_length-(split-text) is length of last line
if (width) {
s = graphics_resource_render_text_ext(img, (img_w - width)>>1, y_offset-height,
GRAPHICS_RESOURCE_WIDTH,
GRAPHICS_RESOURCE_HEIGHT,
GRAPHICS_RGBA32(0xff,0xff,0xff,0xff), /* fg */
GRAPHICS_RGBA32(0,0,0,0x80), /* bg */
split, text_length-(split-text), text_size);
if (s!=0) return s;
}
return render_subtitle(img, text, skip+text_length-len, text_size, y_offset - height);
}
int main(void)
{
GRAPHICS_RESOURCE_HANDLE img;
uint32_t width, height;
int LAYER=1;
bcm_host_init();
int s;
s = gx_graphics_init(".");
assert(s == 0); //101. line
s = graphics_get_display_size(0, &width, &height);
assert(s == 0);
s = gx_create_window(0, width, height, GRAPHICS_RESOURCE_RGBA32, &img);
assert(s == 0);
// transparent before display to avoid screen flash
graphics_resource_fill(img, 0, 0, width, height, GRAPHICS_RGBA32(0,0,0,0x00));
graphics_display_resource(img, 0, LAYER, 0, 0, GRAPHICS_RESOURCE_WIDTH, GRAPHICS_RESOURCE_HEIGHT, VC_DISPMAN_ROT0, 1);
uint32_t text_size = 10;
while (1) {
const char *text = "The quick brown fox jumps over the lazy dog";
uint32_t y_offset = height-60+text_size/2;
graphics_resource_fill(img, 0, 0, width, height, GRAPHICS_RGBA32(0,0,0,0x00));
// blue, at the top (y=40)
graphics_resource_fill(img, 0, 40, width, 1, GRAPHICS_RGBA32(0,0,0xff,0xff));
// green, at the bottom (y=height-40)
graphics_resource_fill(img, 0, height-40, width, 1, GRAPHICS_RGBA32(0,0xff,0,0xff));
// draw the subtitle text
render_subtitle(img, text, 0, text_size, y_offset);
graphics_update_displayed_resource(img, 0, 0, 0, 0);
text_size += 1;
if (text_size > 50)
text_size = 10;
}
graphics_display_resource(img, 0, LAYER, 0, 0, GRAPHICS_RESOURCE_WIDTH, GRAPHICS_RESOURCE_HEIGHT, VC_DISPMAN_ROT0, 0);
graphics_delete_resource(img);
return 0;
}
1- What is wrong ?
2- Why this error on console why I couldn't see during on compiler?
NOTE: I can running this code on terminal (First go file and use make on console after use ./hello_font.bin) work fine.
Thanks your time. Best regards.
1- What is wrong ?
2- Why this error on console why I couldn't see during on compiler?
The assert you are using is a run-time assert.
If you want a compile-time assert, you have to use static_assert.
Using static_assert allows you to print your own message that will appear as compiler error.
Simple example:
int main()
{
static_assert(0 == 1, "Zero is not equal to one");
}
Compiler output:
main.cpp: In function 'int main()':
main.cpp:3:21: error: static assertion failed: Zero is not equal to one
static_assert(0 == 1, "Zero is not equal to one");
As in the comments of #Scheff. You should add macro. I added NDEBUG macro (on my project build setting and added macro to tab of other compiler under options). So my problem solved.
Related
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);
I'm trying to write some code which would allow to render 3D graphics in console using characters and escape sequences (for color). I need it for one specific program I want to write, but, if possible, I would like to make it more universal. I'm experiencing something like screen tearing and I want to get rid of it (that the whole screen would be printed "at once"). The test is simply displaying screen filled with spaces with wite and black background (one full white frame then one full black one) in one second interval.
I have tried:
At the begging I thought about line buffering on stdout. Tried both disabling it and creating full buffor with size sufficient enough to hold every char on the screen. Second option provides better results, and by that I mean that less frames are teared, but they still are.
I thought it might be a problem with my terminal emulator (this question gave me the idea) so I started to mess around with other ones. I've got best result with Kitty but it's not there yet.
The next thing was to mess with Kitty configuration. I've noticed that if I would increase the input_delay setting to about 20 ms the problem would be almost gone. Just few of, and not every frame would be teared.
So, I came into the conclusion that in fact terminal emulators (or at least kitty) are being too fast and there might be some sort of race condition here, where buffer is not flushed yet fully and TE display both what was partially flushed and is part of old frame. Am I wrong? If not is there any way I can enforce terminals to wait for input to finnish before displaying it, or at least enforce input delay in C?
here is the relevant part of the code:
main.c
#include "TermCTRL/termCTRL.h"
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
int main()
{
termcell_t cell;
int k;
uint16_t x,y;
termCTRL_get_term_size(&x, &y);
sleep(1);
termCTRL_init();
uint8_t a = 0;
for(k=0; k<200; k++)
{
a^=255;
cell.bg.B = a;
cell.bg.G = a;
cell.bg.R = a;
cell.fg.B = a;
cell.fg.G = a;
cell.fg.R = a;
cell.symbol[0] = ' '; //symbol is in fact a string, because I want to use UTF chars too
cell.symbol[1] = '\0';
for(int xd=0; xd<x; xd++)
for(int yd=0; yd<y; yd++)
{
termCTRL_load_termcell(xd, yd, &cell);
}
termCTRL_update_screen();
sleep(1);
}
termCTRL_close();
return 0;
}
termCTRL.h
#pragma once
#include <stdint.h>
#define INPLACE_TERMCELL(FG_R, FG_G, FG_B, BG_R, BG_G, BG_B, SYMBOL) \
(termcell_t) { {FG_R, FG_G, FG_B}, {BG_R, BG_G, BG_B}, SYMBOL }
#define termCTRL_black_fill_screen() \
termCTRL_fill_screen(&INPLACE_TERMCELL(0, 0, 0, 0, 0, 0, " "))
typedef struct termcell_color_t
{
uint16_t R;
uint16_t G;
uint16_t B;
} termcell_color_t;
typedef struct termcell_t
{
termcell_color_t fg;
termcell_color_t bg;
char symbol[4];
} termcell_t;
typedef enum termCTRL_ERRNO
{
termCTRL_OUT_OF_BORDER = -2,
termCTRL_INVALID_TERMCELL = -1,
termCTRL_INTERNAL_ERROR = 0,
termCTRL_OK = 1,
} termCTRL_ERRNO;
void termCTRL_init();
void termCTRL_close();
void termCTRL_get_term_size(uint16_t *col, uint16_t *row);
termCTRL_ERRNO termCTRL_load_termcell(uint16_t x, uint16_t y, termcell_t *in);
void termCTRL_update_screen();
termCTRL_ERRNO termCTRL_fill_screen(termcell_t *cell);
termCTRL.c
#include "termCTRL.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#define CONVERTED_TERMCELL_SIZE 44
#define CAST_SCREEN_TO_BUFFER \
char (*screen_buffer)[term_xsize][term_ysize][CONVERTED_TERMCELL_SIZE]; \
screen_buffer = _screen_buffer
static void *_screen_buffer = NULL;
static uint16_t term_xsize, term_ysize;
static char *IO_buff = NULL;
void termCTRL_get_term_size(uint16_t *col, uint16_t *row)
{
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
*col = w.ws_col;
*row = w.ws_row;
}
void int_decompose(uint8_t in, char *out)
{
uint8_t x = in/100;
out[0] = x + '0';
in -= x*100;
x = in/10;
out[1] = x + '0';
in -= x*10;
out[2] = in + '0';
}
termCTRL_ERRNO termCTRL_move_cursor(uint16_t x, uint16_t y)
{
char mov_str[] = "\x1b[000;000H";
if(x<term_xsize && y<term_ysize)
{
int_decompose(y, &mov_str[2]);
int_decompose(x, &mov_str[6]);
if(fputs(mov_str, stdout) == EOF) return termCTRL_INTERNAL_ERROR;
else return termCTRL_OK;
}
else
{
return termCTRL_OUT_OF_BORDER;
}
}
termCTRL_ERRNO termCTRL_load_termcell(uint16_t x, uint16_t y, termcell_t *in)
{
CAST_SCREEN_TO_BUFFER;
if(in == NULL) return termCTRL_INVALID_TERMCELL;
if(x >= term_xsize || y >= term_ysize) return termCTRL_OUT_OF_BORDER;
//because screen buffer was initialized, it is only needed to replace RGB values and symbol.
//whole escape sequence is already there
int_decompose(in->fg.R, &(*screen_buffer)[x][y][7]);
int_decompose(in->fg.G, &(*screen_buffer)[x][y][11]);
int_decompose(in->fg.B, &(*screen_buffer)[x][y][15]);
int_decompose(in->bg.R, &(*screen_buffer)[x][y][26]);
int_decompose(in->bg.G, &(*screen_buffer)[x][y][30]);
int_decompose(in->bg.B, &(*screen_buffer)[x][y][34]);
strcpy(&(*screen_buffer)[x][y][38], in->symbol); //copy symbol, note that it could be UTF char
return termCTRL_OK;
}
termCTRL_ERRNO termCTRL_fill_screen(termcell_t *cell)
{
uint16_t x, y;
termCTRL_ERRNO ret;
for(y=0; y<term_ysize; y++)
for(x=0; x<term_xsize; x++)
{
ret = termCTRL_load_termcell(x, y, cell);
if(ret != termCTRL_OK)
return ret;
}
return ret;
}
void termCTRL_update_screen()
{
uint16_t x, y;
CAST_SCREEN_TO_BUFFER;
termCTRL_move_cursor(0, 0);
for(y=0; y<term_ysize-1; y++)
{
for(x=0; x<term_xsize; x++)
fputs((*screen_buffer)[x][y], stdout);
fputs("\n", stdout);
}
//last line got special treatment because it can't have \n
for(x=0; x<term_xsize; x++)
fputs((*screen_buffer)[x][y], stdout);
fflush(stdout);
}
void termCTRL_init()
{
uint16_t x, y;
termCTRL_get_term_size(&term_xsize, &term_ysize);
IO_buff = calloc(term_xsize*term_ysize, CONVERTED_TERMCELL_SIZE);
setvbuf(stdout, IO_buff, _IOFBF, term_xsize*term_ysize*CONVERTED_TERMCELL_SIZE);
_screen_buffer = calloc(term_xsize*term_ysize, CONVERTED_TERMCELL_SIZE);
fputs("\e[?25l", stdout); //hide cursor
fputs("\x1b[2J", stdout); //clear screen
CAST_SCREEN_TO_BUFFER;
for(y=0; y<term_ysize; y++)
for (x=0; x<term_xsize; x++)
sprintf( (*screen_buffer)[x][y], "\x1b[38;2;200;200;000m\x1b[48;2;000;000;000m ");
termCTRL_update_screen();
}
void termCTRL_close()
{
free(_screen_buffer);
setvbuf(stdout, NULL, _IONBF, 0);
free(IO_buff);
printf("\e[?25h"); //show cursor
printf("\x1b[m"); //reset colors
printf("\x1b[2J"); //clear screen
}
I am super new to creating efi application. My aim is to create a small application in efi, that displays some text on a background. But I am stuck with trying to display text on the display (Great would be to have a custom font, but that is not necessary at this stage). I want the app (also) to run on apple systems (to boot from a usb)
How do I find good documentation on the EFI functions? It seems super hard to find good examples etc.
How can I display a text on a background with EFI?
This is what I got so far. I change the background to a color using the graphics protocol. How do I display a text on it. The Output String doesn't seem to work.
#include "efibind.h"
#include "efidef.h"
#include "efidevp.h"
#include "eficon.h"
#include "efiapi.h"
#include "efierr.h"
#include "efiprot.h"
static EFI_GUID GraphicsOutputProtocolGUID = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
/**
* efi_main - The entry point for the EFI application
* #image: firmware-allocated handle that identifies the image
* #SystemTable: EFI system table
*/
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systemTable) {
EFI_BOOT_SERVICES *bs = systemTable->BootServices;
EFI_STATUS status;
EFI_GRAPHICS_OUTPUT_PROTOCOL *graphicsProtocol;
SIMPLE_TEXT_OUTPUT_INTERFACE *conOut = systemTable->ConOut;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info;
UINTN SizeOfInfo, sWidth, sHeight;
status = bs->LocateProtocol(&GraphicsOutputProtocolGUID, NULL,
(void**)&graphicsProtocol);
if (EFI_ERROR(status) || graphicsProtocol == NULL) {
conOut->OutputString(conOut, L"Failed to init gfx!\r\n");
return status;
}
conOut->ClearScreen(conOut);
//Switch to current mode so gfx is started.
status = graphicsProtocol->SetMode(graphicsProtocol, graphicsProtocol->Mode->Mode);
if (EFI_ERROR(status)) {
conOut->OutputString(conOut, L"Failed to set default mode!\r\n");
return status;
}
EFI_GRAPHICS_OUTPUT_BLT_PIXEL p;
p.Red = 200;
p.Green = 77;
p.Blue = 13;
graphicsProtocol->QueryMode(graphicsProtocol, graphicsProtocol->Mode->Mode, &SizeOfInfo, &info);
sWidth = info->HorizontalResolution;
sHeight = info->VerticalResolution;
status = graphicsProtocol->Blt(graphicsProtocol, &p, EfiBltVideoFill, 0, 0, 0, 0, sWidth, sHeight, 0);
while (1) {
conOut->OutputString(conOut, L"Some text that I want to display\r\n");
bs->Stall(500000);
}
return EFI_SUCCESS;
}
UEFI supports graphics output. It also supports text output (which can mean either output to a serial console, or text rendered to a graphical console, or both). But there is no defined way to interact between these in a controlled manner.
Applications that provide a graphical environment with text elements (BIOS configuration menu, GRUB) generally do this using their own frameworks to draw text on the graphical console using GRAPHICS_OUTPUT_PROTOCOL.
This is a short example of a text renderer using the font module from LVGL (which can be used standalone, replace #include "../../lv_conf.h" in the lv_font.h file with #define USE_LV_FONT_DEJAVU_20 8) and the Blt method from the GRAPHICS_OUTPUT_PROTOCOL
#include <Uefi.h>
#include <Library\UefiLib.h>
#include <Protocol\GraphicsOutput.h>
#include "lv_font.h"
#define LETTER_SPACE 2
#define WAIT_SECONDS 10
#define FONT &lv_font_dejavu_20
static EFI_BOOT_SERVICES *gBS;
static EFI_RUNTIME_SERVICES *gRT;
static EFI_GRAPHICS_OUTPUT_PROTOCOL *gGOP = (EFI_GRAPHICS_OUTPUT_PROTOCOL *)NULL;
static EFI_GRAPHICS_OUTPUT_BLT_PIXEL gWhite = { 255,255,255,0 };
static void _util_render_glyph(UINT32 x, UINT32 y, CHAR8 letter)
{
UINT32 height;
UINT32 width;
UINT32 pm_x;
UINT32 pm_y;
UINT32 index;
const UINT8* bitmap;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *pixelmap;
if (gGOP == NULL) {
return;
}
height = lv_font_get_height(FONT);
width = lv_font_get_width(FONT, letter);
// glyph is not defined in this font
if (width == 0) {
return;
}
bitmap = lv_font_get_bitmap(FONT, letter);
// using 8 bpp for simplicity
if (EFI_ERROR(gBS->AllocatePool(EfiLoaderData, height * width * sizeof(*pixelmap), (VOID**)&pixelmap))) {
return;
}
gBS->SetMem((VOID*)pixelmap, height * width * sizeof(*pixelmap), 0);
// get the current content of the framebuffer to allow 'transparent' blt operations
gGOP->Blt(gGOP, pixelmap, EfiBltVideoToBltBuffer, x, y, 0, 0, width, height, 0);
for (pm_y = 0; pm_y < height; pm_y++) {
for (pm_x = 0; pm_x < width; pm_x++) {
index = width * pm_y + pm_x;
if (bitmap[index] > 200) {
pixelmap[index].Red = 0;
pixelmap[index].Blue = 0;
pixelmap[index].Green = 0;
pixelmap[index].Reserved = 0;
}
else if (bitmap[index] > 100) {
pixelmap[index].Red = 105;
pixelmap[index].Blue = 105;
pixelmap[index].Green = 105;
pixelmap[index].Reserved = 0;
}
}
}
gGOP->Blt(gGOP, pixelmap, EfiBltBufferToVideo, 0, 0, x, y, width, height, 0);
gBS->FreePool(pixelmap);
}
static void _util_render_text(UINT32 x, UINT32 y, const CHAR8 *string)
{
UINT32 index;
UINTN length;
UINT32 scr_w;
UINT32 scr_h;
UINT32 str_x;
UINT32 gly_w;
UINT32 gly_h;
if (string == NULL) {
return;
}
if (gGOP == NULL) {
return;
}
scr_w = gGOP->Mode->Info->HorizontalResolution;
scr_h = gGOP->Mode->Info->VerticalResolution;
length = AsciiStrnLenS(string, 32);
gly_h = lv_font_get_height(FONT);
// check if the string can be printed
if ((y + gly_h) > scr_h) {
return;
}
if (x > scr_w) {
return;
}
// print the string glyph by glyph
str_x = x;
for (index = 0; index < length; index++) {
// check if the glyph can be printed
gly_w = lv_font_get_width(FONT, string[index]);
if ((str_x + gly_w) > scr_w) {
break;
}
// print the glyph
_util_render_glyph(str_x, y, string[index]);
// calculate the position of the next glyph
str_x += gly_w + LETTER_SPACE;
}
}
static void _util_fill_screen(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *color)
{
if (gGOP == NULL) {
return;
}
gGOP->Blt(gGOP, color, EfiBltVideoFill, 0, 0, 0, 0, gGOP->Mode->Info->HorizontalResolution, gGOP->Mode->Info->VerticalResolution, 0);
}
static void _util_wait(UINT32 seconds)
{
EFI_TIME time;
UINT8 current_second = 255;
UINT32 elapsed_seconds = 0;
//wait for some seconds
while (elapsed_seconds <= WAIT_SECONDS) {
if (!EFI_ERROR(gRT->GetTime(&time, (EFI_TIME_CAPABILITIES*)NULL))) {
if (current_second != time.Second) {
elapsed_seconds++;
current_second = time.Second;
}
}
else {
break;
}
CpuPause();
}
}
EFI_STATUS
EFIAPI
UefiMain(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable)
{
EFI_STATUS eRc;
gBS = SystemTable->BootServices;
gRT = SystemTable->RuntimeServices;
eRc = gBS->LocateProtocol(
&gEfiGraphicsOutputProtocolGuid,
NULL,
(VOID**)&gGOP);
if (EFI_ERROR(eRc) || gGOP == NULL) {
return EFI_SUCCESS;
}
_util_fill_screen(&gWhite);
_util_render_text(0, 0, "HELLO WORLD!");
_util_wait(WAIT_SECONDS);
return EFI_SUCCESS;
}
I tested it on a pc and on a mac it runs on both. Using the tools provided by LVGL on their website you can use any font you want.
If you target MacEFI specifically, you'll need an additional protocol call to force the console into text mode, like this.
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
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));
}