When i compile acode i have this error cannot open file X11/Xlib.h in c++ - c++

/* Sequential Mandelbrot program mandelbrot.c */
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#define X_RESN 800 /* x resolution */
#define Y_RESN 800 /* y resolution */
typedef struct complextype
{ float real, imag;
} Compl;
int main (int argc, char *argv[])
{ Window win; /* window initialization */
unsigned
int width, height, /* window size */
x, y, /* window position */
border_width, /* border width in pixels */
display_width,
display_height, /* size of screen */
screen; /* which screen */
char *window_name = "Mandelbrot Set", *display_name = NULL;
GC gc;
unsigned long valuemask = 0;
XGCValues values;
Display *display;
XSizeHints size_hints;
Pixmap bitmap;
XPoint points[800];
FILE *fp, *fopen ();
char str[100];
XSetWindowAttributes attr[1];
/* Mandlebrot variables */
int i, j, k;
Compl z, c;
float lengthsq, temp;
/* connect to Xserver */
if ( (display = XOpenDisplay (display_name)) == NULL )
{ fprintf (stderr, "drawon: cannot connect to X server %s\n",
XDisplayName (display_name) );
exit (-1);
}
/* get screen size */
screen = DefaultScreen (display);
display_width = DisplayWidth (display, screen);
display_height = DisplayHeight (display, screen);
/* set window size */
width = X_RESN;
height = Y_RESN;
/* set window position */
x = 0;
y = 0;
/* create opaque window */
border_width = 4;
win = XCreateSimpleWindow(display, RootWindow (display, screen),
x, y, width, height, border_width,
BlackPixel (display, screen), WhitePixel (display, screen));
size_hints.flags = USPosition|USSize;
size_hints.x = x;
size_hints.y = y;
size_hints.width = width;
size_hints.height = height;
size_hints.min_width = 300;
size_hints.min_height = 300;
XSetNormalHints (display, win, &size_hints);
XStoreName(display, win, window_name);
/* create graphics context */
gc = XCreateGC (display, win, valuemask, &values);
XSetBackground (display, gc, WhitePixel (display, screen));
XSetForeground (display, gc, BlackPixel (display, screen));
XSetLineAttributes (display,gc,1,LineSolid,CapRound,JoinRound);
attr[0].backing_store = Always;
attr[0].backing_planes = 1;
attr[0].backing_pixel = BlackPixel(display, screen);
XChangeWindowAttributes(display, win,
CWBackingStore | CWBackingPlanes | CWBackingPixel, attr);
XMapWindow (display, win);
XSync(display, 0);
/* Calculate and draw points */
for(i=0; i < X_RESN; i++)
{ for(j=0; j < Y_RESN; j++)
{ z.real = z.imag = 0.0; /* 800x800 scale factors */
c.real = ((float) j - 400.0)/200.0;
c.imag = ((float) i - 400.0)/200.0;
k = 0;
do
{ /* iterate for pixel color */
temp = z.real*z.real - z.imag*z.imag + c.real;
z.imag = 2.0*z.real*z.imag + c.imag;
z.real = temp;
lengthsq = z.real*z.real+z.imag*z.imag;
k++;
} while (lengthsq < 4.0 && k < 100);
if (k == 100) XDrawPoint (display, win, gc, j, i);
} }
XFlush (display);
sleep (30);
/* Program Finished */
}

