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
Related
I am creating an X11 window, which is then resized programmatically with XWindowResize:
#include <X11/Xlib.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <cassert>
#include <cstdio>
int main()
{
Display* display = XOpenDisplay(nullptr);
assert(display);
Window root = DefaultRootWindow(display);
assert(root);
GLint att[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None };
XVisualInfo* vi = glXChooseVisual(display, 0, att);
assert(vi);
XSetWindowAttributes swa;
swa.colormap = XCreateColormap(display, root, vi->visual, AllocNone);
swa.event_mask = ExposureMask | KeyPressMask;
// create window with initial size 800 x 600
Window window = XCreateWindow(display, root, 0, 0, 800, 600, 0, vi->depth, InputOutput, vi->visual, CWColormap | CWEventMask, &swa);
XSelectInput(display, window, StructureNotifyMask | ResizeRedirectMask);
XMapWindow(display, window);
XFlush(display);
// resize window to new size 400 x 300
int result = XResizeWindow(display, window, 400, 300);
printf("XResizeWindow return value: %d\n", result);
if (result == BadValue) printf(" bad value!!!\n");
if (result == BadWindow) printf(" bad window!!!\n");
XEvent event;
XAnyEvent& ev = (XAnyEvent&)event;
while (true)
{
XNextEvent(display, &event);
if (ev.type == ResizeRequest)
{
XResizeRequestEvent& ev = (XResizeRequestEvent&)event;
printf("request to resize to %d x %d\n", ev.width, ev.height);
}
XWindowAttributes xwa;
XGetWindowAttributes(display, window, &xwa);
printf("position: %d, %d size: %d x %d\n", xwa.x, xwa.y, xwa.width, xwa.height);
}
}
This is not working as expected. The window decoration drawn by the window manager indicates that it is indeed resized to 400x300 pixels, however, XGetWindowAttributes reports the contrary (output below). Changing position and size manually with the mouse has the same effect: the resize request reports the correct size, but it is not reflected in the output of XGetWindowAttributes. The problem is that this affects the area in which mouse events are detected as well as OpenGL drawing (removed in order to have a minimal example).
XResizeWindow return value: 1
position: 1, 30 size: 800 x 600
position: 1, 30 size: 800 x 600
request to resize to 400 x 300
position: 1, 30 size: 800 x 600
position: 1, 30 size: 800 x 600
position: 1, 30 size: 800 x 600
Apparently I am doing it wrong. I'd appreciate any help on how to make this work. Do I have to do anything in order to honor the resize request? I have searched the web and stackoverflow for hours now without luck.
EDIT: It would already be helpful if someone could tell me whether the XResizeWindow return value of 1 indicates an error or not. I am unable to find documentation on the return value in case there is no error. Also, links to documentation containing this information are more than welcome!
Don't request ResizeRedirectMask. It is supposed to be requested by one client at a time, which is normally your window manager. Except WMs usually request SubstructureNotifyMaks on the root, which takes precedence over ResizeRedirectMask on the children, so that the latter is quite useless. I couldn't find one single example of a program, WM or otherwise, that uses ResizeRedirectMask.
If you do request ResizeRedirectMask, your window attributes may be stuck with a wrong size.
If you need to catch actual size changes, request StructureNotifyMask and process ConfigureNotify events.
#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 am having some issues with GLFW's window creation. I am wanting to have a program capable of toggling between windowed and fullscreen mode. To do this in GLFW 2.7.8 one must first destroy the active window, then create a new one. I read that version 3.0 has support for multiple windows, but it is still in development.
I have provided my own function to handle keyboard input. Using the initial 400 by 400 window, the program functions as expected; it will enter fullscreen on f or F, will exit when the escape key is pressed, and will complain when anything else is pressed.
However, when fullscreen mode is entered, the window becomes unresponsive with regards to my provided keyboard function. It will continue to run through the loop in main() and will respond to something like the glfwGetKey(GLFW_KEY_ESC) test. Regardless of if I have the mouse cursor enabled or not, the cursor does not appear.
Again, the fullscreen window is created and the KeyboardCallback function returns back into the main loop. I wish to understand why the fullscreen window is not working with my keyboard function, and why it is not displaying properly.
I am not drawing anything to the window, as I am trying to get some experience with various window abstraction libraries specifically. Drawing a simple triangle did nothing to solve he problem, and the fullscreen window remains black.
My code is as follows:
#include <stdio.h>
#include <stdlib.h>
// glfw32 - 2.7.8
#include <GL\glfw.h>
#pragma comment (lib, "GLFW.lib")
#pragma comment (lib, "opengl32.lib")
using namespace std;
// constants and globals
const int WINDOW_WIDTH=400, WINDOW_HEIGHT=400;
static bool fullscreen=false;
// function declarations
void GLFWCALL KeyboardCallback(int key, int action);
void FatalError(const char* msg) {
fprintf(stderr, "ERROR: Failure in \"%s\"\n", msg);
exit(1);
}
int main() {
// ititialize GLFW
glfwInit();
glfwEnable(GLFW_MOUSE_CURSOR);
glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 3);
glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 3);
// initial window, 400x400 with 32-bit depth buffer in windowed mode
glfwOpenWindow(WINDOW_WIDTH, WINDOW_HEIGHT, 0,0,0,0, 32, 0, GLFW_WINDOW);
glfwSetWindowTitle("Simple Title");
glfwSetWindowPos(0, 0);
// set custom keyboard callback
glfwSetKeyCallback(KeyboardCallback);
while (true) { // loop until exit
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers();
// debug
//printf("Looping...\n");
if ( glfwGetKey(GLFW_KEY_ESC) ) {break;}
}
glfwTerminate();
printf("\nHave a nice day\n");
return 0;
}
void GLFWCALL KeyboardCallback(int key, int action) {
//printf("In keyboard function\n");
if (action) { // if key DOWN,
switch(key) { // do something...
case 'f':
case 'F': {
fullscreen = !fullscreen;
printf("Toggle Fullscreen: %s\n", (fullscreen ? "On" : "Off"));
glfwCloseWindow();
if (! glfwOpenWindow(WINDOW_WIDTH, WINDOW_HEIGHT, 0,0,0,0, 32, 0,
fullscreen ? GLFW_FULLSCREEN : GLFW_WINDOW)) {
FatalError("toggle fullscreen");
}
glfwSetWindowTitle("New Title");
break;
}
case GLFW_KEY_ESC: {
printf("\nGoodbye cruel world...\n");
glfwTerminate();
exit(0);
}
default: {
printf("Key not implemented: %c\n", key);
break;
}
}
}
printf("Exiting keyboard function\n");
}
I tried James' approach from here but to no effect. Are there GLFW flags I am forgetting to set?
EDIT------- 5/20
I had a thought. Perhaps my callback was being unregistered when the window is destroyed. Turns out that re-registering my function when the new window is created made the window responsive.
While this solves my original problem, I now face a new one. I cannot render to the new window properly. I can insert glClear( GL_COLOR_BUFFER_BIT ); into my main loop, which will successfully set a background colour for the new window. For some reason it does not interact with my arrays and buffers to draw the image.
Code with attempted drawing
EDIT------- 5/21
I converted my code to GLFW 3.0.0. The window management is much cleaner (albeit more complex) and I do not have the rendering issue. Probably because I explicitly have to state the current context to use.
I would still like to solve the rendering issue, both out of curiosity and for if/when I return to 2.7.
Right now the event queue of GLFW is not pumped. You must either set the GLFW_AUTO_POLL_EVENTS option so that glfwSwapBuffers pumps the event queue, or you call glfwPollEvents at the start of a main event loop iteration.
I am in a class in which we will be learning OpenGL. The professor is using Visual Studio, but that isn't working too well with my install of Parallels, so I just decided to use XCode (which I prefer anyway). I have got basic example code working, but I am having issues running the example that the professor gave us. Here it is:
#include <glut.h> //must be included for OpenGL
#include <gl\gl.h> //must be included for OpenGL
#include <time.h> //must be included for time functions
#include <iostream> //must be included for console input/output
using namespace std;
#define WINDOW_WID 800
#define WINDOW_HEI 600
int randomPx, randomPy;
/////////////////////////////////////////
void myInit(void)
{
randomPx = 400;
randomPy = 300;
glClearColor (1.0, 1.0, 1.0, 0.0); // set background color to black
glShadeModel (GL_FLAT);
}
void myDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT); // clear the screen
glColor3f(1,0,0); //set the drawing color
glPointSize(10); //set the point size
glBegin(GL_POINTS);
glVertex2d(randomPx,randomPy); //Set the position of the vertex
glEnd();
glutSwapBuffers (); //put everything on your screen
}
void myReshape ( int w, int h)
{
glViewport (0, 0, w, h);
glMatrixMode (GL_PROJECTION); // set "camera type"
glLoadIdentity (); // clear the matrix
glOrtho(0.0, w, 0.0, h, -1.0, 1.0); // viewing transformation
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
}
void Animation()
{
srand(time(NULL)+rand()); //set the seed for your rand function
randomPx = rand()%WINDOW_WID;
randomPy = rand()%WINDOW_HEI;
Sleep(200); //put the program to sleep for 200 ms
myDisplay();
}
void myMouse(int button, int state, int x, int y)
{
y = WINDOW_HEI - y;
switch (button)
{
case GLUT_LEFT_BUTTON: //when left mouse button is clicked
if (state == GLUT_DOWN)
{
cout << "When mouse is up, animation starts\n";
}
else if(state == GLUT_UP)
{
glutIdleFunc(Animation); //do Animation when idle
}
break;
case GLUT_RIGHT_BUTTON: //when right mouse button is clicked
if (state == GLUT_DOWN)
{
glutIdleFunc(NULL); //do nothing when idle
}
break;
case GLUT_MIDDLE_BUTTON:
if (state == GLUT_DOWN)
{
exit (-1); //exit your program
}
break;
}
myDisplay();
}
void myMotion(int x, int y)
{
y = WINDOW_HEI - y;
myDisplay();
}
void myKeyboard(unsigned char key, int x, int y)
{
//TODO
myDisplay();
}
/*
* Request double buffer display mode.
* Register mouse input callback functions
*/
int main(int argc, char** argv)
{
glutInit(&argc, argv); // initialize the toolkit
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB); // set display mode
// glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); // set display mode
glutInitWindowSize (WINDOW_WID, WINDOW_HEI); // set screen window size
glutInitWindowPosition (100, 100); // set window position on screen
glutCreateWindow (argv[0]); // open the screen window
myInit ();
glutDisplayFunc(myDisplay); // register redraw function
glutReshapeFunc(myReshape); // register reshape function
glutMouseFunc(myMouse); //GLUT provides a way for you to register the function that will be responsable for processing events generated by mouse clicks.
glutMotionFunc(myMotion); //There are two types of motion that GLUT handles: active and passive motion. Active motion occurs when the mouse is moved and a button is pressed.
glutKeyboardFunc(myKeyboard);
//glutPassiveMotionFunc(myPassiveMotion); //Passive motion is when the mouse is moving but no buttons are pressed. If an application is tracking motion, an event will be generated per frame during the period that the mouse is moving.
//glutEntryFunc(processMouseEntry); //GLUT is also able to detect when the mouse leaves or enters the window region. A callback function can be registered to handle these two events.
glutMainLoop(); // go into a perpetual loop
return 0;
}
I took out the imports statements, and replaced them with the imports for example XCode OpenGL code:
#include <iostream>
#include <GLUT/glut.h>
#include <time.h>
And I don't get any error messages, but when I run the application, and click on the window, it does not start the animation it is supposed to. (I know it works, because in Visual Studio on every other computer in the class it worked fine.)
It does register the click on the screen by printing out: "When mouse is up, animation starts"
But after that, it just gives me the Spinning Beachball of Death until I stop it from running via XCode. So is there something else I have to adjust to get this working?
First of all, why are you using a backslash for your import gl.h? Secondly, you should link your code to the GLUT and OpenGL library, so you should include/import them as OpenGL/gl.h and GLUT/glut.h. But your main problem here is the sleep function. It doesn't exist on macs and thus, your code crashes when it tries to animate. Use [NSThread sleepForTimeInterval:0.2] instead if you want to wait for 200 ms. But you will have to change your file extension to .mm in order to use objective-c code and also import the Foundation library to use the NSThread class.
About the sleep.. use
#include <unistd.h> //FROM C
and use
sleep(0.2)
wich is at seconds.. so 2000 miliseconds = 0.2 seconds.. so
just switch from sleep(2000) to sleep(0.2)
I wish to have a semi-transparent SDL background (nothing to do with sub-surfaces or images), such that instead of having a black background it is actually transparent, but the other things I draw are not. My current code is a slightly modified copy of Code::Blocks' SDL project, similar to how various applications have rounded borders or odd shapes besides rectangles.
#ifdef __cplusplus
#include <cstdlib>
#else
#include <stdlib.h>
#endif
#ifdef __APPLE__
#include <SDL/SDL.h>
#else
#include <SDL.h>
#endif
int main ( int argc, char** argv )
{
putenv("SDL_VIDEO_WINDOW_POS");
putenv("SDL_VIDEO_CENTERED=1");
// initialize SDL video
if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
{
printf( "Unable to init SDL: %s\n", SDL_GetError() );
return 1;
}
// make sure SDL cleans up before exit
atexit(SDL_Quit);
// create a new window
SDL_Surface* screen = SDL_SetVideoMode(640, 480, 16,
SDL_HWSURFACE|SDL_DOUBLEBUF|SDL_NOFRAME);
if ( !screen )
{
printf("Unable to set 640x480 video: %s\n", SDL_GetError());
return 1;
}
// load an image
SDL_Surface* bmp = SDL_LoadBMP("cb.bmp");
if (!bmp)
{
printf("Unable to load bitmap: %s\n", SDL_GetError());
return 1;
}
// centre the bitmap on screen
SDL_Rect dstrect;
dstrect.x = (screen->w - bmp->w) / 2;
dstrect.y = (screen->h - bmp->h) / 2;
// program main loop
bool done = false;
while (!done)
{
// message processing loop
SDL_Event event;
while (SDL_PollEvent(&event))
{
// check for messages
switch (event.type)
{
// exit if the window is closed
case SDL_QUIT:
done = true;
break;
// check for keypresses
case SDL_KEYDOWN:
{
// exit if ESCAPE is pressed
if (event.key.keysym.sym == SDLK_ESCAPE)
done = true;
break;
}
} // end switch
} // end of message processing
// DRAWING STARTS HERE
// clear screen
SDL_FillRect(screen, 0, SDL_MapRGB(screen->format, 0, 0, 0));
// draw bitmap
SDL_BlitSurface(bmp, 0, screen, &dstrect);
// DRAWING ENDS HERE
// finally, update the screen :)
SDL_Flip(screen);
} // end main loop
// free loaded bitmap
SDL_FreeSurface(bmp);
// all is well ;)
printf("Exited cleanly\n");
return 0;
}
I think what you're trying to do is in fact a shaped window (parts of the window are transparent depending on a mask that you provide). It seems there's no way to do that with SDL 1.2, however there is a SDL_SetWindowShape function just for this in SDL 1.3 for which you can find a pre-release snapshot here but it's not even in beta yet so I suggest waiting until it's officialy released :)
this is a link to a pretty neat article about development of an older application for Mac OS 9, which did not have support for shaped windows, either.
It's actually a neat article in general about software development.
But the idea seems pretty smart, and I wonder if you might be able to get it working here, too. Instead of trying to make a transparent background, they actually take a screen-shot of the computer right where their window is going to go, and then use that screen shot for their background. When the user drags the window around on the screen, they continue to update the background with new screen-shots. I think this might be more complicated than you were hoping for, but it's certainly an interesting idea.