CORE_PUBLIC_DEFINE_CPU ig_window_create (cpu winid, cpu options, cpu x, cpu y, cpu width, cpu height, cpu dispid) {
int error = 0;
int success = 0;
int fullscreen = 0;
int objects = igstate.object_after;
static cpu glew_initialized = 0;
ig_display* display = 0;
display = (ig_display*)igstate.object[dispid]; // get display structure
error = ig_window_new (winid, 0); // create and initialize new window structure
if (error < 0) { return (error); }
ig_window* window = 0;
window = (ig_window*)igstate.object[winid]; // get address of window structure
//
// establish display characteristics
//
int display_width = display->width;
int display_height = display->height;
Display* xdisplay = display->xdisplay;
Window xwindow = 0;
//
// NOTE: much of the following information was put into the IG display structure when the display was opened with XOpenDisplay() in ig_display_create(). In the long run we must work with the values from our display object so windows can be opened on other displays (on the same computer and across any network).
//
int xscreen = XDefaultScreen (xdisplay);
Window xroot = XRootWindow (xdisplay, xscreen);
Window xwindow_root_default = XDefaultRootWindow (xdisplay);
Screen* xscreen_default_of_display = XDefaultScreenOfDisplay (xdisplay);
Screen* xscreen_of_display = XScreenOfDisplay (xdisplay, xscreen);
GC xgraphics_context = XDefaultGC (xdisplay, xscreen);
Visual* xvisual_default = XDefaultVisual (xdisplay, xscreen);
int xdisplay_width = XDisplayWidth (xdisplay, xscreen);
int xdisplay_height = XDisplayHeight (xdisplay, xscreen);
Colormap xcolormap;
XVisualInfo* xvisualinfo = 0;
XSetWindowAttributes xsetwindowattributes;
GLXWindow glxwindow;
GLXContext glxcontext;
GLXFBConfig* glxfbconfig = 0;
//
// get system metrics --- size-in-pixels of window frame and title-bar
//
int cmo = 1; // number of display-monitors on this/local computer
int xfr = 4; // frame width in pixels = 4 usually (on both left and right edges)
int yfr = 4; // frame height in pixels = 4 usually (on both top and bottom edges)
int yca = 19; // guess this value until we capture information in window message handler
int xsc = display_width; // full screen width - possibly reduced to support start/other bars
int ysc = display_height; // full screen height - possibly reduced to support start/other bars
int xfs = display_width; // full screen width - not reduced by start-bar or other travesties
int yfs = display_height; // full screen height - not reduced by start-bar or other travesties
//
// find functions to return the following values --- generally "window manager hints" in XWindows
//
if (x < 0) { x = 0; } // fix invalid x coordinate
if (y < 0) { y = 0; } // fix invalid y coordinate
if (x > display_width) { x = display_width - 32; } // make window at least partially visible
if (y > display_height) { y = display_height - 32; } // make window at least partially visible
if (width <= 0) { options = options | IG_OPTION_WINDOW_FULLWIDTH; } // width <= 0 is "full-width"
if (height <= 0) { options = options | IG_OPTION_WINDOW_FULLHEIGHT; } // height <= 0 is "full-height"
if (options & IG_OPTION_WINDOW_FULLSCREEN) { fullscreen = IG_OPTION_WINDOW_FULLSCREEN; }
if ((options & IG_OPTION_WINDOW_FULLWIDTH) && (options & IG_OPTION_WINDOW_FULLHEIGHT)) { fullscreen = IG_OPTION_WINDOW_FULLSCREEN; }
//
// later need to support fullscreen window that HAS border, caption and minimize/maximize/close buttons
//
if (fullscreen) { // fullscreen window if window width and height == display width and height
x = 0; // origin is always at top-left corner of display
y = 0; // origin is always at top-left corner of display
xsc = 0; // ditto
ysc = 0; // ditto
xfr = 0; // ditto
yfr = 0; // ditto
yca = 0; // ditto
width = display_width; // width == display_width
height = display_height; // height == display_height
} else {
if (x < xfr) { x = xfr; } // window border at left (4-pixels usually)
if (y < (yfr + yca)) { y = (yfr + yca); } // window border and title-bar at top
if (display_width < (width - (xfr + xfr))) { width = display_width - (xfr + xfr); }
if (display_height < (height - (yca + yfr + yfr))) { height = display_height - (yca + yfr + yfr); }
}
if (width < 16) { width = 16; }
if (height < 16) { height = 16; }
//
// test basic GLX functions and get basic GLX information
//
int major = 0;
int minor = 0;
int errorbase = 0;
int eventbase = 0;
error = glXQueryVersion (xdisplay, &major, &minor);
error = glXQueryExtension (xdisplay, &errorbase, &eventbase);
const char* extensions = glXQueryExtensionsString (xdisplay, xscreen);
const char* clientvendor = glXGetClientString (xdisplay, GLX_VENDOR);
const char* clientversion = glXGetClientString (xdisplay, GLX_VERSION);
const char* clientextensions = glXGetClientString (xdisplay, GLX_EXTENSIONS);
const char* servervendor = glXQueryServerString (xdisplay, xscreen, GLX_VENDOR);
const char* serverversion = glXQueryServerString (xdisplay, xscreen, GLX_VERSION);
const char* serverextensions = glXQueryServerString (xdisplay, xscreen, GLX_EXTENSIONS);
printf ("GLX version ::: major.minor == %d.%d\n", major, minor);
printf ("GLX offsets ::: errorbase : eventbase == %d %d\n", errorbase, eventbase);
printf ("GLX extensions ::: <%s>\n", extensions);
printf ("GLX clientvendor ::: <%s>\n", clientvendor);
printf ("GLX clientversion ::: <%s>\n", clientversion);
printf ("GLX clientextensions ::: <%s>\n", clientextensions);
printf ("GLX servervendor ::: <%s>\n", servervendor);
printf ("GLX serverversion ::: <%s>\n", serverversion);
printf ("GLX serverextensions ::: <%s>\n", serverextensions);
//
// the following is an expanded version of glxfbconfigattributes002 below (for ease of reading)
//
GLint glxfbconfigattributes[] = {
GLX_BUFFER_SIZE, 32,
GLX_DOUBLEBUFFER, 1,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
GLX_DEPTH_SIZE, 24,
GLX_STENCIL_SIZE, 1,
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
GLX_CONFIG_CAVEAT, GLX_NONE,
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 2,
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
0, 0,
0, 0
};
//
// create integer array of GL/GLX framebuffer configuration attributes
//
int glxfbconfigelements = 0;
int glxfbconfigattributes000[] = { GLX_BUFFER_SIZE, 32, GLX_DOUBLEBUFFER, 1, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_ALPHA_SIZE, 8, GLX_DEPTH_SIZE, 24, GLX_STENCIL_SIZE, 1, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, GLX_CONFIG_CAVEAT, GLX_NONE, GLX_CONTEXT_MAJOR_VERSION_ARB, 4, GLX_CONTEXT_MINOR_VERSION_ARB, 1, GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, 0, 0, 0, 0 };
int glxfbconfigattributes001[] = { GLX_BUFFER_SIZE, 32, GLX_DOUBLEBUFFER, 1, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_ALPHA_SIZE, 8, GLX_DEPTH_SIZE, 24, GLX_STENCIL_SIZE, 1, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, GLX_CONFIG_CAVEAT, GLX_NONE, GLX_CONTEXT_MAJOR_VERSION_ARB, 4, GLX_CONTEXT_MINOR_VERSION_ARB, 0, GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, 0, 0, 0, 0 };
int glxfbconfigattributes002[] = { GLX_BUFFER_SIZE, 32, GLX_DOUBLEBUFFER, 1, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_ALPHA_SIZE, 8, GLX_DEPTH_SIZE, 24, GLX_STENCIL_SIZE, 1, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, GLX_CONFIG_CAVEAT, GLX_NONE, GLX_CONTEXT_MAJOR_VERSION_ARB, 3, GLX_CONTEXT_MINOR_VERSION_ARB, 3, GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, 0, 0, 0, 0 };
int glxfbconfigattributes003[] = { GLX_BUFFER_SIZE, 32, GLX_DOUBLEBUFFER, 1, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_ALPHA_SIZE, 8, GLX_DEPTH_SIZE, 24, GLX_STENCIL_SIZE, 1, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, GLX_CONFIG_CAVEAT, GLX_NONE, GLX_CONTEXT_MAJOR_VERSION_ARB, 3, GLX_CONTEXT_MINOR_VERSION_ARB, 2, GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, 0, 0, 0, 0 };
int glxfbconfigattributes004[] = { GLX_BUFFER_SIZE, 32, GLX_DOUBLEBUFFER, 1, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_ALPHA_SIZE, 8, GLX_DEPTH_SIZE, 24, GLX_STENCIL_SIZE, 1, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, GLX_CONFIG_CAVEAT, GLX_NONE, GLX_CONTEXT_MAJOR_VERSION_ARB, 3, GLX_CONTEXT_MINOR_VERSION_ARB, 2, 0, 0, 0, 0 };
int glxfbconfigattributes005[] = { GLX_BUFFER_SIZE, 32, GLX_DOUBLEBUFFER, 1, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_ALPHA_SIZE, 8, GLX_DEPTH_SIZE, 24, GLX_STENCIL_SIZE, 1, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, GLX_CONFIG_CAVEAT, GLX_NONE, 0, 0, 0, 0 };
int glxfbconfigattributes006[] = { GLX_BUFFER_SIZE, 32, GLX_DOUBLEBUFFER, 1, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_ALPHA_SIZE, 8, GLX_DEPTH_SIZE, 24, GLX_STENCIL_SIZE, 1, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, 0, 0, 0, 0 };
int glxfbconfigattributes007[] = { GLX_BUFFER_SIZE, 32, GLX_DOUBLEBUFFER, 1, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_ALPHA_SIZE, 8, GLX_DEPTH_SIZE, 32, GLX_STENCIL_SIZE, 1, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, 0, 0, 0, 0 };
int glxfbconfigattributes008[] = { 0, 0, 0, 0 };
//
// choose framebuffer configuration closest to desired (in order specified above)
//
// glxfbconfig = glXChooseFBConfig (xdisplay, xscreen, 0, &glxfbconfigelements);
glxfbconfig = glXChooseFBConfig (xdisplay, xscreen, (int*)glxfbconfigattributes000, &glxfbconfigelements);
if ((glxfbconfig == 0) || (glxfbconfigelements < 1)) {
printf ("glXChooseFBConfig() : error : glxfbconfigattributes000 failed - trying less restrictive...\n");
glxfbconfig = glXChooseFBConfig (xdisplay, xscreen, (int*)glxfbconfigattributes001, &glxfbconfigelements);
if ((glxfbconfig == 0) || (glxfbconfigelements < 1)) {
printf ("glXChooseFBConfig() : error : glxfbconfigattributes001 failed - trying less restrictive...\n");
glxfbconfig = glXChooseFBConfig (xdisplay, xscreen, (int*)glxfbconfigattributes002, &glxfbconfigelements);
if ((glxfbconfig == 0) || (glxfbconfigelements < 1)) {
printf ("glXChooseFBConfig() : error : glxfbconfigattributes002 failed - trying less restrictive...\n");
glxfbconfig = glXChooseFBConfig (xdisplay, xscreen, (int*)glxfbconfigattributes003, &glxfbconfigelements);
if ((glxfbconfig == 0) || (glxfbconfigelements < 1)) {
printf ("glXChooseFBConfig() : error : glxfbconfigattributes003 failed - trying less restrictive...\n");
glxfbconfig = glXChooseFBConfig (xdisplay, xscreen, (int*)glxfbconfigattributes004, &glxfbconfigelements);
if ((glxfbconfig == 0) || (glxfbconfigelements < 1)) {
printf ("glXChooseFBConfig() : error : glxfbconfigattributes004 failed - trying less restrictive...\n");
glxfbconfig = glXChooseFBConfig (xdisplay, xscreen, (int*)glxfbconfigattributes005, &glxfbconfigelements);
if ((glxfbconfig == 0) || (glxfbconfigelements < 1)) {
printf ("glXChooseFBConfig() : error : glxfbconfigattributes005 failed - nothing less restrictive - permanent failure - terminate process\n");
return (CORE_ERROR_INTERNAL);
}
}
}
}
}
}
xvisualinfo = glXGetVisualFromFBConfig (xdisplay, glxfbconfig[0]);
if (xvisualinfo == 0) { printf ("glXGetVisualFromFBConfig() : error : xvisualinfo == 0 : terminate process\n"); return (CORE_ERROR_INTERNAL); }
glxcontext = glXCreateNewContext (xdisplay, glxfbconfig[0], GLX_RGBA_TYPE, 0, GL_TRUE);
if (glxcontext == 0) { printf ("glXCreateNewContext() : error : glxcontext == 0 : terminate process\n"); return (CORE_ERROR_INTERNAL); }
xcolormap = XCreateColormap (xdisplay, xroot, xvisualinfo->visual, AllocNone);
if (xcolormap == 0) { printf ("XCreateColormap() : error : xcolormap == 0 : terminate process\n"); return (CORE_ERROR_INTERNAL); }
//
// define XCreateWindow() arguments
//
int xeventmask = 0;
xeventmask = xeventmask | KeyPressMask; // bit 0
xeventmask = xeventmask | KeyReleaseMask; // bit 1
xeventmask = xeventmask | ButtonPressMask; // bit 2
xeventmask = xeventmask | ButtonReleaseMask; // bit 3
xeventmask = xeventmask | EnterWindowMask; // bit 4
xeventmask = xeventmask | LeaveWindowMask; // bit 5
xeventmask = xeventmask | PointerMotionMask; // bit 6
xeventmask = xeventmask | PointerMotionHintMask; // bit 7
xeventmask = xeventmask | Button1MotionMask; // bit 8
xeventmask = xeventmask | Button2MotionMask; // bit 9
xeventmask = xeventmask | Button3MotionMask; // bit 10
xeventmask = xeventmask | Button4MotionMask; // bit 11
xeventmask = xeventmask | Button5MotionMask; // bit 12
xeventmask = xeventmask | ButtonMotionMask; // bit 13
xeventmask = xeventmask | KeymapStateMask; // bit 14
xeventmask = xeventmask | ExposureMask; // bit 15
xeventmask = xeventmask | VisibilityChangeMask; // bit 16
xeventmask = xeventmask | StructureNotifyMask; // bit 17
//xeventmask = xeventmask | ResizeRedirectMask; // bit 18 DANGER ::: DO NOT ENABLE
xeventmask = xeventmask | SubstructureNotifyMask; // bit 19
xeventmask = xeventmask | SubstructureRedirectMask; // bit 20
xeventmask = xeventmask | FocusChangeMask; // bit 21
xeventmask = xeventmask | PropertyChangeMask; // bit 22
xeventmask = xeventmask | ColormapChangeMask; // bit 23
xeventmask = xeventmask | OwnerGrabButtonMask; // bit 24
xsetwindowattributes.colormap = xcolormap; // vanilla RGBA
xsetwindowattributes.background_pixel = None; // prevent background clear (let OpenGL glClear())
xsetwindowattributes.background_pixmap = None; // default = None
xsetwindowattributes.border_pixmap = None; // default = CopyFromParent
xsetwindowattributes.border_pixel = None; // default = Undefined
xsetwindowattributes.cursor = None; // default = None
xsetwindowattributes.event_mask = xeventmask; // 0x0001FFFF if events of all types are enabled
xsetwindowattributes.bit_gravity = StaticGravity;
int xselectattributes = (CWBackPixel | CWBorderPixel | CWBitGravity | CWColormap | CWEventMask);
xwindow = XCreateWindow (xdisplay, xroot, x, y, width, height, 0, xvisualinfo->depth, InputOutput, xvisualinfo->visual, xselectattributes, &xsetwindowattributes);
if (xwindow == 0) { printf ("error ::: XCreateWindow()\n"); return (-1); }
error = XSetStandardProperties (xdisplay, xwindow, "IG", "window.bmp", 0, 0, 0, 0);
if (error == 0) { printf ("error ::: XSetStandardProperties()\n"); }
char* STRING_WM_DELETE_WINDOW = (char*) "WM_DELETE_WINDOW";
Atom XA_WM_DELETE_WINDOW = XInternAtom (xdisplay, STRING_WM_DELETE_WINDOW, 0);
error = XSetWMProtocols (xdisplay, xwindow, &XA_WM_DELETE_WINDOW, 1);
igstate.message_close_window = XA_WM_DELETE_WINDOW;
//
// ####################### in theory the glXMakeContextCurrent() should not be here, but........
// ##### IMPORTANT ##### simple tests indicate this glXMakeContextCurrent() must be here
// ####################### because putting this in CreateNotify causes segment violation
//
glxwindow = glXCreateWindow (xdisplay, glxfbconfig[0], xwindow, 0);
error = glXMakeContextCurrent (xdisplay, glxwindow, glxwindow, glxcontext);
//
// do not automatically map/show/display windows --- we have a function for that == ig_window_display()
//
// error = XMapWindow (xdisplay, xwindow);
//
// populate window structure
//
window->displayid = dispid;
window->xdisplay = xdisplay;
window->xwindow = xwindow;
window->glxwindow = glxwindow;
window->glxcontext = glxcontext;
window->glxfbconfig = glxfbconfig[0];
window->style = 0;
window->type = options;
if (fullscreen) {
window->x = 0;
window->y = 0;
window->xdisp = x;
window->ydisp = y;
window->width = width;
window->height = height;
window->xframe = x;
window->yframe = y;
window->wframe = width;
window->hframe = height;
window->lborder = 0;
window->tborder = 0;
window->rborder = 0;
window->bborder = 0;
window->cborder = 0;
window->resized = 1;
} else {
window->x = 0;
window->y = 0;
window->xdisp = x;
window->ydisp = y;
window->width = width;
window->height = height;
window->xframe = x - xfr;
window->yframe = y - yfr - yca;
window->wframe = width + xfr + xfr;
window->hframe = height + yfr + yfr + yca;
window->lborder = xfr;
window->tborder = yfr;
window->rborder = xfr;
window->bborder = yfr;
window->cborder = yca;
window->resized = 1;
}
//
//
// ###############################################################################
// ##### XWindows does NOT generate an event when a new window is created! #####
// ##### But work must be done when windows are created, so generate event #####
// ###############################################################################
//
XCreateWindowEvent xmessage;
xmessage.type = CreateNotify;
xmessage.display = xdisplay;
xmessage.window = xwindow;
xmessage.parent = xroot;
xmessage.send_event = 0;
xmessage.serial = 0;
xmessage.x = x;
xmessage.y = y;
xmessage.width = width;
xmessage.height = height;
xmessage.border_width = xfr;
xmessage.override_redirect = 0;
error = XSendEvent (xdisplay, xwindow, 0, StructureNotifyMask, (XEvent*)&xmessage);
//
// free all resources we're supposed to free according to xlib and GLX function documentation
//
XFree (glxfbconfig);
XFree (xvisualinfo);
return (winid); // return window id #
}