Open up a command prompt and run the two commands:
find / -type f - name Xlib.h
find / -type d - name X11
That should help you locate that file and/or directory so you can see whether it's available.
If it is available (e.g., it's found at /usr/include/X_stuff/X11/Xlib.h), make sure your compiler command references it, like:
g++ -I/usr/include/X_stuff ...
If it's not there, install it.

Either you forgot to install the X development packages, or the directory containing the headers was not added to the includedir list.

Related

Gtk smooth panning issue

I am in a project where map and other information are displayed in a Gtk window. There are several map layers, that I draw into a Cairo surface and save in a .png (plotRect() function in code below). That .png is displayed in a Gtk image when there is a Gtk draw signal (draw()).
I now want to accomplish smooth grabbing and panning. When the mouse button is pressed, I want the whole image to be translated within the window area, follow the movements of the mouse. When the button is released the image should be Cairo remade and redrawn with new bounds. During the drag/pan procedure itself there is no need to draw areas that where previously out of the window borders -- it is OK to wait for that to be done when the mouse button is released.
Enclosed you find a simplified version of my code. The main has a loop going until the windows is closed, redrawing the image after each panning. The problem is in the pan() function. After the translation in line 21 I woould expect the draw statement in line 128 to successively draw panned images while moving the mouse, but the visible image is unaffected. Uncommenting line 23 shows that graph->image has really been modified, and I can see that the draw signal of line 25 is invoking the draw() callback function. After button release, the translated image is correctly displayed.
Can anyone please give me some advice?
I'm using gcc, Cairo, Gtk3 and Ubuntu 18.04 on a double-booted MacBook Pro 64 bit i5.
#include <cairo.h>
#include <chrono>
#include <cmath>
#include <gtk/gtk.h>
#include <iostream>
#include <mutex>
#include <thread>
using namespace std;
mutex mtx;
bool gtkMainLoopRunning = false;
#define SLEEP(d) this_thread::sleep_for(chrono::milliseconds(d))
template <class T>
inline T sqr(T x) {
return x * x;
}
//-----------------------------------------------------------------------------
class Graph {
double toplat, leftlon; // upper left corner
double dydlat, dxdlon; // pixels / degree lon/lat
public:
int size; // window x = y
GtkWidget *window;
GtkImage *image;
const char *png = "/tmp/image.png";
cairo_surface_t *surface{};
cairo_t *cr{};
bool closed = false;
bool leftbuttondown = false;
int mousex = 0, mousey = 0;
Graph(const double, const double, const double, const double);
~Graph();
void plotRect(const double, const double, const double, const double);
bool pan();
};
//-----------------------------------------------------------------------------
static gboolean draw(GtkWidget *widget, cairo_t *cr, gpointer data) {
Graph *graph = (Graph *)data;
if (!graph->leftbuttondown) {
mtx.lock();
gtk_image_set_from_file(graph->image, graph->png);
mtx.unlock();
}
return FALSE;
}
//-----------------------------------------------------------------------------
static gboolean clicked(GtkWidget *widget, GdkEventButton *button, gpointer data) {
Graph *graph = (Graph *)data;
if (button->button == 1) {
if (button->type == GDK_BUTTON_PRESS) {
graph->leftbuttondown = true;
} else if (button->type == GDK_BUTTON_RELEASE) {
graph->leftbuttondown = false;
}
}
graph->mousex = button->x;
graph->mousey = button->y;
return FALSE;
}
//-----------------------------------------------------------------------------
Graph::~Graph() {
do {
SLEEP(100);
} while (gtkMainLoopRunning); // wait until gtk main loop has stopped
cairo_destroy(cr);
cairo_surface_destroy(surface);
}
//-----------------------------------------------------------------------------
void destroyWindow(GtkWidget *widget, gpointer data) {
gtk_main_quit();
gtkMainLoopRunning = false;
Graph *graph = (Graph *)data;
graph->closed = true; // signal gtkThread to finish
gtk_widget_destroy((GtkWidget *)graph->image);
gtk_widget_destroy(graph->window);
}
//-----------------------------------------------------------------------------
Graph::Graph(const double minlat, const double minlon, const double maxlat, const double maxlon) {
gtk_init(NULL, NULL);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
size = 800;
gtk_widget_show(window);
image = (GtkImage *)gtk_image_new();
gtk_widget_set_size_request((GtkWidget *)image, size, size);
gtk_container_add(GTK_CONTAINER(window), (GtkWidget *)image);
gtk_widget_show((GtkWidget *)image);
g_signal_connect(image, "draw", G_CALLBACK(draw), this);
g_signal_connect(window, "destroy", G_CALLBACK(destroyWindow), this);
surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, size, size);
cr = cairo_create(surface);
gtk_widget_add_events(window, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON1_MOTION_MASK);
g_signal_connect(window, "button-press-event", G_CALLBACK(clicked), this);
g_signal_connect(window, "button-release-event", G_CALLBACK(clicked), this);
g_signal_connect(window, "motion-notify-event", G_CALLBACK(clicked), this);
const double coslat = cos((minlat + maxlat) / 2 * M_PI / 180);
const double extension = max(maxlat - minlat, (maxlon - minlon) * coslat); // [lat degrees]
toplat = (minlat + maxlat + extension) / 2;
leftlon = (minlon + maxlon - extension / coslat) / 2;
dydlat = -size / extension; // [pixels/degree]
dxdlon = size / extension * coslat;
gtkMainLoopRunning = true;
thread(gtk_main).detach();
}
//-----------------------------------------------------------------------------
bool Graph::pan() {
const int sqrSignifPan = sqr(4);
while (!closed) {
if (leftbuttondown) {
int x0 = mousex;
int y0 = mousey;
int dx = 0, dy = 0;
GdkPixbuf *origPixbuf = gdk_pixbuf_new_from_file("/tmp/image.png", NULL);
char *origPixels = (char *)gdk_pixbuf_get_pixels(origPixbuf);
const int rowstride = gdk_pixbuf_get_rowstride(origPixbuf);
const int nChannels = gdk_pixbuf_get_n_channels(origPixbuf);
char *imagePixels = (char *)gdk_pixbuf_get_pixels(gtk_image_get_pixbuf(image));
while (leftbuttondown) {
const int dx0 = dx, dy0 = dy;
dx = mousex - x0, dy = mousey - y0;
if (sqr(dx - dx0) + sqr(dy - dy0) >= sqrSignifPan) {
const int minx = max(0, -dx);
const int nx = max(0, size - abs(dx));
if (nx > 0) {
for (int y = max(0, -dy); y < min(size, size - dy); ++y) {
memcpy(imagePixels + (y + dy) * rowstride + (minx + dx) * nChannels, origPixels + y * rowstride + minx * nChannels, nx * nChannels);
}
// gdk_pixbuf_save(gtk_image_get_pixbuf(image), "/tmp/imagePixbuf.png", "png", NULL, NULL);
gtk_widget_queue_draw((GtkWidget *)image);
SLEEP(10); // pause for drawing
}
}
SLEEP(100);
}
// rescale graph
toplat -= (mousey - y0) / dydlat;
leftlon -= (mousex - x0) / dxdlon;
dxdlon = -dydlat * cos((toplat + size / dydlat / 2) * M_PI / 180);
gtk_widget_queue_draw((GtkWidget *)image);
return true;
}
SLEEP(100);
}
return false;
}
//-----------------------------------------------------------------------------
void Graph::plotRect(const double minlat, const double minlon, const double maxlat, const double maxlon) {
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_paint(cr);
cairo_rectangle(cr, (minlon - leftlon) * dxdlon, (minlat - toplat) * dydlat, (maxlon - minlon) * dxdlon, (maxlat - minlat) * dydlat);
cairo_set_source_rgb(cr, 0, 1, 0);
cairo_fill(cr);
mtx.lock();
remove(png);
cairo_surface_write_to_png(surface, png);
mtx.unlock();
}
//-----------------------------------------------------------------------------
int main() {
const double minlat = 59, minlon = 16, maxlat = 60, maxlon = 18;
Graph *graph = new Graph(minlat - 0.5, minlon - 1, maxlat + 0.5, maxlon + 1);
do {
graph->plotRect(minlat, minlon, maxlat, maxlon);
} while (graph->pan());
delete graph;
}

