I'm using XCB to create my x11 window and, somewhere in the code, I want to move it.
I make a little test to print the window position (0, 0), then move it, and print the position again (200, 100).
Saddly, I have always x:10 and y:10.
Here the code:
// g++ -o test test_xcb.cpp -lX11 -lxcb
#include <xcb/xcb.h>
#include <iostream>
using namespace std;
void print_window_xywh(xcb_connection_t *conn, xcb_drawable_t win)
{
auto geo = xcb_get_geometry_reply(
conn, xcb_get_geometry(conn, win), nullptr);
cout << "Window( " << win << ") - x: " << geo->x
<< " - y: " << geo->y
<< " - w: " << geo->width
<< " - h: " << geo->height << endl;
}
int main(void) {
xcb_connection_t *c;
xcb_screen_t *screen;
xcb_window_t win;
/* Open the connection to the X server */
c = xcb_connect (NULL, NULL);
/* Get the first screen */
screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
/* Ask for our window's Id */
win = xcb_generate_id(c);
/* Create the window */
xcb_create_window (c, /* Connection */
XCB_COPY_FROM_PARENT, /* depth (same as root)*/
win, /* window Id */
screen->root, /* parent window */
10, 10, /* x, y */
150, 150, /* width, height */
10, /* border_width */
XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */
screen->root_visual, /* visual */
0, NULL); /* masks, not used yet */
/* Map the window on the screen */
xcb_map_window (c, win);
/* Make sure commands are sent, so window is shown */
xcb_flush (c);
// Print the position and size of the window
print_window_xywh(c, win);
// Move the window
const static uint32_t values[] = { 200, 100 };
xcb_configure_window(c, win, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values);
// Print again, should be 200 for x and 100 for y
print_window_xywh(c, win);
return 0;
}
Did I miss something? Thank you.
The short version: You are ignoring the interaction with the window manager.
The long version:
First, the position that GetGeometry gives you is relative to the parent window. With a reparenting window manager, the WM will add a frame window around your window to draw window decorations to (titlebar, close button, ...). If you want the position of your window on screen, you should use use xcb_translate_coordinates(c, win, screen->root, 0, 0). The reply to this request will give you the position of 0,0 of your window translated to the root window.
However, in your example that will still not work. This is because of how the window manager works. It basically forbids your program from moving its window (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT). Due to this, when you try to move your window, the X11 server only sends this request as an event to the window manager. The window manager then needs some time to handle this request. Since you are immediately checking the window position again, the request will not yet have been handled.
Related
Per design requirements, I am developing a GUI in FLTK that must have a main (parent) window, a child window, and an X Window that is the child of the child window. This is in Ubuntu 16.04.
Running my original project with this setup produces the XLib error BadWindow (invalid Window parameter) (Details: serial 7 error_code 3 request_code 1 minor_code 0).
I have the following test program with only the features relevant to the error that reproduces a similar error:
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Button.H>
#include <FL/x.H>
#include <iostream>
class ChildWindow : public Fl_Window {
public:
ChildWindow() : Fl_Window(100, 100, 300, 200, "Child"){
this->end();
this->show();
Display * dis = XOpenDisplay(NULL);
std::cout << "Child XID: " << (void *)fl_xid(this) << '\n';
std::cout << "XWindow XID: " << dis << '\n';
Window win = XCreateSimpleWindow(dis, fl_xid(this),
5, 5, 100, 100, 0, 0, 0);
XMapRaised(dis, win);
XSync(dis, false);
}
};
class ParentWindow : public Fl_Window {
public:
static ChildWindow * child;
ParentWindow() : Fl_Window(100, 100, 400, 300, "Parent"){
Fl_Button * b = new Fl_Button(10, 10, 70, 20, "Make Child");
b->callback(CallbackMakeChild, NULL);
this->add(b);
this->end();
this->show();
std::cout << "Parent XID: " << (void *)fl_xid(this) << '\n';
}
static void CallbackMakeChild(Fl_Widget * w, void * o){
child = new ChildWindow();
child->show();
}
};
ChildWindow * ParentWindow::child = NULL;
with the main function of
int main(){
ParentWindow parent;
Fl::run();
}
When run, the above code should create a window with a button. When the button is pressed, a child window will be created and the X Window will be attempted to be created. Here is the console output:
Parent XID: 0x4400002
Child XID: 0x4400005
XWindow XID: 0xe03140
X_CreateWindow: BadWindow (invalid Window parameter) 0x4400005
X_ConfigureWindow: BadWindow (invalid Window parameter) 0x4600001
X_MapWindow: BadWindow (invalid Window parameter) 0x4600001
The child window and X Window by themselves behave fine:
int main(){
ChildWindow child;
Fl::run();
}
This code (creating two non-hierarchical windows) also fails:
int main(){
ChildWindow child1; // This window works
ChildWindow child2; // This causes similar errors as above
Fl::run();
}
I have also tried various combinations of fl_open_display and Fl_Window::make_current without success.
(All code, being in one file, compiles by running ./fltk-config --compile myprog.cpp)
The pattern here appears that X windows initialize fine for the first FLTK window, but do not for windows created after that. My guess is that it has something to do with how FLTK interfaces/initializes with XLib, but I have not been able to find specifics in the documentation.
Does anyone have an explanation/solution for why X Window initialization only works when using the first-created FLTK window as a parent?
The problem was that XOpenDisplay was being called twice. FLTK opens the display as part of the initialization process, and calling it again with initializing the X window messed up the system.
This was solved by removing the line that said dis = XOpenDisplay(NULL) and replacing references to dis, with the FLTK display located at fl_display.
I need to get working gtk3 with vtk6.
Ive just built (after some effort) gtkglext for gtk3.
Later I built vtkmm1.2 with the win32 patches and I do not see vtk widget.
Due to this, I discovered I cant see any draw in the gtkglext examples.
On the other side, Ive tried the excellent example of gtkglarea (the new, gtk built in one ) with plain opengl from https://www.bassi.io/articles/2015/02/17/using-opengl-with-gtk/
and I get no draw because "fb setup not supported".
It seems the framebuffer is complete, checking gtkglarea.c.
How can i solve this?
Anyone have been able to draw something in gtk with opengl, for windows?
This is the simplest code i've made,and i'm getting the mentioned error enter image description here, and adapting the signals to the new built in GtkGLArea ("render" instead of "draw")
#include <math.h>
#include <gtk/gtk.h>
//#include <gtkgl/gtkglarea.h> //LUCIANO, gtkglarea is built in now
#include <gtk/gtkglarea.h>
#include <GL/gl.h>
gint init(GtkWidget *widget)
{
/* OpenGL functions can be called only if make_current returns true */
gtk_gl_area_make_current(GTK_GL_AREA(widget));
{
GtkAllocation allocation;
gtk_widget_get_allocation (widget, &allocation);
glViewport(0, 0, allocation.width, allocation.height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0,100, 100,0, -1,1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
return TRUE;
}
/* When widget is exposed it's contents are redrawn. */
gboolean draw (GtkWidget *widget, cairo_t *cr, gpointer data)
{
/* OpenGL functions can be called only if make_current returns true */
gtk_gl_area_make_current(GTK_GL_AREA(widget));
{
/* Draw simple triangle */
glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1,1,1);
glBegin(GL_TRIANGLES);
glVertex2f(10,10);
glVertex2f(10,90);
glVertex2f(90,90);
glEnd();
/* Swap backbuffer to front */
//ggla_area_swap_buffers(GGLA_AREA(widget));
gtk_gl_area_attach_buffers(GTK_GL_AREA(widget));
}
return TRUE;
}
/* When glarea widget size changes, viewport size is set to match the new size */
gint reshape(GtkWidget *widget, GdkEventConfigure *event)
{
/* OpenGL functions can be called only if make_current returns true */
//if (ggla_area_make_current(GTK_GL_AREA(widget)))
gtk_gl_area_make_current(GTK_GL_AREA(widget));
{
GtkAllocation allocation;
gtk_widget_get_allocation (widget, &allocation);
glViewport(0, 0, allocation.width, allocation.height);
}
return TRUE;
}
int main(int argc, char **argv)
{
GtkWidget *window,*glarea;
gchar *info_str;
/* Attribute list for gtkglarea widget. Specifies a
list of Boolean attributes and enum/integer
attribute/value pairs. The last attribute must be
GGLA_NONE. See glXChooseVisual manpage for further
explanation.
*/
int attrlist[] = {
// GGLA_RGBA,
// GGLA_RED_SIZE,1,
// GGLA_GREEN_SIZE,1,
// GGLA_BLUE_SIZE,1,
// GGLA_DOUBLEBUFFER,
// GGLA_NONE
};
/* initialize gtk */
gtk_init(&argc, &argv);
/* Check if OpenGL is supported. */
// if (ggla_query() == FALSE) {
// g_print("OpenGL not supported\n");
// return 0;
// }
/* Create new top level window. */
window = gtk_window_new( GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "Simple");
gtk_container_set_border_width(GTK_CONTAINER(window), 10);
/* Quit form main if got delete event */
g_signal_connect(G_OBJECT(window), "delete-event",
G_CALLBACK(gtk_main_quit), NULL);
/* Create new OpenGL widget. */
//glarea = GTK_WIDGET(gtk_gl_area_new(attrlist));
glarea = gtk_gl_area_new();
/* Events for widget must be set before X Window is created */
gtk_widget_set_events(GTK_WIDGET(glarea),
GDK_EXPOSURE_MASK|
GDK_BUTTON_PRESS_MASK);
init(glarea);
/* Connect signal handlers */
/* Redraw image when exposed. */
// g_signal_connect(G_OBJECT(glarea), "draw",
// G_CALLBACK(draw), NULL);
// /* When window is resized viewport needs to be resized also. */
// g_signal_connect(G_OBJECT(glarea), "configure-event",
// G_CALLBACK(reshape), NULL);
// /* Do initialization when widget has been realized. */
// g_signal_connect(G_OBJECT(glarea), "realize",
// G_CALLBACK(init), NULL);
g_signal_connect(G_OBJECT(glarea), "render",
G_CALLBACK(draw), NULL);
/* When window is resized viewport needs to be resized also. */
// g_signal_connect(G_OBJECT(glarea), "resize",
// G_CALLBACK(reshape), NULL);
/* Do initialization when widget has been realized. */
// g_signal_connect(G_OBJECT(glarea), "create-context",
// G_CALLBACK(init), NULL);
/* set minimum size */
gtk_widget_set_size_request(GTK_WIDGET(glarea), 100,100);
/* put glarea into window and show it all */
gtk_container_add(GTK_CONTAINER(window),GTK_WIDGET(glarea));
gtk_widget_show(GTK_WIDGET(glarea));
gtk_widget_show(GTK_WIDGET(window));
/* vendor dependent version info string */
// info_str = ggla_get_info();
// g_print(info_str);
// g_free(info_str);
gtk_main();
return 0;
}
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
Display *dis;
int screen;
Window win;
GC gc;
void init_x() {
/* get the colors black and white (see section for details) */
unsigned long black,white;
/* use the information from the environment variable DISPLAY
to create the X connection:
*/
dis=XOpenDisplay((char *)0);
screen=DefaultScreen(dis);
black=BlackPixel(dis,screen), /* get color black */
white=WhitePixel(dis, screen); /* get color white */
/* once the display is initialized, create the window.
This window will be have be 200 pixels across and 300 down.
It will have the foreground white and background black
*/
win=XCreateSimpleWindow(dis,DefaultRootWindow(dis),0,0,
200, 300, 5, white, black);
/* here is where some properties of the window can be set.
The third and fourth items indicate the name which appears
at the top of the window and the name of the minimized window
respectively.
*/
XSetStandardProperties(dis,win,"My Window","HI!",None,NULL,0,NULL);
/* this routine determines which types of input are allowed in
the input. see the appropriate section for details...
*/
XSelectInput(dis, win, ExposureMask|ButtonPressMask|KeyPressMask);
/* create the Graphics Context */
gc=XCreateGC(dis, win, 0,0);
/* here is another routine to set the foreground and background
colors _currently_ in use in the window.
*/
XSetBackground(dis,gc,white);
XSetForeground(dis,gc,black);
/* clear the window and bring it on top of the other windows */
XClearWindow(dis, win);
XMapRaised(dis, win);
}
int main()
{
init_x();
return 0;
}
This is my first program to get started with X programming. I got this sample code from Internet, I compiled and ran the code but there is no output window.Can anyone please guide me what modification is required here to display a window.
You don't have an event loop, so the program initializes the window and then exits immediately.
Try using
XEvent e;
while (1) {
XNextEvent(dis, &e);
if (e.type == KeyPress)
break;
}
and also clean up on exit using
XCloseDisplay(dis);
I'm using Ubuntu 12.04 in a VM.
Upper left is never correct. Width and height are correct about 90% of the time.
XMoveWindow and friends have no effect on the rendered position of the window.
Source:
#include <stdio.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/X.h>
int main(int argc, char **argv)
{
Display *disp = XOpenDisplay(0);
GLint attr[] = {GLX_RGBA, GLX_DEPTH_SIZE, 24, GX_DOUBLEBUFFER, None};
XVisualInfo *vinfo = glXChooseVisual(disp,0,attr);
Window rootWnd = DefaultRootWindow(disp);
XSetWindowAttributes setWndAttr = {0};
setWndAttr.colormap = XCreateColormap(disp,rootWnd,vinfo->visual,AllocNone);
setWndAttr.event_mask =
ExposureMask|
StructureNotifyMask;
Window wnd = XCreateWindow(
disp,rootWnd,
64,64, // can be ignored (asinine)
512,512,
0,vinfo->depth,
InputOutput,
vinfo->visual,
CWColormap|CWEventMask,
&setWndAttr
);
XStoreName(disp,wnd,"What is this crap?");
XMapWindow(disp,wnd);
// WMs allowed to completely ignore these, too?
//XMoveWindow(disp,wnd,128,128);
//XMoveResizeWindow(disp,wnd,128,128,256,256);
Atom closeWndAtom = XInternAtom(disp,"WM_DELETE_WINDOW",0);
XSetWMProtocols(disp,wnd,&closeWndAtom,1);
GLXContext ctx = glCreateContext(disp,vinfo,0,GL_TRUE);
glXMakeCurrent(disp,wnd,ctx);
bool run = true;
XEvent evt;
while(run){
XNextEvent(disp,&evt);
switch(evt.type){
case Expose:
{
XWindowAttributes wndAttr;
XGetWindowAttributes(disp,wnd,&wndAttr);
// these are NEVER correct (0,0 most of the time)
printf("%i, %i\n",wndAttr.x,wndAttr.y);
// these are correct, most of the time
//
// occasionally, either width or height will be 0
glViewport(0,0,wndAttr.width,wndAttr.height);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glBegin(GL_TRIANGLES);
glColor3f(1,0,0);
glVertex2f(0,0);
glColor3f(0,1,0);
glVertex2f(1,0);
glColor3f(0,0,1);
glVertex2f(0,1);
glEnd();
glXSwapBuffers(disp,wnd);
}break;
case ClientMessage:
{
run = false;
}break;
}
}
glXDestroyContext(disp,ctx);
XDestroyWindow(disp,wnd);
XCloseDisplay(disp);
return 0;
}
Note: There might be a spelling error to two, as pasting from within the VM wouldn't format correctly. As a result, I had to re-type it.
EDIT:
Because clarity is needed here: I don't care what the window manager does with the position I give it, I am interested in retrieving this information from the window manager reliably. The position I am given does not correspond to the rendered position of the window on the screen. For example: The window appears at the lower right of the screen, and the coordinates returned to me are (0,0). Moving the window around using the mouse doesn't change what XGetWindowAttributes returns.
It seems you are polling window information from Expose event, which may not have newest information about window at the time. Use ConfigureNotify event and it's properties to get updated position and size:
// you need to have this in your event mask(you've already got that):
EVENT_MASK |= StructureNotifyMask;
// in your event loop
// ...
case ConfigureNotify: // resize or move event
printf("x: %d, y:%d, width: %d, height: %d\n",
event.xconfigure.x,
event.xconfigure.y,
event.xconfigure.width,
event.xconfigure.height);
break;
I think, one of the option is to use XTranslateCoordinates:
XTranslateCoordinates(dpy,
wnd, // get position for this window
root_window, // something like macro: DefaultRootWindow(dpy)
0, 0, // local left top coordinates of the wnd
&dest_x, // these is position of wnd in root_window
&dest_y, // ...
&unused);
You also can use XGetGeometry instead of XGetWindowAttributes to get left, top, width and height of a drawable. As far as I know XGetWindowAttributes calls XGetGeometry to retrieve some of the attributes.
I know, I'm necroposter, but I was also looking for the answer and found out that the incorrect coordinates are related to Window Manager.
{
case ConfigureNotify :
printf("%d, %d : %u, %u\n",
event.xconfigure.x, event.xconfigure.y,
event.xconfigure.width, event.xconfigure.height);
break;
}
# Moving window
353, 100 : 791, 600
363, 113 : 791, 600
# Changing window size
1, 24 : 791, 600 << Pay attention to this
363, 113 : 791, 600
363, 113 : 791, 600
For the additional info you need to read ICCCM (4.1.5. Configuring the Window, 4.2.3. Window Move, 4.2.4. Window Resize) https://tronche.com/gui/x/icccm/sec-4.html#s-4.1.5
I have been checking out some Rogue like games (Larn, Rogue, etc) that are written in C and C++, and I have noticed that they do not have the scrollbars to the right of the console window.
How can I accomplish this same feature?
To remove the scrollbar, simply set the screen buffer height to be the same size as the height of the window:
#include <windows.h>
#include <iostream>
using namespace std;
int main()
{
// get handle to the console window
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
// retrieve screen buffer info
CONSOLE_SCREEN_BUFFER_INFO scrBufferInfo;
GetConsoleScreenBufferInfo(hOut, &scrBufferInfo);
// current window size
short winWidth = scrBufferInfo.srWindow.Right - scrBufferInfo.srWindow.Left + 1;
short winHeight = scrBufferInfo.srWindow.Bottom - scrBufferInfo.srWindow.Top + 1;
// current screen buffer size
short scrBufferWidth = scrBufferInfo.dwSize.X;
short scrBufferHeight = scrBufferInfo.dwSize.Y;
// to remove the scrollbar, make sure the window height matches the screen buffer height
COORD newSize;
newSize.X = scrBufferWidth;
newSize.Y = winHeight;
// set the new screen buffer dimensions
int Status = SetConsoleScreenBufferSize(hOut, newSize);
if (Status == 0)
{
cout << "SetConsoleScreenBufferSize() failed! Reason : " << GetLastError() << endl;
exit(Status);
}
// print the current screen buffer dimensions
GetConsoleScreenBufferInfo(hOut, &scrBufferInfo);
cout << "Screen Buffer Size : " << scrBufferInfo.dwSize.X << " x " << scrBufferInfo.dwSize.Y << endl;
return 0;
}
You need to make the console screen buffer the same size as the console window. Get the window size with GetConsoleScreenBufferInfo, srWindow member. Set the buffer size with SetConsoleScreenBufferSize().
Using #include <winuser.h>, you can simply do
ShowScrollBar(GetConsoleWindow(), SB_VERT, 0);
You can specify which scroll bar to hide using different parameters.
To remove scrollbars from the console, we can make the console screen buffer the same size as the console window. This can be done as follows:
#include <Windows.h>
#include <iostream>
int main() {
CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo;
// Get console handle and get screen buffer information from that handle.
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(hConsole, &screenBufferInfo);
// Get rid of the scrollbar by setting the screen buffer size the same as
// the console window size.
COORD new_screen_buffer_size;
// screenBufferInfo.srWindow allows us to obtain the width and height info
// of the visible console in character cells.
// That visible portion is what we want to set the screen buffer to, so that
// no scroll bars are needed to view the entire buffer.
new_screen_buffer_size.X = screenBufferInfo.srWindow.Right -
screenBufferInfo.srWindow.Left + 1; // Columns
new_screen_buffer_size.Y = screenBufferInfo.srWindow.Bottom -
screenBufferInfo.srWindow.Top + 1; // Rows
// Set new buffer size
SetConsoleScreenBufferSize(hConsole, new_screen_buffer_size);
std::cout << "There are no scrollbars in this console!" << std::endl;
return 0;
}