C++, ncurses: unable to display menu before a key is pressed

With a friend I am working on a tetris like game within a terminal. We are using ncurses to manage it and we have different "views". For example a view manages the grid while the other manages the Menu. However we have a problem: when we start the game, we need to press a key in order to see it, otherwise the window is empty.
Here is the code ran when we create the menu (the constructor):
MenuScreen::MenuScreen()
{
if (has_colors())
{
use_default_colors();
start_color();
init_pair(WHITEONRED, COLOR_WHITE, COLOR_RED);
init_pair(WHITEONBLUE, COLOR_WHITE, COLOR_BLUE);
init_pair(REDONWHITE, COLOR_RED, COLOR_WHITE);
}
char *choices[] = /* The menu choices */
{
(char *)" Solo ",
(char *)" Bot ",
(char *)" Tetrix ",
(char *)" Quitter ",
NULL};
/* Calculate nchoices */
for (n_choices = 0; choices[n_choices]; n_choices++)
;
/* alloction of an iteam array for the menu */
my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *));
for (ssChoice = 0; ssChoice < n_choices; ++ssChoice)
my_items[ssChoice] = new_item(choices[ssChoice], NULL);
my_items[n_choices] = (ITEM *)NULL;
/* menu structure creation */
my_menu = new_menu((ITEM **)my_items);
/* symbole on the left of selected iteam*/
set_menu_mark(my_menu, "> ");
/* Windows Border cration */
wBorder = newwin(8, 40, LINES / 2 - 8 / 2, COLS / 2 - 40 / 2);
registerWindow(wBorder);
wattrset(wBorder, COLOR_PAIR(WHITEONRED));
windowsFilling(wBorder);
box(wBorder, 0, 0);
windowsBorderTitle(wBorder, " option ");
wUI = derwin(wBorder, 8 - 2, 40 - 2, 2, 2);
registerWindow(wUI);
set_menu_sub(my_menu, wUI);
set_menu_fore(my_menu, COLOR_PAIR(REDONWHITE));
set_menu_back(my_menu, COLOR_PAIR(WHITEONRED));
/* menu display */
post_menu(my_menu);
}
And when the next key is pressed:
void MenuScreen::next()
{
menu_driver(my_menu, REQ_DOWN_ITEM);
update();
}
And here is what update() contains:
void MenuScreen::update()
{
touchwin(wUI);
wrefresh(wUI);
touchwin(wBorder);
wrefresh(wBorder);
}
If we remove update() from the next() function, the menu is no longer displayed when we press the next key, so we tried to add a call to update() at the end of the constructor, but this didn't work. We have no idea what could cause this bug. Here is our entire source code:
https://github.com/Th0rgal/poyuterm/tree/22e2422930a29fbe83414e382fd566c3eac69366
EDIT: Here is a minimal reproducible example made by my friend:
To build it, copy paste it in a menu.cpp file and type: g++ menu.cpp -o menu -lncurses -l menu
#include <stdlib.h> /* calloc() */
#include <string.h> /* strlen() */
#include <ncurses.h>
#include <menu.h>
#include <curses.h>
#define WHITEONRED 10
#define WHITEONBLUE 20
#define WHITEONBLACK 30
#define BLACKONWHITE 40
#define REDONWHITE 50
void windowsBorderTitle(WINDOW *pwin, const char *title)
{
int x, maxy, maxx, stringsize;
getmaxyx(pwin, maxy, maxx);
stringsize = 4 + strlen(title);
x = (maxx - stringsize) / 2;
mvwaddch(pwin, 0, x, ACS_RTEE);
waddch(pwin, ' ');
waddstr(pwin, title);
waddch(pwin, ' ');
waddch(pwin, ACS_LTEE);
}
void windowsFilling(WINDOW *pwin)
{
int y, x, maxy, maxx;
getmaxyx(pwin, maxy, maxx);
for (y = 0; y < maxy; y++)
for (x = 0; x < maxx; x++)
mvwaddch(pwin, y, x, ' ');
}
int main(int argc, char const *argv[])
{
initscr(); /* start ncurses */
cbreak(); /* immediately acquire each keystroke */
noecho(); /* do not echo user keystrokes */
keypad(stdscr, TRUE); /* enable detection of function keys */
int c;
ITEM **my_items;
MENU *my_menu;
WINDOW *wUI;
WINDOW *wBorder;
int n_choices;
int ssChoice;
int my_choice = -1;
if (has_colors())
{
use_default_colors();
start_color();
init_pair(WHITEONRED, COLOR_WHITE, COLOR_RED);
init_pair(WHITEONBLUE, COLOR_WHITE, COLOR_BLUE);
init_pair(REDONWHITE, COLOR_RED, COLOR_WHITE);
}
char *choices[] = /* The menu choices */
{
(char *)" Solo ",
(char *)" Bot ",
(char *)" Tetrix ",
(char *)" Quitter ",
NULL};
for(n_choices=0; choices[n_choices]; n_choices++);
/* ALLOCATE ITEM ARRAY AND INDIVIDUAL ITEMS */
my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *));
for(ssChoice = 0; ssChoice < n_choices; ++ssChoice)
my_items[ssChoice] = new_item(choices[ssChoice], NULL);
my_items[n_choices] = (ITEM *)NULL;
/* CREATE THE MENU STRUCTURE */
my_menu = new_menu((ITEM **)my_items);
/* PUT > TO THE LEFT OF HIGHLIGHTED ITEM */
set_menu_mark(my_menu, "> ");
/* SET UP WINDOW FOR MENU'S BORDER */
wBorder = newwin(16, 40, 2, 20);
wattrset(wBorder, COLOR_PAIR(WHITEONRED) | WA_BOLD);
windowsFilling(wBorder);
box(wBorder, 0, 0);
windowsBorderTitle(wBorder, "Choose one");
/* SET UP WINDOW FOR THE MENU'S USER INTERFACE */
wUI = derwin(wBorder, 16-2, 40-2, 2, 2);
/* ASSOCIATE THESE WINDOWS WITH THE MENU */
set_menu_win(my_menu, wBorder);
set_menu_sub(my_menu, wUI);
/* MATCH MENU'S COLORS TO THAT OF ITS WINDOWS */
set_menu_fore(my_menu, COLOR_PAIR(REDONWHITE));
set_menu_back(my_menu, COLOR_PAIR(WHITEONRED) | WA_BOLD);
/* SET UP AN ENVIRONMENT CONDUCIVE TO MENUING */
keypad(wUI, TRUE); /* enable detection of function keys */
noecho(); /* user keystrokes don't echo */
curs_set(0); /* make cursor invisible */
/* DISPLAY THE MENU */
post_menu(my_menu);
touchwin(wBorder);
wrefresh(wBorder);
while(my_choice == -1)
{
touchwin(wBorder);
wrefresh(wBorder);
touchwin(wUI); /* refresh prior to getch() */
wrefresh(wUI); /* refresh prior to getch() */
c = getch();
switch(c)
{
case KEY_DOWN:
menu_driver(my_menu, REQ_DOWN_ITEM);
break;
case KEY_UP:
menu_driver(my_menu, REQ_UP_ITEM);
break;
case 10: /* Enter */
my_choice = item_index(current_item(my_menu));
pos_menu_cursor(my_menu);
break;
}
}
unpost_menu(my_menu);
for(ssChoice = 0; ssChoice < n_choices; ++ssChoice)
free_item(my_items[ssChoice]);
free_menu(my_menu);
delwin(wUI);
delwin(wBorder);
touchwin(stdscr);
wrefresh(stdscr);
endwin();
}

Text overlay not working with Xorg modesetting driver

This is a piece of code which displays text and background rectangle When this piece of code is run with Intel as default XORG driver everything works fine both text and rectangle are being displayed,whereas when i switch to the Modesetting driver only the background rectangle is seen and text is not being displayed
#include <iostream>
#include<unistd.h>
#include <sstream>
#include <string>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xft/Xft.h>
#include <X11/extensions/XShm.h>
#include <sys/ipc.h>
#include <sys/shm.h>
using namespace std;
int main()
{
Display *display = XOpenDisplay(NULL);
Screen *scn = DefaultScreenOfDisplay(display);
int screen_num = DefaultScreen(display);
int screen_width = DisplayWidth(display, screen_num);
int screen_height = DisplayHeight(display, screen_num);
int defaultScnDepth = DefaultDepthOfScreen(scn);
Visual *visual = DefaultVisualOfScreen(scn);
Window window=XCreateSimpleWindow(display,RootWindow(display,screen_num), 50, 50, 400, 400, 2 ,BlackPixel(display,screen_num),WhitePixel(display,screen_num));
//XFlush(display)
XMapWindow(display, window);
XShmSegmentInfo shmInfo;
XImage *xImage;
Pixmap backPixmap;
(xImage) = XShmCreateImage(display, visual, defaultScnDepth, ZPixmap, NULL, &shmInfo, screen_width, screen_height);
shmInfo.shmid = shmget(IPC_PRIVATE, (xImage)->bytes_per_line * (xImage)->height, IPC_CREAT | 0777);
shmInfo.shmaddr = (char *) shmat(shmInfo.shmid, 0, 0);
xImage->data = shmInfo.shmaddr;
shmInfo.readOnly = False;
XShmAttach(display, &shmInfo);
(backPixmap) = XShmCreatePixmap(display, window, (char *) (shmInfo.shmaddr), &shmInfo, (xImage)->width, (xImage)->height, (xImage)->depth);
XGCValues values;
GC gc = XCreateGC(display, backPixmap, 0, &values);
XSync(display, false);
Drawable drawable =backPixmap;
visual = DefaultVisual(display, DefaultScreen(display));
Colormap colormap = XCreateColormap(display, window, visual, AllocNone);
//gc = XCreateGC(display, drawable, 0, &values);
//XFlushGC(display, gc);
const char *text = "Hello";
XftDraw *xftDraw = NULL;
XRenderColor xrFGColor, xrBGColor;
XftColor xftFGColor, xftBGColor;
XftFont *font = NULL;
font = XftFontOpenName( display, DefaultScreen( display ), "morpheus-18" );
xftDraw = XftDrawCreate(display, drawable, visual, colormap);
int nextLineStartY, rectYRef;
bool firstIte;
unsigned int rectX, rectY, rectWidth, rectHeight;
nextLineStartY = 0; rectYRef = 0;
firstIte = true;
rectX = 0; rectY = 0; rectWidth = 0; rectHeight = 0;
std::istringstream strStream(text);
std::string line;
while(std::getline(strStream, line))
{
const char *lineText = line.c_str();
if(*lineText == '\0')
{
nextLineStartY += rectHeight + 1;
continue;
}
const char *text = lineText;
XGlyphInfo extents;
XftTextExtents8(display, font, (XftChar8 *)text, strlen(text), &extents);
unsigned int width = extents.width;
unsigned int height = extents.height;
int ascent = extents.y;
int lBearing = extents.x;
rectX = 50 - lBearing - 1;
rectY = 50 - ascent - 1;
rectWidth = width + 2 * 1;
rectHeight = height + 5 + 1;
if(firstIte)
{
rectYRef = rectY;
firstIte = false;
}
int diff = rectYRef - rectY;
rectY += nextLineStartY + diff;
nextLineStartY += rectHeight + 1;
if(1)
{
xrBGColor.red = 0x7fff;
xrBGColor.green= 0x7fff;
xrBGColor.blue = 0x7fff;
xrBGColor.alpha= 0xffff;
XftColorAllocValue(display, visual, colormap, &xrBGColor, &xftBGColor);
// Draw background fill rectangle
XftDrawRect(xftDraw, &xftBGColor, rectX, rectY, rectWidth, rectHeight);
XftColorFree(display, visual, colormap, &xftBGColor);
}
xrFGColor.red = 0xbfff;
xrFGColor.green = 0xbfff;
xrFGColor.blue = 0xbfff;
xrFGColor.alpha= 0xffff;
XftColorAllocValue(display, visual, colormap, &xrFGColor, &xftFGColor);
// Overlay Text
XftDrawString8(xftDraw, &xftFGColor, font, 50, 50, (XftChar8 *) text, strlen(text));
XColor xForeColor;
xForeColor.red = 0xafff;
xForeColor.green = 0xafff;
xForeColor.blue = 0xffff;
if(XAllocColor(display,colormap,&xForeColor))
XSetForeground(display,gc,xForeColor.pixel);
XftColorFree(display, visual, colormap, &xftFGColor);
XFreeColors(display, colormap, &(xForeColor.pixel), 1, 0);
}
XftDrawDestroy(xftDraw);
XShmPutImage(display, window, gc, xImage, 0, 0, 0, 0, 400, 400, false);
XSync(display, false);
getchar();
}
I tried out other drivers too, with the radeon drivers i see a X error that shared pixmaps are not supported while i don't see any such error for the modesetting driver.
Has this something to do with the shared pixmaps, if yes how should i make it work with the modesetting driver.
I have been stuck on this for a while now, any help would be appreciated.

How to display an image into an XCB window?

I'm having trouble displaying an image (PNG extracted with libpng) into an XCB window, it is always entirely empty/white. I'm pretty sure the PNG extraction is correct since I can perfectly re-write it into another file.
I've tried everything I found (explanations, guides, documentation) and I'm running out of ideas:
Creating an xcb_pixmap_t calling xcb_create_pixmap_from_bitmap_data() with the data taken from the PNG, then calling xcb_copy_area() into the EXPOSE part of the event loop.
Creating an xcb_image_t* calling xcb_image_create_from_bitmap_data() then trying to map it to the window with xcb_image_put(). I've even tried to display each pixel with xcb_image_put_pixel(), but without success.
Code sample:
xcb_pixmap_t pixmap = xcb_create_pixmap_from_bitmap_data(
connection, // xcb_connect(0, 0) (type: xcb_connection_t*)
window, // xcb_generate_id(connection) (type: xcb_window_t)
img.getData(), // uint8_t*
img.getWidth(), // 128
img.getHeight(), // 128
img.getBitDepth(), // 8
screen->black_pixel, // screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data (type: xcb_screen_t*)
screen->white_pixel,
nullptr);
// "img" is an instance of my own custom class, result of PNG reading
xcb_image_t* image = xcb_image_create_from_bitmap_data(
img.getData(),
img.getWidth(),
img.getHeight()); // image->data seems fine
xcb_image_put(connection,
window,
graphicsContext,
image, 0, 0, 0); // This does nothing
for (unsigned int i = 0; i < screen->height_in_pixels; ++i)
for (unsigned int j = 0; j < screen->width_in_pixels; ++j)
xcb_image_put_pixel(image, j, i, 0); // Displays nothing
[...]
// Into event loop
case XCB_EXPOSE: {
xcb_expose_event_t* exposeEvent = reinterpret_cast<xcb_expose_event_t*>(event);
xcb_copy_area(connection,
pixmap,
window,
graphicsContext,
exposeEvent->x, exposeEvent->y, // Top left x & y coordinates of the source's region to copy
exposeEvent->x, exposeEvent->y, // Top left x & y coordinates of the destination's region to copy to
exposeEvent->width,
exposeEvent->height);
xcb_flush(connection);
break;
}
From the examples I found I saw that it didn't need a colormap, but could that be the case? Could anyone tell me where I've gone wrong?
I threw together a simple xcb image viewer about 4 years ago, but just noticed this question, so apologies for the necromancy.
It uses xcb_image, stb_image and nanosvg, but compiles to a relatively small static binary (with a musl or uclibc toolchain)
#include <xcb/xcb.h>
#include <xcb/xcb_image.h>
#define STBI_NO_HDR
#define STBI_NO_LINEAR
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define NANOSVG_IMPLEMENTATION
#include "nanosvg.h"
#define NANOSVGRAST_IMPLEMENTATION
#include "nanosvgrast.h"
int main(int argc, char **argv){
xcb_connection_t *c = xcb_connect(0, 0);
xcb_screen_t *s = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
int w, h, n,
depth = s->root_depth,
win_class = XCB_WINDOW_CLASS_INPUT_OUTPUT,
format = XCB_IMAGE_FORMAT_Z_PIXMAP;
xcb_colormap_t colormap = s->default_colormap;
xcb_drawable_t win = xcb_generate_id(c);
xcb_gcontext_t gc = xcb_generate_id(c);
xcb_pixmap_t pixmap = xcb_generate_id(c);
xcb_generic_event_t *ev;
xcb_image_t *image;
NSVGimage *shapes = NULL;
NSVGrasterizer *rast = NULL;
char *data = NULL;
unsigned *dp;
size_t i, len;
uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK,
value_mask = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS,
values[] = { s->black_pixel, value_mask };
if (argc<2) return -1;
if ((data = stbi_load(argv[1], &w, &h, &n, 4)))
;
else if ((shapes = nsvgParseFromFile(argv[1], "px", 96.0f))) {
w = (int)shapes->width;
h = (int)shapes->height;
rast = nsvgCreateRasterizer();
data = malloc(w*h*4);
nsvgRasterize(rast, shapes, 0,0,1, data, w, h, w*4);
}else return -1;
for(i=0,len=w*h,dp=(unsigned *)data;i<len;i++) //rgba to bgra
dp[i]=dp[i]&0xff00ff00|((dp[i]>>16)&0xFF)|((dp[i]<<16)&0xFF0000);
xcb_create_window(c,depth,win,s->root,0,0,w,h,1,win_class,s->root_visual,mask,values);
xcb_create_pixmap(c,depth,pixmap,win,w,h);
xcb_create_gc(c,gc,pixmap,0,NULL);
image = xcb_image_create_native(c,w,h,format,depth,data,w*h*4,data);
xcb_image_put(c, pixmap, gc, image, 0, 0, 0);
xcb_image_destroy(image);
xcb_map_window(c, win);
xcb_flush(c);
while ((ev = xcb_wait_for_event(c))) {
switch (ev->response_type & ~0x80){
case XCB_EXPOSE: {
xcb_expose_event_t *x = (xcb_expose_event_t *)ev;
xcb_copy_area(c,pixmap,win,gc,x->x,x->y,x->x,x->y,x->width,x->height);
xcb_flush(c);
}break;
case XCB_BUTTON_PRESS: goto end;
default: break;
}
}
end:
xcb_free_pixmap(c, pixmap);
xcb_disconnect(c);
return 0;
}

How to create a full screen window on the current monitor with GLFW

Creating a window with GLFW3 is done using glfwCreateWindow:
GLFWwindow* glfwCreateWindow ( int width,
int height,
const char *title,
GLFWmonitor *monitor,
GLFWwindow *share
)
If the monitor parameter is not NULL, the window is created in full screen mode on the given monitor. One can receive the primary monitor by calling glfwGetPrimaryMonitor, or chose one of the results of glfwGetMonitors. But how can I create a full screen window on the current monitor, i.e. the monitor the window is currently running in windowed mode? There seems to be no way to receive the currently used monitor. There is glfwGetWindowMonitor, but it only returns the monitor in full screen mode, NULL in windowed mode.
You can find the current monitor with glfwGetWindowPos/glfwGetWindowSize.
This function returns the monitor that contains the greater window area.
static int mini(int x, int y)
{
return x < y ? x : y;
}
static int maxi(int x, int y)
{
return x > y ? x : y;
}
GLFWmonitor* get_current_monitor(GLFWwindow *window)
{
int nmonitors, i;
int wx, wy, ww, wh;
int mx, my, mw, mh;
int overlap, bestoverlap;
GLFWmonitor *bestmonitor;
GLFWmonitor **monitors;
const GLFWvidmode *mode;
bestoverlap = 0;
bestmonitor = NULL;
glfwGetWindowPos(window, &wx, &wy);
glfwGetWindowSize(window, &ww, &wh);
monitors = glfwGetMonitors(&nmonitors);
for (i = 0; i < nmonitors; i++) {
mode = glfwGetVideoMode(monitors[i]);
glfwGetMonitorPos(monitors[i], &mx, &my);
mw = mode->width;
mh = mode->height;
overlap =
maxi(0, mini(wx + ww, mx + mw) - maxi(wx, mx)) *
maxi(0, mini(wy + wh, my + mh) - maxi(wy, my));
if (bestoverlap < overlap) {
bestoverlap = overlap;
bestmonitor = monitors[i];
}
}
return bestmonitor;
}
After discussion on IRC it seems that it is not possible to retrieve the currently active monitor (as in the monitor the window is currently drawn on) with GLFW. Therefore it is not possible to create a full screen window on the current monitor.
EDIT: Even though there is no GLFW functionality to directly achieve this, the answer of Shmo provides an elegant solution.
Here is Shmo's answer, ported over to LWJGL:
/** Determines the current monitor that the specified window is being displayed on.
* If the monitor could not be determined, the primary monitor will be returned.
*
* #param window The window to query
* #return The current monitor on which the window is being displayed, or the primary monitor if one could not be determined
* #author Shmo<br>
* Ported to LWJGL by Brian_Entei */
#NativeType("GLFWmonitor *")
public static final long glfwGetCurrentMonitor(long window) {
int[] wx = {0}, wy = {0}, ww = {0}, wh = {0};
int[] mx = {0}, my = {0}, mw = {0}, mh = {0};
int overlap, bestoverlap;
long bestmonitor;
PointerBuffer monitors;
GLFWVidMode mode;
bestoverlap = 0;
bestmonitor = glfwGetPrimaryMonitor();// (You could set this back to NULL, but I'd rather be guaranteed to get a valid monitor);
glfwGetWindowPos(window, wx, wy);
glfwGetWindowSize(window, ww, wh);
monitors = glfwGetMonitors();
while(monitors.hasRemaining()) {
long monitor = monitors.get();
mode = glfwGetVideoMode(monitor);
glfwGetMonitorPos(monitor, mx, my);
mw[0] = mode.width();
mh[0] = mode.height();
overlap =
Math.max(0, Math.min(wx[0] + ww[0], mx[0] + mw[0]) - Math.max(wx[0], mx[0])) *
Math.max(0, Math.min(wy[0] + wh[0], my[0] + mh[0]) - Math.max(wy[0], my[0]));
if (bestoverlap < overlap) {
bestoverlap = overlap;
bestmonitor = monitor;
}
}
return bestmonitor;
}