From cd7b2b1a69145aaf94de406c757306d56b7f40a7 Mon Sep 17 00:00:00 2001 From: Samuel Gomes Date: Mon, 29 Jan 2024 22:22:21 +0530 Subject: [PATCH] Changes to resolve merge conflicts --- internal/c/common.h | 4 +- internal/c/libqb.cpp | 84 +- internal/c/parts/core/log.txt | 66 + internal/c/parts/core/src/freeglut_main.c | 2928 +++++++++++++++++++ internal/c/parts/core/src/freeglut_window.c | 2284 +++++++++++++++ 5 files changed, 5322 insertions(+), 44 deletions(-) create mode 100644 internal/c/parts/core/log.txt create mode 100644 internal/c/parts/core/src/freeglut_main.c create mode 100644 internal/c/parts/core/src/freeglut_window.c diff --git a/internal/c/common.h b/internal/c/common.h index 9300c2510..1343756c2 100644 --- a/internal/c/common.h +++ b/internal/c/common.h @@ -246,7 +246,7 @@ struct img_struct { uint8 print_mode; // BEGIN apm ('active page migration') // everything between apm points is migrated during active page changes - // note: apm data is only relevent to graphics modes + // note: apm data is only relevant to graphics modes uint8 apm_p1; int32 view_x1, view_y1, view_x2, view_y2; int32 view_offset_x, view_offset_y; @@ -316,7 +316,7 @@ struct device_struct { int32 type; // 0=Unallocated // 1=Joystick/Gamepad - // 2=Keybaord + // 2=Keyboard // 3=Mouse char *name; int32 connected; diff --git a/internal/c/libqb.cpp b/internal/c/libqb.cpp index 12028aba2..def81dc07 100644 --- a/internal/c/libqb.cpp +++ b/internal/c/libqb.cpp @@ -162,7 +162,7 @@ int32 environment_2d__screen_x1 = 0; // offsets of 'screen' within the window int32 environment_2d__screen_y1 = 0; int32 environment_2d__screen_x2 = 0; int32 environment_2d__screen_y2 = 0; -int32 environment_2d__screen_scaled_width = 640; // inital values prevent _SCALEDWIDTH/_SCALEDHEIGHT returning 0 +int32 environment_2d__screen_scaled_width = 640; // initial values prevent _SCALEDWIDTH/_SCALEDHEIGHT returning 0 int32 environment_2d__screen_scaled_height = 400; float environment_2d__screen_x_scale = 1.0f; float environment_2d__screen_y_scale = 1.0f; @@ -2174,7 +2174,7 @@ int32 lprint_locked = 0; // set to 1 to deny access by QB64 program multiplatform compatibility. 'Pure' C-based routines may not allow certain functionality, such as partial file locking. GFS handles/indexes are independent of QB64 handles/indexes to allow for internal files - to be open but not intefere with the QB64 file handle numbers. + to be open but not interfere with the QB64 file handle numbers. GFS error codes: -1 non-specific fail @@ -4150,13 +4150,13 @@ void pset(int32 x, int32 y, uint32 col) { case 0x0: // 0%(0) alpha, so no pset (very fast) return; break; - case 0x80000000: //~50% alpha (optomized) + case 0x80000000: //~50% alpha (optimized) o32 = write_page->offset32 + (y * write_page->width + x); *o32 = (((*o32 & 0xFEFEFE) + (col & 0xFEFEFE)) >> 1) + (ablend128[*o32 >> 24] << 24); return; break; - case 0x7F000000: //~50% alpha (optomized) + case 0x7F000000: //~50% alpha (optimized) o32 = write_page->offset32 + (y * write_page->width + x); *o32 = (((*o32 & 0xFEFEFE) + (col & 0xFEFEFE)) >> 1) + (ablend127[*o32 >> 24] << 24); return; @@ -4524,7 +4524,7 @@ int32 imgnew(int32 x, int32 y, int32 bpp) { return i; } -void sub__font(int32 f, int32 i, int32 passed); // foward def +void sub__font(int32 f, int32 i, int32 passed); // forward def void flush_old_hardware_commands() { static int32 old_command; @@ -5232,7 +5232,7 @@ stretch: return; if (dy1 > dy2) return; - // all values are now within the boundries of the source & dest + // all values are now within the boundaries of the source & dest stretch_noreverse_noclip: w = dx2 - dx1 + 1; @@ -5625,7 +5625,7 @@ clip: return; if (dy1 > dy2) return; - // all values are now within the boundries of the source & dest + // all values are now within the boundaries of the source & dest // mirror put if (mirror) { @@ -7167,7 +7167,7 @@ int32 asciicode_reading = 0; int32 lock_display = 0; int32 lock_display_required = 0; -// cost delay, made obselete by managing thread priorities (consider removal) +// cost delay, made obsolete by managing thread priorities (consider removal) #define cost_limit 10000 #define cost_delay 0 uint32 cost = 0; @@ -7190,7 +7190,7 @@ uint64 build_uint64(uint32 val2, uint32 val1) { return val; } -// nb. abreviations are used in variable names to save typing, here are some of the expansions +// nb. abbreviations are used in variable names to save typing, here are some of the expansions // cmem=conventional memory // qbs=qbick basic string (refers to the emulation of quick basic strings) // sp=stack pointer @@ -7613,7 +7613,7 @@ extern uint8 *mem_static_limit; uint8 *mem_static_malloc(uint32 size) { size += 7; - size -= (size & 7); // align to 8 byte boundry + size -= (size & 7); // align to 8 byte boundary if ((mem_static_pointer += size) < mem_static_limit) return mem_static_pointer - size; mem_static_size = (mem_static_size << 1) + size; @@ -8204,7 +8204,7 @@ qbs *qbs_set(qbs *deststr, qbs *srcstr) { } // non-fixed deststr - // can srcstr be aquired by deststr? + // can srcstr be acquired by deststr? if (srcstr->tmp) { if (srcstr->fixed == 0) { if (srcstr->readonly == 0) { @@ -8279,7 +8279,7 @@ qbs *qbs_set(qbs *deststr, qbs *srcstr) { // all next indexes invalid! qbs_cmem_list_nexti = deststr->listi + 1; // adjust nexti if (((ptrszint)deststr->chr + srcstr->len) <= (dblock + cmem_sp)) { // space available - memmove(deststr->chr, srcstr->chr, srcstr->len); // overlap possible due to sometimes aquiring srcstr's space + memmove(deststr->chr, srcstr->chr, srcstr->len); // overlap possible due to sometimes acquiring srcstr's space deststr->len = srcstr->len; qbs_cmem_sp = ((ptrszint)deststr->chr) + (ptrszint)deststr->len - dblock; goto qbs_set_return; @@ -8336,7 +8336,7 @@ skippedtmpsrcindex2: qbs_list_nexti = deststr->listi + 1; // adjust nexti if (((ptrszint)deststr->chr + srcstr->len) <= ((ptrszint)qbs_data + qbs_data_size)) { // space available - memmove(deststr->chr, srcstr->chr, srcstr->len); // overlap possible due to sometimes aquiring srcstr's space + memmove(deststr->chr, srcstr->chr, srcstr->len); // overlap possible due to sometimes acquiring srcstr's space deststr->len = srcstr->len; qbs_sp = ((ptrszint)deststr->chr) + (ptrszint)deststr->len - (ptrszint)qbs_data; goto qbs_set_return; @@ -10962,7 +10962,7 @@ void qbsub_width(int32 option, int32 value1, int32 value2, int32 value3, int32 v if ((write_page->compatible_mode == 32) || (write_page->compatible_mode == 256)) { - if (!(passed & 1)) { // width ommited + if (!(passed & 1)) { // width omitted width = write_page->width; } else { if (width <= 0) @@ -10973,7 +10973,7 @@ void qbsub_width(int32 option, int32 value1, int32 value2, int32 value3, int32 v width *= i; } - if (!(passed & 2)) { // height ommited + if (!(passed & 2)) { // height omitted height = write_page->height; } else { if (height <= 0) @@ -11050,7 +11050,7 @@ void qbsub_width(int32 option, int32 value1, int32 value2, int32 value3, int32 v } // 32/256 - if (!(passed & 1)) { // width ommited + if (!(passed & 1)) { // width omitted if (height <= 0) goto error; @@ -11659,12 +11659,12 @@ void pset_and_clip(int32 x, int32 y, uint32 col) { case 0x0: // 0%(0) alpha, so no pset (very fast) return; break; - case 0x80000000: //~50% alpha (optomized) + case 0x80000000: //~50% alpha (optimized) o32 = write_page->offset32 + (y * write_page->width + x); *o32 = (((*o32 & 0xFEFEFE) + (col & 0xFEFEFE)) >> 1) + (ablend128[*o32 >> 24] << 24); return; break; - case 0x7F000000: //~50% alpha (optomized) + case 0x7F000000: //~50% alpha (optimized) o32 = write_page->offset32 + (y * write_page->width + x); *o32 = (((*o32 & 0xFEFEFE) + (col & 0xFEFEFE)) >> 1) + (ablend127[*o32 >> 24] << 24); return; @@ -11763,7 +11763,7 @@ void qb32_boxfill(float x1f, float y1f, float x2f, float y2f, uint32 col) { } // 1 // assume 32-bit - // optomized + // optimized // alpha disabled or full alpha? a = col >> 24; if ((write_page->alpha_disabled) || (a == 255)) { @@ -11860,7 +11860,7 @@ void fast_boxfill(int32 x1, int32 y1, int32 x2, int32 y2, uint32 col) { } // 1 // assume 32-bit - // optomized + // optimized // alpha disabled or full alpha? a = col >> 24; if ((write_page->alpha_disabled) || (a == 255)) { @@ -13191,7 +13191,7 @@ void sub_circle(double x, double y, double r, uint32 col, double start, double e write_page->x = x; write_page->y = y; // set graphics cursor position to circle's centre - r = x + r; // the differece between x & x+r in pixels will be the radius in pixels + r = x + r; // the difference between x & x+r in pixels will be the radius in pixels // resolve coordinates (but keep as floats) if (write_page->clipping_or_scaling) { if (write_page->clipping_or_scaling == 2) { @@ -14110,7 +14110,7 @@ void qbs_print(qbs *str, int32 finish_on_new_line) { if (character == 30) { // previous row, same column - // no change if cursor not within view print boundries + // no change if cursor not within view print boundaries if ((write_page->cursor_y > write_page->top_row) && (write_page->cursor_y <= write_page->bottom_row)) { write_page->cursor_y--; } @@ -14119,7 +14119,7 @@ void qbs_print(qbs *str, int32 finish_on_new_line) { if (character == 31) { // next row, same column - // no change if cursor not within view print boundries + // no change if cursor not within view print boundaries if ((write_page->cursor_y >= write_page->top_row) && (write_page->cursor_y < write_page->bottom_row)) { write_page->cursor_y++; } @@ -14589,7 +14589,7 @@ void qbg_sub_view(int32 x1, int32 y1, int32 x2, int32 y2, int32 fillcolor, int32 if (!write_page->clipping_or_scaling) write_page->clipping_or_scaling = 1; } else { - // no argurments passed + // no arguments passed write_page->view_x1 = 0; write_page->view_y1 = 0; write_page->view_x2 = write_page->width - 1; @@ -15261,8 +15261,8 @@ qbs_input_sep_arg_done: if (toomany) goto backspace; - // validate current arguements - // ASSUME LEADING & TRALING SPACES REMOVED! + // validate current arguments + // ASSUME LEADING & TRAILING SPACES REMOVED! uint8 valid; uint8 neg; int32 completewith; @@ -17215,7 +17215,7 @@ uint16 n_digits; uint8 n_digit[256]; int64 n_exp; // if 0, there is one digit in front of the decimal place uint8 n_neg; // if 1, the number is negative -uint8 n_hex; // if 1, the digits are in hexidecimal and n_exp should be ignored +uint8 n_hex; // if 1, the digits are in hexadecimal and n_exp should be ignored // if 2, the digits are in octal and n_exp should be ignored // if 3, the digits are in binary and n_exp should be ignored //(consider revising variable name n_hex) @@ -19166,7 +19166,7 @@ void sub_graphics_get(float x1f, float y1f, float x2f, float y2f, void *element, sx = read_page->width; sy = read_page->height; - // boundry checking (if no mask colour was passed) + // boundary checking (if no mask colour was passed) if (!(passed & 4)) { if ((x1 < 0) || (y1 < 0) || (x2 >= sx) || (y2 >= sy)) { error(5); @@ -19456,7 +19456,7 @@ void sub_graphics_put(float x1f, float y1f, void *element, int32 option, uint32 x2 = x1 + w - 1; y2 = y1 + h - 1; - // boundry checking (if CLIP option was not used) + // boundary checking (if CLIP option was not used) if (!clip) { if ((x1 < 0) || (y1 < 0) || (x2 >= sx) || (y2 >= sy)) { error(5); @@ -21051,7 +21051,7 @@ int32 func_eof(int32 i) { else if (sh->index == 2) return 0; - // Only report EOF() if the program had read all incomming data and + // Only report EOF() if the program had read all incoming data and // the connection is finished. if (libqb_http_connected(x)) return 0; @@ -23525,7 +23525,7 @@ void call_int(int32 i) { if (cpu.cx >= (display_page->width * 8)) cpu.cx = (display_page->width * 8) - 1; // note: a range from 0 to rows*8-1 is returned regardless of the number of actual pixels - // obselete line of code: + // obsolete line of code: // cpu.dx=(((float)cpu.dx)/((float)(display_page->height*fontheight[display_page->font])))*((float)(display_page->height*8));//(mouse_y/height_in_pixels)*(rows*8) cpu.dx = (my - 0.5) * 8.0; if (cpu.dx >= (display_page->height * 8)) @@ -24051,7 +24051,7 @@ void sub__setalpha(int32 a, uint32 c, uint32 c2, int32 i, int32 passed) { return; } -// Finding infomation about an image surface: +// Finding information about an image surface: int32 func__width(int32 i, int32 passed) { if (new_error) @@ -24687,7 +24687,7 @@ int32 func__printwidth(qbs *text, int32 screenhandle, int32 passed) { } auto fonthandle = img[screenhandle].font; // Get the font used in screenhandle - auto fwidth = func__fontwidth(fonthandle, 1); // Try and get the font width + auto fwidth = func__fontwidth(fonthandle, 1); // Try to get the font width if (fwidth) return fwidth * text->len; // if it's not a variable width font, return the width * the letter count @@ -25646,7 +25646,7 @@ numeric_spacer: return 0; } - // reduce digits before point appropriatly + // reduce digits before point appropriately extra_sign_space = 0; if (exponent_digits) { if ((leading_plus == 0) && (trailing_plus == 0) && (trailing_minus == 0)) { @@ -34062,7 +34062,7 @@ void prepare_environment_2d() { // called prior to rendering 2D content can_scale = 1; if (full_screen == 2) need_square_pixels = 1; - // note: 'letter-boxing' is only requred where the size of the window + // note: 'letter-boxing' is only required where the size of the window // cannot be controlled, and the only place where this is the // case is full screen mode _SQUAREPIXELS environment_2d__screen_smooth = fullscreen_smooth; @@ -35287,7 +35287,7 @@ void GLUT_DISPLAY_REQUEST() { glutEnterGameMode(); fullscreen_width=display_frame[i].w; fullscreen_height=display_frame[i].h; reinit_glut_callbacks(); - full_screen=full_screen_set;//it's currently irrelavent if it is + full_screen=full_screen_set;//it's currently irrelevant if it is stretched or 1:1 full_screen_set=-1; return; }else{ //native dimensions not possible //attempt full screen using desktop dimensions @@ -36618,7 +36618,7 @@ uint8 *pixeldata = (uint8 *)malloc(1); int32 pixeldatasize = 1; uint32 paldata[256]; -// note: temporarily swapping a source palette is far more effecient than converting the resulting image pixels +// note: temporarily swapping a source palette is far more efficient than converting the resulting image pixels void swap_paldata_BGRA_with_RGBA() { static uint32 col; static uint32 *pos; @@ -36721,7 +36721,7 @@ void display() { z = 0; //? conversion_required = 0; - pixel = display_surface_offset; //<-will be made obselete + pixel = display_surface_offset; //<-will be made obsolete if (!display_page->compatible_mode) { // text @@ -36763,7 +36763,7 @@ void display() { // Check/Prepare palette-buffer if (!check_last) { - // set pal_last (no prev pal was avilable to compare to) + // set pal_last (no prev pal was available to compare to) memcpy(&paldata, display_page->pal, 256 * 4); } else { // if palette has changed, update paldata and draw all characters @@ -38248,7 +38248,7 @@ void keydown(uint32 x) { if (b2 = scancode_lookup[x * 10 + 1]) { // table entry exists scancodedown(b2); - // check for relevent table modifiers + // check for relevant table modifiers shift = 0; if (keyheld(VK + QBVK_LSHIFT) || keyheld(VK + QBVK_RSHIFT)) shift = 1; @@ -38313,7 +38313,7 @@ void keydown(uint32 x) { r = (x >> 8) + 256; if (scancode_lookup[r * 10 + 2]) { scancodedown(scancode_lookup[r * 10 + 1]); - // check relevent modifiers + // check relevant modifiers shift = 0; if (keyheld(VK + QBVK_LSHIFT) || keyheld(VK + QBVK_RSHIFT)) shift = 1; @@ -38725,7 +38725,7 @@ void sub__consolefont(qbs *FontName, int FontSize) { SECURITY_ATTRIBUTES SecAttribs = {sizeof(SECURITY_ATTRIBUTES), 0, 1}; HANDLE cl_conout = CreateFileA("CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &SecAttribs, OPEN_EXISTING, 0, 0); static int OneTimePause; - if (!OneTimePause) { // a slight delay so the console can be properly created and registered with Windows, before we try and change fonts with it. + if (!OneTimePause) { // a slight delay so the console can be properly created and registered with Windows, before we try to change fonts with it. Sleep(500); OneTimePause = 1; // after the first pause, the console should be created, so we don't need any more delays in the future. } diff --git a/internal/c/parts/core/log.txt b/internal/c/parts/core/log.txt new file mode 100644 index 000000000..8b74a9228 --- /dev/null +++ b/internal/c/parts/core/log.txt @@ -0,0 +1,66 @@ +-downloaded: http://freeglut.sourceforge.net/index.php#download +-copied *.c in 'src' folder of download to src +-copied headers in 'include' folder of download to src +-created QB64 program to help locally build freeglut without makefiles + note: this program is for reference purposes only, do not run it unless you fully understand it + note: for rebuilding edits to the existing source, simple run the batch/script file provided + +########################### QB64 PROGRAM TO MANAGE FREEGLUT LIBRARY ###################################### +'FreeGLUT Source Manipulation +rel_c_path$ = "..\..\" +c_path$ = "c:\qb64_gl_core\internal\c\" '<<<<<<<<<< ********CHANGE ME********* +path$ = c_path$ + "parts\core\" +SHELL "dir /b /s " + path$ + "src\*.c >glutfiles.txt" +OPEN path$ + "rebuild_libfreeglut_a.bat" FOR OUTPUT AS #10 +OPEN path$ + "rebuild_libfreeglut_a_pause.bat" FOR OUTPUT AS #11 +OPEN "glutfiles.txt" FOR INPUT AS #1 +DO UNTIL EOF(1) + LINE INPUT #1, f$ + IF LEN(f$) THEN + OPEN f$ FOR BINARY AS #2 + a$ = SPACE$(LOF(2)) + GET #2, , a$ + CLOSE #2 + h$ = "#ifndef FREEGLUT_STATIC" + IF LEFT$(a$, LEN(h$)) <> h$ THEN + a$ = "#ifndef FREEGLUT_STATIC" + CHR$(13) + CHR$(10) + "#define FREEGLUT_STATIC" + CHR$(13) + CHR$(10) + "#endif" + CHR$(13) + CHR$(10) + a$ + END IF + DO + i = INSTR(a$, "#include ") + IF i THEN + MID$(a$, i) = "#include " + CHR$(34) + "freeglut.h" + CHR$(34) + END IF + i = INSTR(a$, "#include ") + IF i THEN + MID$(a$, i) = "#include " + CHR$(34) + "freeglut_std.h" + CHR$(34) + END IF + LOOP UNTIL i = 0 + OPEN f$ FOR OUTPUT AS #2: CLOSE #2: OPEN f$ FOR BINARY AS #2 + PUT #2, , a$ + CLOSE #2 + 'strip path from it \ + FOR x = LEN(f$) TO 1 STEP -1 + IF ASC(f$, x) = 92 THEN EXIT FOR + NEXT + f2$ = RIGHT$(f$, LEN(f$) - x) '.c + f3$ = LEFT$(f2$, LEN(f2$) - 2) 'without .c + PRINT #10, rel_c_path$ + "bin\gcc -s -O2 -c src\" + f2$ + " -o temp\" + f3$ + ".o" + PRINT #11, rel_c_path$ + "bin\gcc -s -O2 -c src\" + f2$ + " -o temp\" + f3$ + ".o" + PRINT #11, "pause" + o$ = o$ + " temp\" + f3$ + ".o" + END IF +LOOP +CLOSE #1 +PRINT #10, rel_c_path$ + "\bin\ar rcs libfreeglut_static.a " + o$ +PRINT #11, rel_c_path$ + "\bin\ar rcs libfreeglut_static.a " + o$ +PRINT #11, "********************* PROCESS COMPLETE **************************" +PRINT #11, "pause" +PRINT #11, "pause" +PRINT #11, "pause" +PRINT #11, "pause" +PRINT #11, "pause" +CLOSE \ No newline at end of file diff --git a/internal/c/parts/core/src/freeglut_main.c b/internal/c/parts/core/src/freeglut_main.c new file mode 100644 index 000000000..9ee928236 --- /dev/null +++ b/internal/c/parts/core/src/freeglut_main.c @@ -0,0 +1,2928 @@ +#ifndef FREEGLUT_STATIC + #define FREEGLUT_STATIC +#endif + +/* + * freeglut_main.c + * + * The windows message processing methods. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Fri Dec 3 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "freeglut.h" +#include "freeglut_internal.h" +#ifdef HAVE_ERRNO_H +# include +#endif +#include +#ifdef HAVE_VFPRINTF +# define VFPRINTF(s,f,a) vfprintf((s),(f),(a)) +#elif defined(HAVE__DOPRNT) +# define VFPRINTF(s,f,a) _doprnt((f),(a),(s)) +#else +# define VFPRINTF(s,f,a) +#endif + +int qb64_custom_event(int event,int v1,int v2,int v3,int v4,int v5,int v6,int v7,int v8,void *p1,void *p2); +#if TARGET_HOST_POSIX_X11 + void qb64_os_event_linux(XEvent *event, Display *display, int *qb64_os_event_info); +#else + LRESULT qb64_os_event_windows(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, int *qb64_os_event_info); +#endif + +#define QB64_EVENT_CLOSE 1 +#define QB64_EVENT_KEY 2 +#define QB64_EVENT_RELATIVE_MOUSE_MOVEMENT 3 +#define QB64_EVENT_FILE_DROP 4 + +#define QBK 200000 +#define VK 100000 +#define UC 1073741824 +/* QBK codes: +200000-200010: Numpad keys with Num-Lock off + NO_NUMLOCK_KP0=INSERT + NO_NUMLOCK_KP1=END + NO_NUMLOCK_KP2=DOWN + NO_NUMLOCK_KP3=PGDOWN + NO_NUMLOCK_KP4... + NO_NUMLOCK_KP5 + NO_NUMLOCK_KP6 + NO_NUMLOCK_KP7 + NO_NUMLOCK_KP8 + NO_NUMLOCK_KP9 + NO_NUMLOCK_KP_PERIOD=DEL +200011: SCROLL_LOCK_ON +200012: INSERT_MODE_ON +*/ +#define QBK_SCROLL_LOCK_MODE 11 +#define QBK_INSERT_MODE 12 +#define QBK_CHR0 13 +typedef enum { + QBVK_UNKNOWN = 0, + QBVK_FIRST = 0, + QBVK_BACKSPACE = 8, + QBVK_TAB = 9, + QBVK_CLEAR = 12, + QBVK_RETURN = 13, + QBVK_PAUSE = 19, + QBVK_ESCAPE = 27, + QBVK_SPACE = 32, + QBVK_EXCLAIM = 33, + QBVK_QUOTEDBL = 34, + QBVK_HASH = 35, + QBVK_DOLLAR = 36, + QBVK_AMPERSAND = 38, + QBVK_QUOTE = 39, + QBVK_LEFTPAREN = 40, + QBVK_RIGHTPAREN = 41, + QBVK_ASTERISK = 42, + QBVK_PLUS = 43, + QBVK_COMMA = 44, + QBVK_MINUS = 45, + QBVK_PERIOD = 46, + QBVK_SLASH = 47, + QBVK_0 = 48, + QBVK_1 = 49, + QBVK_2 = 50, + QBVK_3 = 51, + QBVK_4 = 52, + QBVK_5 = 53, + QBVK_6 = 54, + QBVK_7 = 55, + QBVK_8 = 56, + QBVK_9 = 57, + QBVK_COLON = 58, + QBVK_SEMICOLON = 59, + QBVK_LESS = 60, + QBVK_EQUALS = 61, + QBVK_GREATER = 62, + QBVK_QUESTION = 63, + QBVK_AT = 64, + //Skip uppercase letters + QBVK_LEFTBRACKET= 91, + QBVK_BACKSLASH = 92, + QBVK_RIGHTBRACKET = 93, + QBVK_CARET = 94, + QBVK_UNDERSCORE = 95, + QBVK_BACKQUOTE = 96, + QBVK_a = 97, + QBVK_b = 98, + QBVK_c = 99, + QBVK_d = 100, + QBVK_e = 101, + QBVK_f = 102, + QBVK_g = 103, + QBVK_h = 104, + QBVK_i = 105, + QBVK_j = 106, + QBVK_k = 107, + QBVK_l = 108, + QBVK_m = 109, + QBVK_n = 110, + QBVK_o = 111, + QBVK_p = 112, + QBVK_q = 113, + QBVK_r = 114, + QBVK_s = 115, + QBVK_t = 116, + QBVK_u = 117, + QBVK_v = 118, + QBVK_w = 119, + QBVK_x = 120, + QBVK_y = 121, + QBVK_z = 122, + QBVK_DELETE = 127, + //End of ASCII mapped QBVKs + //International QBVKs + QBVK_WORLD_0 = 160, /* 0xA0 */ + QBVK_WORLD_1 = 161, + QBVK_WORLD_2 = 162, + QBVK_WORLD_3 = 163, + QBVK_WORLD_4 = 164, + QBVK_WORLD_5 = 165, + QBVK_WORLD_6 = 166, + QBVK_WORLD_7 = 167, + QBVK_WORLD_8 = 168, + QBVK_WORLD_9 = 169, + QBVK_WORLD_10 = 170, + QBVK_WORLD_11 = 171, + QBVK_WORLD_12 = 172, + QBVK_WORLD_13 = 173, + QBVK_WORLD_14 = 174, + QBVK_WORLD_15 = 175, + QBVK_WORLD_16 = 176, + QBVK_WORLD_17 = 177, + QBVK_WORLD_18 = 178, + QBVK_WORLD_19 = 179, + QBVK_WORLD_20 = 180, + QBVK_WORLD_21 = 181, + QBVK_WORLD_22 = 182, + QBVK_WORLD_23 = 183, + QBVK_WORLD_24 = 184, + QBVK_WORLD_25 = 185, + QBVK_WORLD_26 = 186, + QBVK_WORLD_27 = 187, + QBVK_WORLD_28 = 188, + QBVK_WORLD_29 = 189, + QBVK_WORLD_30 = 190, + QBVK_WORLD_31 = 191, + QBVK_WORLD_32 = 192, + QBVK_WORLD_33 = 193, + QBVK_WORLD_34 = 194, + QBVK_WORLD_35 = 195, + QBVK_WORLD_36 = 196, + QBVK_WORLD_37 = 197, + QBVK_WORLD_38 = 198, + QBVK_WORLD_39 = 199, + QBVK_WORLD_40 = 200, + QBVK_WORLD_41 = 201, + QBVK_WORLD_42 = 202, + QBVK_WORLD_43 = 203, + QBVK_WORLD_44 = 204, + QBVK_WORLD_45 = 205, + QBVK_WORLD_46 = 206, + QBVK_WORLD_47 = 207, + QBVK_WORLD_48 = 208, + QBVK_WORLD_49 = 209, + QBVK_WORLD_50 = 210, + QBVK_WORLD_51 = 211, + QBVK_WORLD_52 = 212, + QBVK_WORLD_53 = 213, + QBVK_WORLD_54 = 214, + QBVK_WORLD_55 = 215, + QBVK_WORLD_56 = 216, + QBVK_WORLD_57 = 217, + QBVK_WORLD_58 = 218, + QBVK_WORLD_59 = 219, + QBVK_WORLD_60 = 220, + QBVK_WORLD_61 = 221, + QBVK_WORLD_62 = 222, + QBVK_WORLD_63 = 223, + QBVK_WORLD_64 = 224, + QBVK_WORLD_65 = 225, + QBVK_WORLD_66 = 226, + QBVK_WORLD_67 = 227, + QBVK_WORLD_68 = 228, + QBVK_WORLD_69 = 229, + QBVK_WORLD_70 = 230, + QBVK_WORLD_71 = 231, + QBVK_WORLD_72 = 232, + QBVK_WORLD_73 = 233, + QBVK_WORLD_74 = 234, + QBVK_WORLD_75 = 235, + QBVK_WORLD_76 = 236, + QBVK_WORLD_77 = 237, + QBVK_WORLD_78 = 238, + QBVK_WORLD_79 = 239, + QBVK_WORLD_80 = 240, + QBVK_WORLD_81 = 241, + QBVK_WORLD_82 = 242, + QBVK_WORLD_83 = 243, + QBVK_WORLD_84 = 244, + QBVK_WORLD_85 = 245, + QBVK_WORLD_86 = 246, + QBVK_WORLD_87 = 247, + QBVK_WORLD_88 = 248, + QBVK_WORLD_89 = 249, + QBVK_WORLD_90 = 250, + QBVK_WORLD_91 = 251, + QBVK_WORLD_92 = 252, + QBVK_WORLD_93 = 253, + QBVK_WORLD_94 = 254, + QBVK_WORLD_95 = 255, /* 0xFF */ + //Numeric keypad + QBVK_KP0 = 256, + QBVK_KP1 = 257, + QBVK_KP2 = 258, + QBVK_KP3 = 259, + QBVK_KP4 = 260, + QBVK_KP5 = 261, + QBVK_KP6 = 262, + QBVK_KP7 = 263, + QBVK_KP8 = 264, + QBVK_KP9 = 265, + QBVK_KP_PERIOD = 266, + QBVK_KP_DIVIDE = 267, + QBVK_KP_MULTIPLY = 268, + QBVK_KP_MINUS = 269, + QBVK_KP_PLUS = 270, + QBVK_KP_ENTER = 271, + QBVK_KP_EQUALS = 272, + //Arrows + Home/End pad + QBVK_UP = 273, + QBVK_DOWN = 274, + QBVK_RIGHT = 275, + QBVK_LEFT = 276, + QBVK_INSERT = 277, + QBVK_HOME = 278, + QBVK_END = 279, + QBVK_PAGEUP = 280, + QBVK_PAGEDOWN = 281, + //Function keys + QBVK_F1 = 282, + QBVK_F2 = 283, + QBVK_F3 = 284, + QBVK_F4 = 285, + QBVK_F5 = 286, + QBVK_F6 = 287, + QBVK_F7 = 288, + QBVK_F8 = 289, + QBVK_F9 = 290, + QBVK_F10 = 291, + QBVK_F11 = 292, + QBVK_F12 = 293, + QBVK_F13 = 294, + QBVK_F14 = 295, + QBVK_F15 = 296, + //Key state modifier keys + QBVK_NUMLOCK = 300, + QBVK_CAPSLOCK = 301, + QBVK_SCROLLOCK = 302, + QBVK_RSHIFT = 303, + QBVK_LSHIFT = 304, + QBVK_RCTRL = 305, + QBVK_LCTRL = 306, + QBVK_RALT = 307, + QBVK_LALT = 308, + QBVK_RMETA = 309, + QBVK_LMETA = 310, + QBVK_LSUPER = 311, /* Left "Windows" key */ + QBVK_RSUPER = 312, /* Right "Windows" key */ + QBVK_MODE = 313, /* "Alt Gr" key */ + QBVK_COMPOSE = 314, /* Multi-key compose key */ + //Miscellaneous function keys + QBVK_HELP = 315, + QBVK_PRINT = 316, + QBVK_SYSREQ = 317, + QBVK_BREAK = 318, + QBVK_MENU = 319, + QBVK_POWER = 320, /* Power Macintosh power key */ + QBVK_EURO = 321, /* Some european keyboards */ + QBVK_UNDO = 322, /* Atari keyboard has Undo */ + QBVK_LAST +}QBVKs; +//Enumeration of valid key mods (possibly OR'd together) +typedef enum { + KMOD_NONE = 0x0000, + KMOD_LSHIFT= 0x0001, + KMOD_RSHIFT= 0x0002, + KMOD_LCTRL = 0x0040, + KMOD_RCTRL = 0x0080, + KMOD_LALT = 0x0100, + KMOD_RALT = 0x0200, + KMOD_LMETA = 0x0400, + KMOD_RMETA = 0x0800, + KMOD_NUM = 0x1000, + KMOD_CAPS = 0x2000, + KMOD_MODE = 0x4000, + KMOD_RESERVED = 0x8000 +}KMODs; +#define KMOD_CTRL (KMOD_LCTRL|KMOD_RCTRL) +#define KMOD_SHIFT (KMOD_LSHIFT|KMOD_RSHIFT) +#define KMOD_ALT (KMOD_LALT|KMOD_RALT) +#define KMOD_META (KMOD_LMETA|KMOD_RMETA) + + +#ifdef _WIN32_WCE + +typedef struct GXDisplayProperties GXDisplayProperties; +typedef struct GXKeyList GXKeyList; +#include + +typedef struct GXKeyList (*GXGETDEFAULTKEYS)(int); +typedef int (*GXOPENINPUT)(); + +GXGETDEFAULTKEYS GXGetDefaultKeys_ = NULL; +GXOPENINPUT GXOpenInput_ = NULL; + +struct GXKeyList gxKeyList; + +#endif /* _WIN32_WCE */ + +/* + * Try to get the maximum value allowed for ints, falling back to the minimum + * guaranteed by ISO C99 if there is no suitable header. + */ +#ifdef HAVE_LIMITS_H +# include +#endif +#ifndef INT_MAX +# define INT_MAX 32767 +#endif + +#ifndef MIN +# define MIN(a,b) (((a)<(b)) ? (a) : (b)) +#endif + +#ifdef WM_TOUCH + typedef BOOL (WINAPI *pGetTouchInputInfo)(HTOUCHINPUT,UINT,PTOUCHINPUT,int); + typedef BOOL (WINAPI *pCloseTouchInputHandle)(HTOUCHINPUT); + static pGetTouchInputInfo fghGetTouchInputInfo = (pGetTouchInputInfo)0xDEADBEEF; + static pCloseTouchInputHandle fghCloseTouchInputHandle = (pCloseTouchInputHandle)0xDEADBEEF; +#endif + +/* + * TODO BEFORE THE STABLE RELEASE: + * + * There are some issues concerning window redrawing under X11, and maybe + * some events are not handled. The Win32 version lacks some more features, + * but seems acceptable for not demanding purposes. + * + * Need to investigate why the X11 version breaks out with an error when + * closing a window (using the window manager, not glutDestroyWindow)... + */ + +/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ + +/* + * Handle a window configuration change. When no reshape + * callback is hooked, the viewport size is updated to + * match the new window size. + */ +static void fghReshapeWindow ( SFG_Window *window, int width, int height ) +{ + SFG_Window *current_window = fgStructure.CurrentWindow; + + freeglut_return_if_fail( window != NULL ); + +#if TARGET_HOST_POSIX_X11 + + XResizeWindow( fgDisplay.Display, window->Window.Handle, + width, height ); + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) + { + RECT windowRect; + + /* + * For windowed mode, get the current position of the + * window and resize taking the size of the frame + * decorations into account. + */ + + /* "GetWindowRect" returns the pixel coordinates of the outside of the window */ + GetWindowRect( window->Window.Handle, &windowRect ); + + /* Create rect in FreeGLUT format, (X,Y) topleft outside window, WxH of client area */ + windowRect.right = windowRect.left+width; + windowRect.bottom = windowRect.top+height; + + if (window->Parent == NULL) + /* get the window rect from this to feed to SetWindowPos, correct for window decorations */ + fghComputeWindowRectFromClientArea_QueryWindow(window,&windowRect,TRUE); + else + { + /* correct rect for position client area of parent window + * (SetWindowPos input for child windows is in coordinates + * relative to the parent's client area). + * Child windows don't have decoration, so no need to correct + * for them. + */ + RECT parentRect; + parentRect = fghGetClientArea( window->Parent, FALSE ); + windowRect.left -= parentRect.left; + windowRect.right -= parentRect.left; + windowRect.top -= parentRect.top; + windowRect.bottom -= parentRect.top; + } + + /* Do the actual resizing */ + SetWindowPos( window->Window.Handle, + HWND_TOP, + windowRect.left, windowRect.top, + windowRect.right - windowRect.left, + windowRect.bottom- windowRect.top, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | + SWP_NOZORDER + ); + } +#endif + + if( FETCH_WCB( *window, Reshape ) ) + INVOKE_WCB( *window, Reshape, ( width, height ) ); + else + { + fgSetWindow( window ); + glViewport( 0, 0, width, height ); + } + + /* + * Force a window redraw. In Windows at least this is only a partial + * solution: if the window is increasing in size in either dimension, + * the already-drawn part does not get drawn again and things look funny. + * But without this we get this bad behaviour whenever we resize the + * window. + */ + window->State.Redisplay = GL_TRUE; + + if( window->IsMenu ) + fgSetWindow( current_window ); +} + +/* + * Calls a window's redraw method. This is used when + * a redraw is forced by the incoming window messages. + */ +static void fghRedrawWindow ( SFG_Window *window ) +{ + SFG_Window *current_window = fgStructure.CurrentWindow; + + freeglut_return_if_fail( window ); + freeglut_return_if_fail( FETCH_WCB ( *window, Display ) ); + + window->State.Redisplay = GL_FALSE; + + freeglut_return_if_fail( window->State.Visible ); + + fgSetWindow( window ); + + if( window->State.NeedToResize ) + { + fghReshapeWindow( + window, + window->State.Width, + window->State.Height + ); + + window->State.NeedToResize = GL_FALSE; + } + + INVOKE_WCB( *window, Display, ( ) ); + + fgSetWindow( current_window ); +} + +/* + * A static helper function to execute display callback for a window + */ +static void fghcbDisplayWindow( SFG_Window *window, + SFG_Enumerator *enumerator ) +{ + if( window->State.Redisplay && + window->State.Visible ) + { + window->State.Redisplay = GL_FALSE; + +#if TARGET_HOST_POSIX_X11 + fghRedrawWindow ( window ) ; +#elif TARGET_HOST_MS_WINDOWS + + RedrawWindow( + window->Window.Handle, NULL, NULL, + RDW_NOERASE | RDW_INTERNALPAINT | RDW_INVALIDATE | RDW_UPDATENOW + ); +#endif + } + + fgEnumSubWindows( window, fghcbDisplayWindow, enumerator ); +} + +/* + * Make all windows perform a display call + */ +static void fghDisplayAll( void ) +{ + SFG_Enumerator enumerator; + + enumerator.found = GL_FALSE; + enumerator.data = NULL; + + fgEnumWindows( fghcbDisplayWindow, &enumerator ); +} + +/* + * Window enumerator callback to check for the joystick polling code + */ +static void fghcbCheckJoystickPolls( SFG_Window *window, + SFG_Enumerator *enumerator ) +{ + long int checkTime = fgElapsedTime( ); + + if( window->State.JoystickLastPoll + window->State.JoystickPollRate <= + checkTime ) + { +#if !defined(_WIN32_WCE) + fgJoystickPollWindow( window ); +#endif /* !defined(_WIN32_WCE) */ + window->State.JoystickLastPoll = checkTime; + } + + fgEnumSubWindows( window, fghcbCheckJoystickPolls, enumerator ); +} + +/* + * Check all windows for joystick polling + */ +static void fghCheckJoystickPolls( void ) +{ + SFG_Enumerator enumerator; + + enumerator.found = GL_FALSE; + enumerator.data = NULL; + + fgEnumWindows( fghcbCheckJoystickPolls, &enumerator ); +} + +/* + * Check the global timers + */ +static void fghCheckTimers( void ) +{ + long checkTime = fgElapsedTime( ); + + while( fgState.Timers.First ) + { + SFG_Timer *timer = fgState.Timers.First; + + if( timer->TriggerTime > checkTime ) + break; + + fgListRemove( &fgState.Timers, &timer->Node ); + fgListAppend( &fgState.FreeTimers, &timer->Node ); + + timer->Callback( timer->ID ); + } +} + + +/* Platform-dependent time in milliseconds, as an unsigned 32-bit integer. + * This value wraps every 49.7 days, but integer overflows cancel + * when subtracting an initial start time, unless the total time exceeds + * 32-bit, where the GLUT API return value is also overflowed. + */ +unsigned long fgSystemTime(void) { +#if TARGET_HOST_SOLARIS || HAVE_GETTIMEOFDAY + struct timeval now; + gettimeofday( &now, NULL ); + return now.tv_usec/1000 + now.tv_sec*1000; +#elif TARGET_HOST_MS_WINDOWS +# if defined(_WIN32_WCE) + return GetTickCount(); +# else + return timeGetTime(); +# endif +#endif +} + +/* + * Elapsed Time + */ +long fgElapsedTime( void ) +{ + return (long) (fgSystemTime() - fgState.Time); +} + +/* + * Error Messages. + */ +void fgError( const char *fmt, ... ) +{ + va_list ap; + + if (fgState.ErrorFunc) { + + va_start( ap, fmt ); + + /* call user set error handler here */ + fgState.ErrorFunc(fmt, ap); + + va_end( ap ); + + } else { + + va_start( ap, fmt ); + + fprintf( stderr, "freeglut "); + if( fgState.ProgramName ) + fprintf( stderr, "(%s): ", fgState.ProgramName ); + VFPRINTF( stderr, fmt, ap ); + fprintf( stderr, "\n" ); + + va_end( ap ); + + if ( fgState.Initialised ) + fgDeinitialize (); + + exit( 1 ); + } +} + +void fgWarning( const char *fmt, ... ) +{ + va_list ap; + + if (fgState.WarningFunc) { + + va_start( ap, fmt ); + + /* call user set warning handler here */ + fgState.WarningFunc(fmt, ap); + + va_end( ap ); + + } else { + + va_start( ap, fmt ); + + fprintf( stderr, "freeglut "); + if( fgState.ProgramName ) + fprintf( stderr, "(%s): ", fgState.ProgramName ); + VFPRINTF( stderr, fmt, ap ); + fprintf( stderr, "\n" ); + + va_end( ap ); + } +} + + +/* + * Indicates whether Joystick events are being used by ANY window. + * + * The current mechanism is to walk all of the windows and ask if + * there is a joystick callback. We have a short-circuit early + * return if we find any joystick handler registered. + * + * The real way to do this is to make use of the glutTimer() API + * to more cleanly re-implement the joystick API. Then, this code + * and all other "joystick timer" code can be yanked. + * + */ +static void fghCheckJoystickCallback( SFG_Window* w, SFG_Enumerator* e) +{ + if( FETCH_WCB( *w, Joystick ) ) + { + e->found = GL_TRUE; + e->data = w; + } + fgEnumSubWindows( w, fghCheckJoystickCallback, e ); +} +static int fghHaveJoystick( void ) +{ + SFG_Enumerator enumerator; + + enumerator.found = GL_FALSE; + enumerator.data = NULL; + fgEnumWindows( fghCheckJoystickCallback, &enumerator ); + return !!enumerator.data; +} +static void fghHavePendingRedisplaysCallback( SFG_Window* w, SFG_Enumerator* e) +{ + if( w->State.Redisplay && w->State.Visible ) + { + e->found = GL_TRUE; + e->data = w; + } + fgEnumSubWindows( w, fghHavePendingRedisplaysCallback, e ); +} +static int fghHavePendingRedisplays (void) +{ + SFG_Enumerator enumerator; + + enumerator.found = GL_FALSE; + enumerator.data = NULL; + fgEnumWindows( fghHavePendingRedisplaysCallback, &enumerator ); + return !!enumerator.data; +} +/* + * Returns the number of GLUT ticks (milliseconds) till the next timer event. + */ +static long fghNextTimer( void ) +{ + long ret = INT_MAX; + SFG_Timer *timer = fgState.Timers.First; + + if( timer ) + ret = timer->TriggerTime - fgElapsedTime(); + if( ret < 0 ) + ret = 0; + + return ret; +} +/* + * Does the magic required to relinquish the CPU until something interesting + * happens. + */ +static void fghSleepForEvents( void ) +{ + long msec; + + if( fgState.IdleCallback || fghHavePendingRedisplays( ) ) + return; + + msec = fghNextTimer( ); + /* XXX Use GLUT timers for joysticks... */ + /* XXX Dumb; forces granularity to .01sec */ + if( fghHaveJoystick( ) && ( msec > 10 ) ) + msec = 10; + +#if TARGET_HOST_POSIX_X11 + /* + * Possibly due to aggressive use of XFlush() and friends, + * it is possible to have our socket drained but still have + * unprocessed events. (Or, this may just be normal with + * X, anyway?) We do non-trivial processing of X events + * after the event-reading loop, in any case, so we + * need to allow that we may have an empty socket but non- + * empty event queue. + */ + if( ! XPending( fgDisplay.Display ) ) + { + fd_set fdset; + int err; + int socket; + struct timeval wait; + + socket = ConnectionNumber( fgDisplay.Display ); + FD_ZERO( &fdset ); + FD_SET( socket, &fdset ); + wait.tv_sec = msec / 1000; + wait.tv_usec = (msec % 1000) * 1000; + err = select( socket+1, &fdset, NULL, NULL, &wait ); + +#ifdef HAVE_ERRNO_H + if( ( -1 == err ) && ( errno != EINTR ) ) + fgWarning ( "freeglut select() error: %d", errno ); +#endif + } +#elif TARGET_HOST_MS_WINDOWS + MsgWaitForMultipleObjects( 0, NULL, FALSE, msec, QS_ALLINPUT ); +#endif +} + +#if TARGET_HOST_POSIX_X11 +/* + * Returns GLUT modifier mask for the state field of an X11 event. + */ +int fghGetXModifiers( int state ) +{ + int ret = 0; + + if( state & ( ShiftMask | LockMask ) ) + ret |= GLUT_ACTIVE_SHIFT; + if( state & ControlMask ) + ret |= GLUT_ACTIVE_CTRL; + if( state & Mod1Mask ) + ret |= GLUT_ACTIVE_ALT; + + return ret; +} +#endif + + +#if TARGET_HOST_POSIX_X11 && _DEBUG + +static const char* fghTypeToString( int type ) +{ + switch( type ) { + case KeyPress: return "KeyPress"; + case KeyRelease: return "KeyRelease"; + case ButtonPress: return "ButtonPress"; + case ButtonRelease: return "ButtonRelease"; + case MotionNotify: return "MotionNotify"; + case EnterNotify: return "EnterNotify"; + case LeaveNotify: return "LeaveNotify"; + case FocusIn: return "FocusIn"; + case FocusOut: return "FocusOut"; + case KeymapNotify: return "KeymapNotify"; + case Expose: return "Expose"; + case GraphicsExpose: return "GraphicsExpose"; + case NoExpose: return "NoExpose"; + case VisibilityNotify: return "VisibilityNotify"; + case CreateNotify: return "CreateNotify"; + case DestroyNotify: return "DestroyNotify"; + case UnmapNotify: return "UnmapNotify"; + case MapNotify: return "MapNotify"; + case MapRequest: return "MapRequest"; + case ReparentNotify: return "ReparentNotify"; + case ConfigureNotify: return "ConfigureNotify"; + case ConfigureRequest: return "ConfigureRequest"; + case GravityNotify: return "GravityNotify"; + case ResizeRequest: return "ResizeRequest"; + case CirculateNotify: return "CirculateNotify"; + case CirculateRequest: return "CirculateRequest"; + case PropertyNotify: return "PropertyNotify"; + case SelectionClear: return "SelectionClear"; + case SelectionRequest: return "SelectionRequest"; + case SelectionNotify: return "SelectionNotify"; + case ColormapNotify: return "ColormapNotify"; + case ClientMessage: return "ClientMessage"; + case MappingNotify: return "MappingNotify"; + default: return "UNKNOWN"; + } +} + +static const char* fghBoolToString( Bool b ) +{ + return b == False ? "False" : "True"; +} + +static const char* fghNotifyHintToString( char is_hint ) +{ + switch( is_hint ) { + case NotifyNormal: return "NotifyNormal"; + case NotifyHint: return "NotifyHint"; + default: return "UNKNOWN"; + } +} + +static const char* fghNotifyModeToString( int mode ) +{ + switch( mode ) { + case NotifyNormal: return "NotifyNormal"; + case NotifyGrab: return "NotifyGrab"; + case NotifyUngrab: return "NotifyUngrab"; + case NotifyWhileGrabbed: return "NotifyWhileGrabbed"; + default: return "UNKNOWN"; + } +} + +static const char* fghNotifyDetailToString( int detail ) +{ + switch( detail ) { + case NotifyAncestor: return "NotifyAncestor"; + case NotifyVirtual: return "NotifyVirtual"; + case NotifyInferior: return "NotifyInferior"; + case NotifyNonlinear: return "NotifyNonlinear"; + case NotifyNonlinearVirtual: return "NotifyNonlinearVirtual"; + case NotifyPointer: return "NotifyPointer"; + case NotifyPointerRoot: return "NotifyPointerRoot"; + case NotifyDetailNone: return "NotifyDetailNone"; + default: return "UNKNOWN"; + } +} + +static const char* fghVisibilityToString( int state ) { + switch( state ) { + case VisibilityUnobscured: return "VisibilityUnobscured"; + case VisibilityPartiallyObscured: return "VisibilityPartiallyObscured"; + case VisibilityFullyObscured: return "VisibilityFullyObscured"; + default: return "UNKNOWN"; + } +} + +static const char* fghConfigureDetailToString( int detail ) +{ + switch( detail ) { + case Above: return "Above"; + case Below: return "Below"; + case TopIf: return "TopIf"; + case BottomIf: return "BottomIf"; + case Opposite: return "Opposite"; + default: return "UNKNOWN"; + } +} + +static const char* fghPlaceToString( int place ) +{ + switch( place ) { + case PlaceOnTop: return "PlaceOnTop"; + case PlaceOnBottom: return "PlaceOnBottom"; + default: return "UNKNOWN"; + } +} + +static const char* fghMappingRequestToString( int request ) +{ + switch( request ) { + case MappingModifier: return "MappingModifier"; + case MappingKeyboard: return "MappingKeyboard"; + case MappingPointer: return "MappingPointer"; + default: return "UNKNOWN"; + } +} + +static const char* fghPropertyStateToString( int state ) +{ + switch( state ) { + case PropertyNewValue: return "PropertyNewValue"; + case PropertyDelete: return "PropertyDelete"; + default: return "UNKNOWN"; + } +} + +static const char* fghColormapStateToString( int state ) +{ + switch( state ) { + case ColormapUninstalled: return "ColormapUninstalled"; + case ColormapInstalled: return "ColormapInstalled"; + default: return "UNKNOWN"; + } +} + +static void fghPrintEvent( XEvent *event ) +{ + switch( event->type ) { + + case KeyPress: + case KeyRelease: { + XKeyEvent *e = &event->xkey; + fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, " + "(x,y)=(%d,%d), (x_root,y_root)=(%d,%d), state=0x%x, " + "keycode=%u, same_screen=%s", fghTypeToString( e->type ), + e->window, e->root, e->subwindow, (unsigned long)e->time, + e->x, e->y, e->x_root, e->y_root, e->state, e->keycode, + fghBoolToString( e->same_screen ) ); + break; + } + + case ButtonPress: + case ButtonRelease: { + XButtonEvent *e = &event->xbutton; + fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, " + "(x,y)=(%d,%d), (x_root,y_root)=(%d,%d), state=0x%x, " + "button=%u, same_screen=%d", fghTypeToString( e->type ), + e->window, e->root, e->subwindow, (unsigned long)e->time, + e->x, e->y, e->x_root, e->y_root, e->state, e->button, + fghBoolToString( e->same_screen ) ); + break; + } + + case MotionNotify: { + XMotionEvent *e = &event->xmotion; + fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, " + "(x,y)=(%d,%d), (x_root,y_root)=(%d,%d), state=0x%x, " + "is_hint=%s, same_screen=%d", fghTypeToString( e->type ), + e->window, e->root, e->subwindow, (unsigned long)e->time, + e->x, e->y, e->x_root, e->y_root, e->state, + fghNotifyHintToString( e->is_hint ), + fghBoolToString( e->same_screen ) ); + break; + } + + case EnterNotify: + case LeaveNotify: { + XCrossingEvent *e = &event->xcrossing; + fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, " + "(x,y)=(%d,%d), mode=%s, detail=%s, same_screen=%d, " + "focus=%d, state=0x%x", fghTypeToString( e->type ), + e->window, e->root, e->subwindow, (unsigned long)e->time, + e->x, e->y, fghNotifyModeToString( e->mode ), + fghNotifyDetailToString( e->detail ), (int)e->same_screen, + (int)e->focus, e->state ); + break; + } + + case FocusIn: + case FocusOut: { + XFocusChangeEvent *e = &event->xfocus; + fgWarning( "%s: window=0x%x, mode=%s, detail=%s", + fghTypeToString( e->type ), e->window, + fghNotifyModeToString( e->mode ), + fghNotifyDetailToString( e->detail ) ); + break; + } + + case KeymapNotify: { + XKeymapEvent *e = &event->xkeymap; + char buf[32 * 2 + 1]; + int i; + for ( i = 0; i < 32; i++ ) { + snprintf( &buf[ i * 2 ], sizeof( buf ) - i * 2, + "%02x", e->key_vector[ i ] ); + } + buf[ i ] = '\0'; + fgWarning( "%s: window=0x%x, %s", fghTypeToString( e->type ), e->window, + buf ); + break; + } + + case Expose: { + XExposeEvent *e = &event->xexpose; + fgWarning( "%s: window=0x%x, (x,y)=(%d,%d), (width,height)=(%d,%d), " + "count=%d", fghTypeToString( e->type ), e->window, e->x, + e->y, e->width, e->height, e->count ); + break; + } + + case GraphicsExpose: { + XGraphicsExposeEvent *e = &event->xgraphicsexpose; + fgWarning( "%s: drawable=0x%x, (x,y)=(%d,%d), (width,height)=(%d,%d), " + "count=%d, (major_code,minor_code)=(%d,%d)", + fghTypeToString( e->type ), e->drawable, e->x, e->y, + e->width, e->height, e->count, e->major_code, + e->minor_code ); + break; + } + + case NoExpose: { + XNoExposeEvent *e = &event->xnoexpose; + fgWarning( "%s: drawable=0x%x, (major_code,minor_code)=(%d,%d)", + fghTypeToString( e->type ), e->drawable, e->major_code, + e->minor_code ); + break; + } + + case VisibilityNotify: { + XVisibilityEvent *e = &event->xvisibility; + fgWarning( "%s: window=0x%x, state=%s", fghTypeToString( e->type ), + e->window, fghVisibilityToString( e->state) ); + break; + } + + case CreateNotify: { + XCreateWindowEvent *e = &event->xcreatewindow; + fgWarning( "%s: (x,y)=(%d,%d), (width,height)=(%d,%d), border_width=%d, " + "window=0x%x, override_redirect=%s", + fghTypeToString( e->type ), e->x, e->y, e->width, e->height, + e->border_width, e->window, + fghBoolToString( e->override_redirect ) ); + break; + } + + case DestroyNotify: { + XDestroyWindowEvent *e = &event->xdestroywindow; + fgWarning( "%s: event=0x%x, window=0x%x", + fghTypeToString( e->type ), e->event, e->window ); + break; + } + + case UnmapNotify: { + XUnmapEvent *e = &event->xunmap; + fgWarning( "%s: event=0x%x, window=0x%x, from_configure=%s", + fghTypeToString( e->type ), e->event, e->window, + fghBoolToString( e->from_configure ) ); + break; + } + + case MapNotify: { + XMapEvent *e = &event->xmap; + fgWarning( "%s: event=0x%x, window=0x%x, override_redirect=%s", + fghTypeToString( e->type ), e->event, e->window, + fghBoolToString( e->override_redirect ) ); + break; + } + + case MapRequest: { + XMapRequestEvent *e = &event->xmaprequest; + fgWarning( "%s: parent=0x%x, window=0x%x", + fghTypeToString( event->type ), e->parent, e->window ); + break; + } + + case ReparentNotify: { + XReparentEvent *e = &event->xreparent; + fgWarning( "%s: event=0x%x, window=0x%x, parent=0x%x, (x,y)=(%d,%d), " + "override_redirect=%s", fghTypeToString( e->type ), + e->event, e->window, e->parent, e->x, e->y, + fghBoolToString( e->override_redirect ) ); + break; + } + + case ConfigureNotify: { + XConfigureEvent *e = &event->xconfigure; + fgWarning( "%s: event=0x%x, window=0x%x, (x,y)=(%d,%d), " + "(width,height)=(%d,%d), border_width=%d, above=0x%x, " + "override_redirect=%s", fghTypeToString( e->type ), e->event, + e->window, e->x, e->y, e->width, e->height, e->border_width, + e->above, fghBoolToString( e->override_redirect ) ); + break; + } + + case ConfigureRequest: { + XConfigureRequestEvent *e = &event->xconfigurerequest; + fgWarning( "%s: parent=0x%x, window=0x%x, (x,y)=(%d,%d), " + "(width,height)=(%d,%d), border_width=%d, above=0x%x, " + "detail=%s, value_mask=%lx", fghTypeToString( e->type ), + e->parent, e->window, e->x, e->y, e->width, e->height, + e->border_width, e->above, + fghConfigureDetailToString( e->detail ), e->value_mask ); + break; + } + + case GravityNotify: { + XGravityEvent *e = &event->xgravity; + fgWarning( "%s: event=0x%x, window=0x%x, (x,y)=(%d,%d)", + fghTypeToString( e->type ), e->event, e->window, e->x, e->y ); + break; + } + + case ResizeRequest: { + XResizeRequestEvent *e = &event->xresizerequest; + fgWarning( "%s: window=0x%x, (width,height)=(%d,%d)", + fghTypeToString( e->type ), e->window, e->width, e->height ); + break; + } + + case CirculateNotify: { + XCirculateEvent *e = &event->xcirculate; + fgWarning( "%s: event=0x%x, window=0x%x, place=%s", + fghTypeToString( e->type ), e->event, e->window, + fghPlaceToString( e->place ) ); + break; + } + + case CirculateRequest: { + XCirculateRequestEvent *e = &event->xcirculaterequest; + fgWarning( "%s: parent=0x%x, window=0x%x, place=%s", + fghTypeToString( e->type ), e->parent, e->window, + fghPlaceToString( e->place ) ); + break; + } + + case PropertyNotify: { + XPropertyEvent *e = &event->xproperty; + fgWarning( "%s: window=0x%x, atom=%lu, time=%lu, state=%s", + fghTypeToString( e->type ), e->window, + (unsigned long)e->atom, (unsigned long)e->time, + fghPropertyStateToString( e->state ) ); + break; + } + + case SelectionClear: { + XSelectionClearEvent *e = &event->xselectionclear; + fgWarning( "%s: window=0x%x, selection=%lu, time=%lu", + fghTypeToString( e->type ), e->window, + (unsigned long)e->selection, (unsigned long)e->time ); + break; + } + + case SelectionRequest: { + XSelectionRequestEvent *e = &event->xselectionrequest; + fgWarning( "%s: owner=0x%x, requestor=0x%x, selection=0x%x, " + "target=0x%x, property=%lu, time=%lu", + fghTypeToString( e->type ), e->owner, e->requestor, + (unsigned long)e->selection, (unsigned long)e->target, + (unsigned long)e->property, (unsigned long)e->time ); + break; + } + + case SelectionNotify: { + XSelectionEvent *e = &event->xselection; + fgWarning( "%s: requestor=0x%x, selection=0x%x, target=0x%x, " + "property=%lu, time=%lu", fghTypeToString( e->type ), + e->requestor, (unsigned long)e->selection, + (unsigned long)e->target, (unsigned long)e->property, + (unsigned long)e->time ); + break; + } + + case ColormapNotify: { + XColormapEvent *e = &event->xcolormap; + fgWarning( "%s: window=0x%x, colormap=%lu, new=%s, state=%s", + fghTypeToString( e->type ), e->window, + (unsigned long)e->colormap, fghBoolToString( e->new ), + fghColormapStateToString( e->state ) ); + break; + } + + case ClientMessage: { + XClientMessageEvent *e = &event->xclient; + char buf[ 61 ]; + char* p = buf; + char* end = buf + sizeof( buf ); + int i; + switch( e->format ) { + case 8: + for ( i = 0; i < 20; i++, p += 3 ) { + snprintf( p, end - p, " %02x", e->data.b[ i ] ); + } + break; + case 16: + for ( i = 0; i < 10; i++, p += 5 ) { + snprintf( p, end - p, " %04x", e->data.s[ i ] ); + } + break; + case 32: + for ( i = 0; i < 5; i++, p += 9 ) { + snprintf( p, end - p, " %08lx", e->data.l[ i ] ); + } + break; + } + *p = '\0'; + fgWarning( "%s: window=0x%x, message_type=%lu, format=%d, data=(%s )", + fghTypeToString( e->type ), e->window, + (unsigned long)e->message_type, e->format, buf ); + break; + } + + case MappingNotify: { + XMappingEvent *e = &event->xmapping; + fgWarning( "%s: window=0x%x, request=%s, first_keycode=%d, count=%d", + fghTypeToString( e->type ), e->window, + fghMappingRequestToString( e->request ), e->first_keycode, + e->count ); + break; + } + + default: { + fgWarning( "%s", fghTypeToString( event->type ) ); + break; + } + } +} + +#endif + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * Executes a single iteration in the freeglut processing loop. + */ +void FGAPIENTRY glutMainLoopEvent( void ) +{ +#if TARGET_HOST_POSIX_X11 + SFG_Window* window; + XEvent event; + + /* This code was repeated constantly, so here it goes into a definition: */ +#define GETWINDOW(a) \ + window = fgWindowByHandle( event.a.window ); \ + if( window == NULL ) \ + break; + +#define GETMOUSE(a) \ + window->State.MouseX = event.a.x; \ + window->State.MouseY = event.a.y; + + + + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" ); + + while( XPending( fgDisplay.Display ) ) + { + XNextEvent( fgDisplay.Display, &event ); +#if _DEBUG + fghPrintEvent( &event ); +#endif + + int qb64_os_event_info=0; + + qb64_os_event_info=1; + qb64_os_event_linux(&event, fgDisplay.Display, &qb64_os_event_info); + if (qb64_os_event_info==3) return; + + switch( event.type ) + { + case ClientMessage: + if(fgIsSpaceballXEvent(&event)) { + fgSpaceballHandleXEvent(&event); + break; + } + /* Destroy the window when the WM_DELETE_WINDOW message arrives */ + if( (Atom) event.xclient.data.l[ 0 ] == fgDisplay.DeleteWindow ) + { + GETWINDOW( xclient ); + qb64_custom_event(QB64_EVENT_CLOSE,0,0,0,0,0,0,0,0,NULL,NULL); + /* fgDestroyWindow ( window ); + + if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT ) + { + fgDeinitialize( ); + exit( 0 ); + } + else if( fgState.ActionOnWindowClose == GLUT_ACTION_GLUTMAINLOOP_RETURNS ) + fgState.ExecState = GLUT_EXEC_STATE_STOP; + return; + */ + } + break; + + /* + * CreateNotify causes a configure-event so that sub-windows are + * handled compatibly with GLUT. Otherwise, your sub-windows + * (in freeglut only) will not get an initial reshape event, + * which can break things. + * + * GLUT presumably does this because it generally tries to treat + * sub-windows the same as windows. + */ + case CreateNotify: + case ConfigureNotify: + { + int width, height; + if( event.type == CreateNotify ) { + GETWINDOW( xcreatewindow ); + width = event.xcreatewindow.width; + height = event.xcreatewindow.height; + } else { + GETWINDOW( xconfigure ); + width = event.xconfigure.width; + height = event.xconfigure.height; + } + + if( ( width != window->State.OldWidth ) || + ( height != window->State.OldHeight ) ) + { + SFG_Window *current_window = fgStructure.CurrentWindow; + + window->State.OldWidth = width; + window->State.OldHeight = height; + if( FETCH_WCB( *window, Reshape ) ) + INVOKE_WCB( *window, Reshape, ( width, height ) ); + else + { + fgSetWindow( window ); + glViewport( 0, 0, width, height ); + } + glutPostRedisplay( ); + if( window->IsMenu ) + fgSetWindow( current_window ); + } + } + break; + + case DestroyNotify: + /* + * This is sent to confirm the XDestroyWindow call. + * + * XXX WHY is this commented out? Should we re-enable it? + */ + /* fgAddToWindowDestroyList ( window ); */ + break; + + case Expose: + /* + * We are too dumb to process partial exposes... + * + * XXX Well, we could do it. However, it seems to only + * XXX be potentially useful for single-buffered (since + * XXX double-buffered does not respect viewport when we + * XXX do a buffer-swap). + * + */ + if( event.xexpose.count == 0 ) + { + GETWINDOW( xexpose ); + window->State.Redisplay = GL_TRUE; + } + break; + + case MapNotify: + break; + + case UnmapNotify: + /* We get this when iconifying a window. */ + GETWINDOW( xunmap ); + INVOKE_WCB( *window, WindowStatus, ( GLUT_HIDDEN ) ); + window->State.Visible = GL_FALSE; + break; + + case MappingNotify: + /* + * Have the client's keyboard knowledge updated (xlib.ps, + * page 206, says that's a good thing to do) + */ + XRefreshKeyboardMapping( (XMappingEvent *) &event ); + break; + + case VisibilityNotify: + { + /* + * Sending this event, the X server can notify us that the window + * has just acquired one of the three possible visibility states: + * VisibilityUnobscured, VisibilityPartiallyObscured or + * VisibilityFullyObscured. Note that we DO NOT receive a + * VisibilityNotify event when iconifying a window, we only get an + * UnmapNotify then. + */ + GETWINDOW( xvisibility ); + switch( event.xvisibility.state ) + { + case VisibilityUnobscured: + INVOKE_WCB( *window, WindowStatus, ( GLUT_FULLY_RETAINED ) ); + window->State.Visible = GL_TRUE; + break; + + case VisibilityPartiallyObscured: + INVOKE_WCB( *window, WindowStatus, + ( GLUT_PARTIALLY_RETAINED ) ); + window->State.Visible = GL_TRUE; + break; + + case VisibilityFullyObscured: + INVOKE_WCB( *window, WindowStatus, ( GLUT_FULLY_COVERED ) ); + window->State.Visible = GL_FALSE; + break; + + default: + fgWarning( "Unknown X visibility state: %d", + event.xvisibility.state ); + break; + } + } + break; + + case EnterNotify: + case LeaveNotify: + GETWINDOW( xcrossing ); + GETMOUSE( xcrossing ); + if( ( event.type == LeaveNotify ) && window->IsMenu && + window->ActiveMenu && window->ActiveMenu->IsActive ) + fgUpdateMenuHighlight( window->ActiveMenu ); + + INVOKE_WCB( *window, Entry, ( ( EnterNotify == event.type ) ? + GLUT_ENTERED : + GLUT_LEFT ) ); + break; + + case MotionNotify: + { + GETWINDOW( xmotion ); + GETMOUSE( xmotion ); + + if( window->ActiveMenu ) + { + if( window == window->ActiveMenu->ParentWindow ) + { + window->ActiveMenu->Window->State.MouseX = + event.xmotion.x_root - window->ActiveMenu->X; + window->ActiveMenu->Window->State.MouseY = + event.xmotion.y_root - window->ActiveMenu->Y; + } + + fgUpdateMenuHighlight( window->ActiveMenu ); + + break; + } + + /* + * XXX For more than 5 buttons, just check {event.xmotion.state}, + * XXX rather than a host of bit-masks? Or maybe we need to + * XXX track ButtonPress/ButtonRelease events in our own + * XXX bit-mask? + */ + fgState.Modifiers = fghGetXModifiers( event.xmotion.state ); + if ( event.xmotion.state & ( Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask ) ) { + INVOKE_WCB( *window, Motion, ( event.xmotion.x, + event.xmotion.y ) ); + } else { + INVOKE_WCB( *window, Passive, ( event.xmotion.x, + event.xmotion.y ) ); + } + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case ButtonRelease: + case ButtonPress: + { + GLboolean pressed = GL_TRUE; + int button; + + if( event.type == ButtonRelease ) + pressed = GL_FALSE ; + + /* + * A mouse button has been pressed or released. Traditionally, + * break if the window was found within the freeglut structures. + */ + GETWINDOW( xbutton ); + GETMOUSE( xbutton ); + + /* + * An X button (at least in XFree86) is numbered from 1. + * A GLUT button is numbered from 0. + * Old GLUT passed through buttons other than just the first + * three, though it only gave symbolic names and official + * support to the first three. + */ + button = event.xbutton.button - 1; + + /* + * Do not execute the application's mouse callback if a menu + * is hooked to this button. In that case an appropriate + * private call should be generated. + */ + if( fgCheckActiveMenu( window, button, pressed, + event.xbutton.x_root, event.xbutton.y_root ) ) + break; + + /* + * Check if there is a mouse or mouse wheel callback hooked to the + * window + */ + if( ! FETCH_WCB( *window, Mouse ) && + ! FETCH_WCB( *window, MouseWheel ) ) + break; + + fgState.Modifiers = fghGetXModifiers( event.xbutton.state ); + + /* Finally execute the mouse or mouse wheel callback */ + if( ( button < glutDeviceGet ( GLUT_NUM_MOUSE_BUTTONS ) ) || ( ! FETCH_WCB( *window, MouseWheel ) ) ) + INVOKE_WCB( *window, Mouse, ( button, + pressed ? GLUT_DOWN : GLUT_UP, + event.xbutton.x, + event.xbutton.y ) + ); + else + { + /* + * Map 4 and 5 to wheel zero; EVEN to +1, ODD to -1 + * " 6 and 7 " " one; ... + * + * XXX This *should* be behind some variables/macros, + * XXX since the order and numbering isn't certain + * XXX See XFree86 configuration docs (even back in the + * XXX 3.x days, and especially with 4.x). + * + * XXX Note that {button} has already been decremented + * XXX in mapping from X button numbering to GLUT. + * + * XXX Should add support for partial wheel turns as Windows does -- 5/27/11 + */ + int wheel_number = (button - glutDeviceGet ( GLUT_NUM_MOUSE_BUTTONS )) / 2; + int direction = -1; + if( button % 2 ) + direction = 1; + + if( pressed ) + INVOKE_WCB( *window, MouseWheel, ( wheel_number, + direction, + event.xbutton.x, + event.xbutton.y ) + ); + } + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case KeyRelease: + case KeyPress: + { + FGCBKeyboard keyboard_cb; + FGCBSpecial special_cb; + + GETWINDOW( xkey ); + GETMOUSE( xkey ); + + /* Detect auto repeated keys, if configured globally or per-window */ + + if ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) + { + if (event.type==KeyRelease) + { + /* + * Look at X11 keystate to detect repeat mode. + * While X11 says the key is actually held down, we'll ignore KeyRelease/KeyPress pairs. + */ + + char keys[32]; + XQueryKeymap( fgDisplay.Display, keys ); /* Look at X11 keystate to detect repeat mode */ + + if ( event.xkey.keycode<256 ) /* XQueryKeymap is limited to 256 keycodes */ + { + if ( keys[event.xkey.keycode>>3] & (1<<(event.xkey.keycode%8)) ) + window->State.KeyRepeating = GL_TRUE; + else + window->State.KeyRepeating = GL_FALSE; + } + } + } + else + window->State.KeyRepeating = GL_FALSE; + + /* Cease processing this event if it is auto repeated */ + + if (window->State.KeyRepeating) + { + if (event.type == KeyPress) window->State.KeyRepeating = GL_FALSE; + break; + } + + if( event.type == KeyPress ) + { + keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, Keyboard )); + special_cb = (FGCBSpecial) ( FETCH_WCB( *window, Special )); + } + else + { + keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, KeyboardUp )); + special_cb = (FGCBSpecial) ( FETCH_WCB( *window, SpecialUp )); + } + + /* Is there a keyboard/special callback hooked for this window? */ + if( keyboard_cb || special_cb ) + { + XComposeStatus composeStatus; + char asciiCode[ 32 ]; + KeySym keySym; + int len; + + /* Check for the ASCII/KeySym codes associated with the event: */ + len = XLookupString( &event.xkey, asciiCode, sizeof(asciiCode), + &keySym, &composeStatus + ); + + /* GLUT API tells us to have two separate callbacks... */ + if( len > 0 ) + { + /* ...one for the ASCII translateable keypresses... */ + if( keyboard_cb ) + { + fgSetWindow( window ); + fgState.Modifiers = fghGetXModifiers( event.xkey.state ); + keyboard_cb( asciiCode[ 0 ], + event.xkey.x, event.xkey.y + ); + fgState.Modifiers = INVALID_MODIFIERS; + } + } + else + { + int special = -1; + + /* + * ...and one for all the others, which need to be + * translated to GLUT_KEY_Xs... + */ + switch( keySym ) + { + case XK_F1: special = GLUT_KEY_F1; break; + case XK_F2: special = GLUT_KEY_F2; break; + case XK_F3: special = GLUT_KEY_F3; break; + case XK_F4: special = GLUT_KEY_F4; break; + case XK_F5: special = GLUT_KEY_F5; break; + case XK_F6: special = GLUT_KEY_F6; break; + case XK_F7: special = GLUT_KEY_F7; break; + case XK_F8: special = GLUT_KEY_F8; break; + case XK_F9: special = GLUT_KEY_F9; break; + case XK_F10: special = GLUT_KEY_F10; break; + case XK_F11: special = GLUT_KEY_F11; break; + case XK_F12: special = GLUT_KEY_F12; break; + + case XK_KP_Left: + case XK_Left: special = GLUT_KEY_LEFT; break; + case XK_KP_Right: + case XK_Right: special = GLUT_KEY_RIGHT; break; + case XK_KP_Up: + case XK_Up: special = GLUT_KEY_UP; break; + case XK_KP_Down: + case XK_Down: special = GLUT_KEY_DOWN; break; + + case XK_KP_Prior: + case XK_Prior: special = GLUT_KEY_PAGE_UP; break; + case XK_KP_Next: + case XK_Next: special = GLUT_KEY_PAGE_DOWN; break; + case XK_KP_Home: + case XK_Home: special = GLUT_KEY_HOME; break; + case XK_KP_End: + case XK_End: special = GLUT_KEY_END; break; + case XK_KP_Insert: + case XK_Insert: special = GLUT_KEY_INSERT; break; + + case XK_Num_Lock : special = GLUT_KEY_NUM_LOCK; break; + case XK_KP_Begin : special = GLUT_KEY_BEGIN; break; + case XK_KP_Delete: special = GLUT_KEY_DELETE; break; + + case XK_Shift_L: special = GLUT_KEY_SHIFT_L; break; + case XK_Shift_R: special = GLUT_KEY_SHIFT_R; break; + case XK_Control_L: special = GLUT_KEY_CTRL_L; break; + case XK_Control_R: special = GLUT_KEY_CTRL_R; break; + case XK_Alt_L: special = GLUT_KEY_ALT_L; break; + case XK_Alt_R: special = GLUT_KEY_ALT_R; break; + } + + /* + * Execute the callback (if one has been specified), + * given that the special code seems to be valid... + */ + if( special_cb && (special != -1) ) + { + fgSetWindow( window ); + fgState.Modifiers = fghGetXModifiers( event.xkey.state ); + special_cb( special, event.xkey.x, event.xkey.y ); + fgState.Modifiers = INVALID_MODIFIERS; + } + } + } + } + break; + + case ReparentNotify: + break; /* XXX Should disable this event */ + + /* Not handled */ + case GravityNotify: + break; + + default: + /* enter handling of Extension Events here */ + #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H + fgHandleExtensionEvents( &event ); + #endif + break; + } + + qb64_os_event_info=2; + qb64_os_event_linux(&event, fgDisplay.Display, &qb64_os_event_info); + if (qb64_os_event_info==3) return;//(although we would return anyway) + + } + +#elif TARGET_HOST_MS_WINDOWS + + MSG stMsg; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" ); + + while( PeekMessage( &stMsg, NULL, 0, 0, PM_NOREMOVE ) ) + { + if( GetMessage( &stMsg, NULL, 0, 0 ) == 0 ) + { + if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT ) + { + fgDeinitialize( ); + exit( 0 ); + } + else if( fgState.ActionOnWindowClose == GLUT_ACTION_GLUTMAINLOOP_RETURNS ) + fgState.ExecState = GLUT_EXEC_STATE_STOP; + + return; + } + + TranslateMessage( &stMsg ); + DispatchMessage( &stMsg ); + } +#endif + + if( fgState.Timers.First ) + fghCheckTimers( ); + fghCheckJoystickPolls( ); + fghDisplayAll( ); + + fgCloseWindows( ); +} + +/* + * Enters the freeglut processing loop. + * Stays until the "ExecState" changes to "GLUT_EXEC_STATE_STOP". + */ +void FGAPIENTRY glutMainLoop( void ) +{ + int action; + +#if TARGET_HOST_MS_WINDOWS + SFG_Window *window = (SFG_Window *)fgStructure.Windows.First ; +#endif + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoop" ); + +#if TARGET_HOST_MS_WINDOWS + /* + * Processing before the main loop: If there is a window which is open and + * which has a visibility callback, call it. I know this is an ugly hack, + * but I'm not sure what else to do about it. Ideally we should leave + * something uninitialized in the create window code and initialize it in + * the main loop, and have that initialization create a "WM_ACTIVATE" + * message. Then we would put the visibility callback code in the + * "case WM_ACTIVATE" block below. - John Fay -- 10/24/02 + */ + while( window ) + { + if ( FETCH_WCB( *window, Visibility ) ) + { + SFG_Window *current_window = fgStructure.CurrentWindow ; + + INVOKE_WCB( *window, Visibility, ( window->State.Visible ) ); + fgSetWindow( current_window ); + } + + window = (SFG_Window *)window->Node.Next ; + } +#endif + + fgState.ExecState = GLUT_EXEC_STATE_RUNNING ; + while( fgState.ExecState == GLUT_EXEC_STATE_RUNNING ) + { + SFG_Window *window; + + glutMainLoopEvent( ); + /* + * Step through the list of windows, seeing if there are any + * that are not menus + */ + for( window = ( SFG_Window * )fgStructure.Windows.First; + window; + window = ( SFG_Window * )window->Node.Next ) + if ( ! ( window->IsMenu ) ) + break; + + if( ! window ) + fgState.ExecState = GLUT_EXEC_STATE_STOP; + else + { + if( fgState.IdleCallback ) + { + if( fgStructure.CurrentWindow && + fgStructure.CurrentWindow->IsMenu ) + /* fail safe */ + fgSetWindow( window ); + fgState.IdleCallback( ); + } + + fghSleepForEvents( ); + } + } + + /* + * When this loop terminates, destroy the display, state and structure + * of a freeglut session, so that another glutInit() call can happen + * + * Save the "ActionOnWindowClose" because "fgDeinitialize" resets it. + */ + action = fgState.ActionOnWindowClose; + fgDeinitialize( ); + if( action == GLUT_ACTION_EXIT ) + exit( 0 ); +} + +/* + * Leaves the freeglut processing loop. + */ +void FGAPIENTRY glutLeaveMainLoop( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutLeaveMainLoop" ); + fgState.ExecState = GLUT_EXEC_STATE_STOP ; +} + + +#if TARGET_HOST_MS_WINDOWS +/* + * Determine a GLUT modifier mask based on MS-WINDOWS system info. + */ +static int fghGetWin32Modifiers (void) +{ + return + ( ( ( GetKeyState( VK_LSHIFT ) < 0 ) || + ( GetKeyState( VK_RSHIFT ) < 0 )) ? GLUT_ACTIVE_SHIFT : 0 ) | + ( ( ( GetKeyState( VK_LCONTROL ) < 0 ) || + ( GetKeyState( VK_RCONTROL ) < 0 )) ? GLUT_ACTIVE_CTRL : 0 ) | + ( ( ( GetKeyState( VK_LMENU ) < 0 ) || + ( GetKeyState( VK_RMENU ) < 0 )) ? GLUT_ACTIVE_ALT : 0 ); +} + +/* + * The window procedure for handling Win32 events + */ +LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, + LPARAM lParam ) +{ + + int qb64_os_event_info=0; + LRESULT qb64_os_event_return=1; + + qb64_os_event_info=1; + qb64_os_event_return=qb64_os_event_windows( + hWnd, uMsg, wParam,lParam, &qb64_os_event_info + ); + if (qb64_os_event_info==3) return qb64_os_event_return; + + static unsigned char lControl = 0, rControl = 0, lShift = 0, + rShift = 0, lAlt = 0, rAlt = 0; + + SFG_Window* window; + PAINTSTRUCT ps; + LRESULT lRet = 1; + + FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ; + + window = fgWindowByHandle( hWnd ); + + if ( ( window == NULL ) && ( uMsg != WM_CREATE ) ) + return DefWindowProc( hWnd, uMsg, wParam, lParam ); + + /* printf ( "Window %3d message <%04x> %12d %12d\n", window?window->ID:0, + uMsg, wParam, lParam ); */ + + if ( window ) + { + /* Checking for CTRL, ALT, and SHIFT key positions: Key Down! */ + if (hWnd == GetForegroundWindow()) { + if ( !lControl && GetAsyncKeyState ( VK_LCONTROL ) ) + { + INVOKE_WCB ( *window, Special, + ( GLUT_KEY_CTRL_L, window->State.MouseX, window->State.MouseY ) + ); + + lControl = 1; + } + + if ( !rControl && GetAsyncKeyState ( VK_RCONTROL ) ) + { + INVOKE_WCB ( *window, Special, + ( GLUT_KEY_CTRL_R, window->State.MouseX, window->State.MouseY ) + ); + + rControl = 1; + } + + if ( !lShift && GetAsyncKeyState ( VK_LSHIFT ) ) + { + INVOKE_WCB ( *window, Special, + ( GLUT_KEY_SHIFT_L, window->State.MouseX, window->State.MouseY ) + ); + + lShift = 1; + } + + if ( !rShift && GetAsyncKeyState ( VK_RSHIFT ) ) + { + INVOKE_WCB ( *window, Special, + ( GLUT_KEY_SHIFT_R, window->State.MouseX, window->State.MouseY ) + ); + + rShift = 1; + } + + if ( !lAlt && GetAsyncKeyState ( VK_LMENU ) ) + { + INVOKE_WCB ( *window, Special, + ( GLUT_KEY_ALT_L, window->State.MouseX, window->State.MouseY ) + ); + + lAlt = 1; + } + + if ( !rAlt && GetAsyncKeyState ( VK_RMENU ) ) + { + INVOKE_WCB ( *window, Special, + ( GLUT_KEY_ALT_R, window->State.MouseX, window->State.MouseY ) + ); + + rAlt = 1; + } + } + + /* Checking for CTRL, ALT, and SHIFT key positions: Key Up! */ + if ( lControl && !GetAsyncKeyState ( VK_LCONTROL ) ) + { + INVOKE_WCB ( *window, SpecialUp, + ( GLUT_KEY_CTRL_L, window->State.MouseX, window->State.MouseY ) + ); + + lControl = 0; + } + + if ( rControl && !GetAsyncKeyState ( VK_RCONTROL ) ) + { + INVOKE_WCB ( *window, SpecialUp, + ( GLUT_KEY_CTRL_R, window->State.MouseX, window->State.MouseY ) + ); + + rControl = 0; + } + + if ( lShift && !GetAsyncKeyState ( VK_LSHIFT ) ) + { + INVOKE_WCB ( *window, SpecialUp, + ( GLUT_KEY_SHIFT_L, window->State.MouseX, window->State.MouseY ) + ); + + lShift = 0; + } + + if ( rShift && !GetAsyncKeyState ( VK_RSHIFT ) ) + { + INVOKE_WCB ( *window, SpecialUp, + ( GLUT_KEY_SHIFT_R, window->State.MouseX, window->State.MouseY ) + ); + + rShift = 0; + } + + if ( lAlt && !GetAsyncKeyState ( VK_LMENU ) ) + { + INVOKE_WCB ( *window, SpecialUp, + ( GLUT_KEY_ALT_L, window->State.MouseX, window->State.MouseY ) + ); + + lAlt = 0; + } + + if ( rAlt && !GetAsyncKeyState ( VK_RMENU ) ) + { + INVOKE_WCB ( *window, SpecialUp, + ( GLUT_KEY_ALT_R, window->State.MouseX, window->State.MouseY ) + ); + + rAlt = 0; + } + } + + switch( uMsg ) + { + case WM_CREATE: + /* The window structure is passed as the creation structure parameter... */ + window = (SFG_Window *) (((LPCREATESTRUCT) lParam)->lpCreateParams); + FREEGLUT_INTERNAL_ERROR_EXIT ( ( window != NULL ), "Cannot create window", + "fgWindowProc" ); + + window->Window.Handle = hWnd; + window->Window.Device = GetDC( hWnd ); + if( window->IsMenu ) + { + unsigned int current_DisplayMode = fgState.DisplayMode; + fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH; +#if !defined(_WIN32_WCE) + fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE ); +#endif + fgState.DisplayMode = current_DisplayMode; + + if( fgStructure.MenuContext ) + wglMakeCurrent( window->Window.Device, + fgStructure.MenuContext->MContext + ); + else + { + fgStructure.MenuContext = + (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) ); + fgStructure.MenuContext->MContext = + wglCreateContext( window->Window.Device ); + } + + /* window->Window.Context = wglGetCurrentContext (); */ + window->Window.Context = wglCreateContext( window->Window.Device ); + } + else + { +#if !defined(_WIN32_WCE) + fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE ); +#endif + + if( ! fgState.UseCurrentContext ) + window->Window.Context = + wglCreateContext( window->Window.Device ); + else + { + window->Window.Context = wglGetCurrentContext( ); + if( ! window->Window.Context ) + window->Window.Context = + wglCreateContext( window->Window.Device ); + } + +#if !defined(_WIN32_WCE) + fgNewWGLCreateContext( window ); +#endif + } + + window->State.NeedToResize = GL_TRUE; + /* if we used CW_USEDEFAULT (that's a negative value) for the size + * of the window, query the window now for the size at which it + * was created. + */ + if( ( window->State.Width < 0 ) || ( window->State.Height < 0 ) ) + { + SFG_Window *current_window = fgStructure.CurrentWindow; + + fgSetWindow( window ); + window->State.Width = glutGet( GLUT_WINDOW_WIDTH ); + window->State.Height = glutGet( GLUT_WINDOW_HEIGHT ); + fgSetWindow( current_window ); + } + + ReleaseDC( window->Window.Handle, window->Window.Device ); + +#if defined(_WIN32_WCE) + /* Take over button handling */ + { + HINSTANCE dxDllLib=LoadLibrary(_T("gx.dll")); + if (dxDllLib) + { + GXGetDefaultKeys_=(GXGETDEFAULTKEYS)GetProcAddress(dxDllLib, _T("?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z")); + GXOpenInput_=(GXOPENINPUT)GetProcAddress(dxDllLib, _T("?GXOpenInput@@YAHXZ")); + } + + if(GXOpenInput_) + (*GXOpenInput_)(); + if(GXGetDefaultKeys_) + gxKeyList = (*GXGetDefaultKeys_)(GX_LANDSCAPEKEYS); + } + +#endif /* defined(_WIN32_WCE) */ + break; + + case WM_SIZE: + /* + * If the window is visible, then it is the user manually resizing it. + * If it is not, then it is the system sending us a dummy resize with + * zero dimensions on a "glutIconifyWindow" call. + */ + if( window->State.Visible ) + { + window->State.NeedToResize = GL_TRUE; +#if defined(_WIN32_WCE) + window->State.Width = HIWORD(lParam); + window->State.Height = LOWORD(lParam); +#else + window->State.Width = LOWORD(lParam); + window->State.Height = HIWORD(lParam); +#endif /* defined(_WIN32_WCE) */ + } + + break; + + case WM_SETFOCUS: +/* printf("WM_SETFOCUS: %p\n", window ); */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) ); + break; + + case WM_KILLFOCUS: +/* printf("WM_KILLFOCUS: %p\n", window ); */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) ); + + if( window->IsMenu && + window->ActiveMenu && window->ActiveMenu->IsActive ) + fgUpdateMenuHighlight( window->ActiveMenu ); + + break; + +#if 0 + case WM_ACTIVATE: + if (LOWORD(wParam) != WA_INACTIVE) + { +/* printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window, + window->State.Cursor ); */ + fgSetCursor( window, window->State.Cursor ); + } + + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + break; +#endif + + case WM_SETCURSOR: +/* printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */ + if( LOWORD( lParam ) == HTCLIENT ) + fgSetCursor ( window, window->State.Cursor ) ; + else + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + break; + + case WM_SHOWWINDOW: + window->State.Visible = GL_TRUE; + window->State.Redisplay = GL_TRUE; + break; + + case WM_PAINT: + /* Turn on the visibility in case it was turned off somehow */ + window->State.Visible = GL_TRUE; + BeginPaint( hWnd, &ps ); + fghRedrawWindow( window ); + EndPaint( hWnd, &ps ); + break; + + case WM_CLOSE: + +//QB64 +/* + fgDestroyWindow ( window ); + if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION ) + PostQuitMessage(0); +*/ + qb64_custom_event(QB64_EVENT_CLOSE,0,0,0,0,0,0,0,0,NULL,NULL); + + break; + + case WM_DROPFILES: + qb64_custom_event(QB64_EVENT_FILE_DROP,0,0,0,0,0,0,0,0,(void*)wParam,NULL); + break; + + case WM_DESTROY: + /* + * The window already got destroyed, so don't bother with it. + */ + return 0; + + + static int raw_setup=0; + static RAWINPUTDEVICE Rid[1]; + case WM_INPUT: + { + if (raw_setup){ + //QB64 + //adapted from http://msdn.microsoft.com/en-us/library/windows/desktop/ee418864%28v=vs.85%29.aspx#WM_INPUT + UINT dwSize = sizeof(RAWINPUT); + static BYTE lpb[sizeof(RAWINPUT)]; + GetRawInputData((HRAWINPUT)lParam, RID_INPUT, + lpb, &dwSize, sizeof(RAWINPUTHEADER)); + RAWINPUT* raw = (RAWINPUT*)lpb; + if (raw->header.dwType == RIM_TYPEMOUSE) + { + int xPosRelative = raw->data.mouse.lLastX; + int yPosRelative = raw->data.mouse.lLastY; + if (xPosRelative||yPosRelative) qb64_custom_event(QB64_EVENT_RELATIVE_MOUSE_MOVEMENT,xPosRelative,yPosRelative,0,0,0,0,0,0,NULL,NULL); + } + + } + break; + + } + + case WM_MOUSEMOVE: + { + + + + if (!raw_setup){ + raw_setup=1; + #ifndef HID_USAGE_PAGE_GENERIC + #define HID_USAGE_PAGE_GENERIC ((USHORT) 0x01) + #endif + #ifndef HID_USAGE_GENERIC_MOUSE + #define HID_USAGE_GENERIC_MOUSE ((USHORT) 0x02) + #endif + Rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC; + Rid[0].usUsage = HID_USAGE_GENERIC_MOUSE; + Rid[0].dwFlags = RIDEV_INPUTSINK; + Rid[0].hwndTarget = window->Window.Handle; + RegisterRawInputDevices(Rid, 1, sizeof(Rid[0])); + } + + + +#if defined(_WIN32_WCE) + window->State.MouseX = 320-HIWORD( lParam ); + window->State.MouseY = LOWORD( lParam ); +#else + window->State.MouseX = LOWORD( lParam ); + window->State.MouseY = HIWORD( lParam ); +#endif /* defined(_WIN32_WCE) */ + /* Restrict to [-32768, 32767] to match X11 behaviour */ + /* See comment in "freeglut_developer" mailing list 10/4/04 */ + if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536; + if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536; + + if ( window->ActiveMenu ) + { + fgUpdateMenuHighlight( window->ActiveMenu ); + break; + } + SetFocus(window->Window.Handle); + + fgState.Modifiers = fghGetWin32Modifiers( ); + + if( ( wParam & MK_LBUTTON ) || + ( wParam & MK_MBUTTON ) || + ( wParam & MK_RBUTTON ) ) + INVOKE_WCB( *window, Motion, ( window->State.MouseX, + window->State.MouseY ) ); + else + INVOKE_WCB( *window, Passive, ( window->State.MouseX, + window->State.MouseY ) ); + + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + { + GLboolean pressed = GL_TRUE; + int button; + +#if defined(_WIN32_WCE) + window->State.MouseX = 320-HIWORD( lParam ); + window->State.MouseY = LOWORD( lParam ); +#else + window->State.MouseX = LOWORD( lParam ); + window->State.MouseY = HIWORD( lParam ); +#endif /* defined(_WIN32_WCE) */ + + /* Restrict to [-32768, 32767] to match X11 behaviour */ + /* See comment in "freeglut_developer" mailing list 10/4/04 */ + if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536; + if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536; + + switch( uMsg ) + { + case WM_LBUTTONDOWN: + pressed = GL_TRUE; + button = GLUT_LEFT_BUTTON; + break; + case WM_MBUTTONDOWN: + pressed = GL_TRUE; + button = GLUT_MIDDLE_BUTTON; + break; + case WM_RBUTTONDOWN: + pressed = GL_TRUE; + button = GLUT_RIGHT_BUTTON; + break; + case WM_LBUTTONUP: + pressed = GL_FALSE; + button = GLUT_LEFT_BUTTON; + break; + case WM_MBUTTONUP: + pressed = GL_FALSE; + button = GLUT_MIDDLE_BUTTON; + break; + case WM_RBUTTONUP: + pressed = GL_FALSE; + button = GLUT_RIGHT_BUTTON; + break; + default: + pressed = GL_FALSE; + button = -1; + break; + } + +#if !defined(_WIN32_WCE) + if( GetSystemMetrics( SM_SWAPBUTTON ) ) + { + if( button == GLUT_LEFT_BUTTON ) + button = GLUT_RIGHT_BUTTON; + else + if( button == GLUT_RIGHT_BUTTON ) + button = GLUT_LEFT_BUTTON; + } +#endif /* !defined(_WIN32_WCE) */ + + if( button == -1 ) + return DefWindowProc( hWnd, uMsg, lParam, wParam ); + + /* + * Do not execute the application's mouse callback if a menu + * is hooked to this button. In that case an appropriate + * private call should be generated. + */ + if( fgCheckActiveMenu( window, button, pressed, + window->State.MouseX, window->State.MouseY ) ) + break; + + /* Set capture so that the window captures all the mouse messages */ + /* + * XXX - Multiple button support: Under X11, the mouse is not released + * XXX - from the window until all buttons have been released, even if the + * XXX - user presses a button in another window. This will take more + * XXX - code changes than I am up to at the moment (10/5/04). The present + * XXX - is a 90 percent solution. + */ + if ( pressed == GL_TRUE ) + SetCapture ( window->Window.Handle ) ; + else + ReleaseCapture () ; + + if( ! FETCH_WCB( *window, Mouse ) ) + break; + + fgSetWindow( window ); + fgState.Modifiers = fghGetWin32Modifiers( ); + + INVOKE_WCB( + *window, Mouse, + ( button, + pressed ? GLUT_DOWN : GLUT_UP, + window->State.MouseX, + window->State.MouseY + ) + ); + + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case 0x020a: + /* Should be WM_MOUSEWHEEL but my compiler doesn't recognize it */ + { + int wheel_number = LOWORD( wParam ); + short ticks = ( short )HIWORD( wParam ); + fgState.MouseWheelTicks += ticks; + + /* + * XXX Should use WHEEL_DELTA instead of 120 + */ + if ( abs ( fgState.MouseWheelTicks ) > 120 ) + { + int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1; + + if( ! FETCH_WCB( *window, MouseWheel ) && + ! FETCH_WCB( *window, Mouse ) ) + break; + + fgSetWindow( window ); + fgState.Modifiers = fghGetWin32Modifiers( ); + + /* + * XXX Should use WHEEL_DELTA instead of 120 + */ + while( abs ( fgState.MouseWheelTicks ) > 120 ) + { + if( FETCH_WCB( *window, MouseWheel ) ) + INVOKE_WCB( *window, MouseWheel, + ( wheel_number, + direction, + window->State.MouseX, + window->State.MouseY + ) + ); + else /* No mouse wheel, call the mouse button callback twice */ + { + /* + * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4 + * " " one +1 to 5, -1 to 6, ... + * + * XXX The below assumes that you have no more than 3 mouse + * XXX buttons. Sorry. + */ + int button = wheel_number * 2 + 3; + if( direction < 0 ) + ++button; + INVOKE_WCB( *window, Mouse, + ( button, GLUT_DOWN, + window->State.MouseX, window->State.MouseY ) + ); + INVOKE_WCB( *window, Mouse, + ( button, GLUT_UP, + window->State.MouseX, window->State.MouseY ) + ); + } + + /* + * XXX Should use WHEEL_DELTA instead of 120 + */ + fgState.MouseWheelTicks -= 120 * direction; + } + + fgState.Modifiers = INVALID_MODIFIERS; + } + } + break ; + + case WM_SYSKEYDOWN: + case WM_KEYDOWN: + { + +//QB64 +if (wParam==VK_PAUSE){ + qb64_custom_event(QB64_EVENT_KEY,VK+QBVK_PAUSE,1,0,0,0,0,0,0,NULL,NULL); + break; +} +if (wParam==VK_CANCEL){ + qb64_custom_event(QB64_EVENT_KEY,VK+QBVK_BREAK,1,0,0,0,0,0,0,NULL,NULL); + break; +} + + + int keypress = -1; + POINT mouse_pos ; + + if( ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) ) + break; + + /* + * Remember the current modifiers state. This is done here in order + * to make sure the VK_DELETE keyboard callback is executed properly. + */ + fgState.Modifiers = fghGetWin32Modifiers( ); + + GetCursorPos( &mouse_pos ); + ScreenToClient( window->Window.Handle, &mouse_pos ); + + window->State.MouseX = mouse_pos.x; + window->State.MouseY = mouse_pos.y; + + /* Convert the Win32 keystroke codes to GLUTtish way */ +# define KEY(a,b) case a: keypress = b; break; + + switch( wParam ) + { + KEY( VK_F1, GLUT_KEY_F1 ); + KEY( VK_F2, GLUT_KEY_F2 ); + KEY( VK_F3, GLUT_KEY_F3 ); + KEY( VK_F4, GLUT_KEY_F4 ); + KEY( VK_F5, GLUT_KEY_F5 ); + KEY( VK_F6, GLUT_KEY_F6 ); + KEY( VK_F7, GLUT_KEY_F7 ); + KEY( VK_F8, GLUT_KEY_F8 ); + KEY( VK_F9, GLUT_KEY_F9 ); + KEY( VK_F10, GLUT_KEY_F10 ); + KEY( VK_F11, GLUT_KEY_F11 ); + KEY( VK_F12, GLUT_KEY_F12 ); + KEY( VK_PRIOR, GLUT_KEY_PAGE_UP ); + KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN ); + KEY( VK_HOME, GLUT_KEY_HOME ); + KEY( VK_END, GLUT_KEY_END ); + KEY( VK_LEFT, GLUT_KEY_LEFT ); + KEY( VK_UP, GLUT_KEY_UP ); + KEY( VK_RIGHT, GLUT_KEY_RIGHT ); + KEY( VK_DOWN, GLUT_KEY_DOWN ); + KEY( VK_INSERT, GLUT_KEY_INSERT ); + KEY( VK_LCONTROL, GLUT_KEY_CTRL_L ); + KEY( VK_RCONTROL, GLUT_KEY_CTRL_R ); + KEY( VK_LSHIFT, GLUT_KEY_SHIFT_L ); + KEY( VK_RSHIFT, GLUT_KEY_SHIFT_R ); + KEY( VK_LMENU, GLUT_KEY_ALT_L ); + KEY( VK_RMENU, GLUT_KEY_ALT_R ); + + case VK_DELETE: + /* The delete key should be treated as an ASCII keypress: */ + INVOKE_WCB( *window, Keyboard, + ( 127, window->State.MouseX, window->State.MouseY ) + ); + } + +#if defined(_WIN32_WCE) + if(!(lParam & 0x40000000)) /* Prevent auto-repeat */ + { + if(wParam==(unsigned)gxKeyList.vkRight) + keypress = GLUT_KEY_RIGHT; + else if(wParam==(unsigned)gxKeyList.vkLeft) + keypress = GLUT_KEY_LEFT; + else if(wParam==(unsigned)gxKeyList.vkUp) + keypress = GLUT_KEY_UP; + else if(wParam==(unsigned)gxKeyList.vkDown) + keypress = GLUT_KEY_DOWN; + else if(wParam==(unsigned)gxKeyList.vkA) + keypress = GLUT_KEY_F1; + else if(wParam==(unsigned)gxKeyList.vkB) + keypress = GLUT_KEY_F2; + else if(wParam==(unsigned)gxKeyList.vkC) + keypress = GLUT_KEY_F3; + else if(wParam==(unsigned)gxKeyList.vkStart) + keypress = GLUT_KEY_F4; + } +#endif + + if( keypress != -1 ) + INVOKE_WCB( *window, Special, + ( keypress, + window->State.MouseX, window->State.MouseY ) + ); + + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case WM_SYSKEYUP: + case WM_KEYUP: + { + +//QB64 +if (wParam==VK_PAUSE){ + qb64_custom_event(QB64_EVENT_KEY,VK+QBVK_PAUSE,-1,0,0,0,0,0,0,NULL,NULL); + break; +} +if (wParam==VK_CANCEL){ + qb64_custom_event(QB64_EVENT_KEY,VK+QBVK_BREAK,-1,0,0,0,0,0,0,NULL,NULL); + break; +} + + + + + int keypress = -1; + POINT mouse_pos; + + /* + * Remember the current modifiers state. This is done here in order + * to make sure the VK_DELETE keyboard callback is executed properly. + */ + fgState.Modifiers = fghGetWin32Modifiers( ); + + GetCursorPos( &mouse_pos ); + ScreenToClient( window->Window.Handle, &mouse_pos ); + + window->State.MouseX = mouse_pos.x; + window->State.MouseY = mouse_pos.y; + + /* + * Convert the Win32 keystroke codes to GLUTtish way. + * "KEY(a,b)" was defined under "WM_KEYDOWN" + */ + + switch( wParam ) + { + KEY( VK_F1, GLUT_KEY_F1 ); + KEY( VK_F2, GLUT_KEY_F2 ); + KEY( VK_F3, GLUT_KEY_F3 ); + KEY( VK_F4, GLUT_KEY_F4 ); + KEY( VK_F5, GLUT_KEY_F5 ); + KEY( VK_F6, GLUT_KEY_F6 ); + KEY( VK_F7, GLUT_KEY_F7 ); + KEY( VK_F8, GLUT_KEY_F8 ); + KEY( VK_F9, GLUT_KEY_F9 ); + KEY( VK_F10, GLUT_KEY_F10 ); + KEY( VK_F11, GLUT_KEY_F11 ); + KEY( VK_F12, GLUT_KEY_F12 ); + KEY( VK_PRIOR, GLUT_KEY_PAGE_UP ); + KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN ); + KEY( VK_HOME, GLUT_KEY_HOME ); + KEY( VK_END, GLUT_KEY_END ); + KEY( VK_LEFT, GLUT_KEY_LEFT ); + KEY( VK_UP, GLUT_KEY_UP ); + KEY( VK_RIGHT, GLUT_KEY_RIGHT ); + KEY( VK_DOWN, GLUT_KEY_DOWN ); + KEY( VK_INSERT, GLUT_KEY_INSERT ); + KEY( VK_LCONTROL, GLUT_KEY_CTRL_L ); + KEY( VK_RCONTROL, GLUT_KEY_CTRL_R ); + KEY( VK_LSHIFT, GLUT_KEY_SHIFT_L ); + KEY( VK_RSHIFT, GLUT_KEY_SHIFT_R ); + KEY( VK_LMENU, GLUT_KEY_ALT_L ); + KEY( VK_RMENU, GLUT_KEY_ALT_R ); + + case VK_DELETE: + /* The delete key should be treated as an ASCII keypress: */ + INVOKE_WCB( *window, KeyboardUp, + ( 127, window->State.MouseX, window->State.MouseY ) + ); + break; + + default: + { +#if !defined(_WIN32_WCE) + BYTE state[ 256 ]; + WORD code[ 2 ]; + + GetKeyboardState( state ); + + if( ToAscii( (UINT)wParam, 0, state, code, 0 ) == 1 ) + wParam=code[ 0 ]; + + INVOKE_WCB( *window, KeyboardUp, + ( (char)wParam, + window->State.MouseX, window->State.MouseY ) + ); +#endif /* !defined(_WIN32_WCE) */ + } + } + + if( keypress != -1 ) + INVOKE_WCB( *window, SpecialUp, + ( keypress, + window->State.MouseX, window->State.MouseY ) + ); + + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case WM_SYSCHAR: + case WM_CHAR: + { + if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) ) + break; + + fgState.Modifiers = fghGetWin32Modifiers( ); + INVOKE_WCB( *window, Keyboard, + ( (char)wParam, + window->State.MouseX, window->State.MouseY ) + ); + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case WM_CAPTURECHANGED: + /* User has finished resizing the window, force a redraw */ + INVOKE_WCB( *window, Display, ( ) ); + + /*lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); */ + break; + + /* Other messages that I have seen and which are not handled already */ + case WM_SETTEXT: /* 0x000c */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + /* Pass it on to "DefWindowProc" to set the window text */ + break; + + case WM_GETTEXT: /* 0x000d */ + /* Ideally we would copy the title of the window into "lParam" */ + /* strncpy ( (char *)lParam, "Window Title", wParam ); + lRet = ( wParam > 12 ) ? 12 : wParam; */ + /* the number of characters copied */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + break; + + case WM_GETTEXTLENGTH: /* 0x000e */ + /* Ideally we would get the length of the title of the window */ + lRet = 12; + /* the number of characters in "Window Title\0" (see above) */ + break; + + case WM_ERASEBKGND: /* 0x0014 */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + break; + +#if !defined(_WIN32_WCE) + case WM_SYNCPAINT: /* 0x0088 */ + /* Another window has moved, need to update this one */ + window->State.Redisplay = GL_TRUE; + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + /* Help screen says this message must be passed to "DefWindowProc" */ + break; + + case WM_NCPAINT: /* 0x0085 */ + /* Need to update the border of this window */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + /* Pass it on to "DefWindowProc" to repaint a standard border */ + break; + + case WM_SYSCOMMAND : /* 0x0112 */ + { + /* + * We have received a system command message. Try to act on it. + * The commands are passed in through the "wParam" parameter: + * The least significant digit seems to be which edge of the window + * is being used for a resize event: + * 4 3 5 + * 1 2 + * 7 6 8 + * Congratulations and thanks to Richard Rauch for figuring this out.. + */ + switch ( wParam & 0xfff0 ) + { + case SC_SIZE : + break ; + + case SC_MOVE : + break ; + + case SC_MINIMIZE : + /* User has clicked on the "-" to minimize the window */ + /* Turn off the visibility */ + window->State.Visible = GL_FALSE ; + + break ; + + case SC_MAXIMIZE : + break ; + + case SC_NEXTWINDOW : + break ; + + case SC_PREVWINDOW : + break ; + + case SC_CLOSE : + /* Followed very closely by a WM_CLOSE message */ + break ; + + case SC_VSCROLL : + break ; + + case SC_HSCROLL : + break ; + + case SC_MOUSEMENU : + break ; + + case SC_KEYMENU : + break ; + + case SC_ARRANGE : + break ; + + case SC_RESTORE : + break ; + + case SC_TASKLIST : + break ; + + case SC_SCREENSAVE : + break ; + + case SC_HOTKEY : + break ; + +#if(WINVER >= 0x0400) + case SC_DEFAULT : + break ; + + case SC_MONITORPOWER : + break ; + + case SC_CONTEXTHELP : + break ; +#endif /* WINVER >= 0x0400 */ + + default: +#if _DEBUG + fgWarning( "Unknown wParam type 0x%x", wParam ); +#endif + break; + } + } +#endif /* !defined(_WIN32_WCE) */ + + /* We need to pass the message on to the operating system as well */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + break; + +#ifdef WM_TOUCH + /* handle multi-touch messages */ + case WM_TOUCH: + { + unsigned int numInputs = (unsigned int)wParam; + unsigned int i = 0; + TOUCHINPUT* ti = (TOUCHINPUT*)malloc( sizeof(TOUCHINPUT)*numInputs); + + if (fghGetTouchInputInfo == (pGetTouchInputInfo)0xDEADBEEF) { + fghGetTouchInputInfo = (pGetTouchInputInfo)GetProcAddress(GetModuleHandle("user32"),"GetTouchInputInfo"); + fghCloseTouchInputHandle = (pCloseTouchInputHandle)GetProcAddress(GetModuleHandle("user32"),"CloseTouchInputHandle"); + } + + if (!fghGetTouchInputInfo) { + free( (void*)ti ); + break; + } + + if (fghGetTouchInputInfo( (HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT) )) { + /* Handle each contact point */ + for (i = 0; i < numInputs; ++i ) { + + POINT tp; + tp.x = TOUCH_COORD_TO_PIXEL(ti[i].x); + tp.y = TOUCH_COORD_TO_PIXEL(ti[i].y); + ScreenToClient( hWnd, &tp ); + + ti[i].dwID = ti[i].dwID * 2; + + if (ti[i].dwFlags & TOUCHEVENTF_DOWN) { + INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_ENTERED ) ); + INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_DOWN ) ); + } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) { + INVOKE_WCB( *window, MultiMotion, ( ti[i].dwID, tp.x, tp.y ) ); + } else if (ti[i].dwFlags & TOUCHEVENTF_UP) { + INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_UP ) ); + INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_LEFT ) ); + } + } + } + fghCloseTouchInputHandle((HTOUCHINPUT)lParam); + free( (void*)ti ); + lRet = 0; /*DefWindowProc( hWnd, uMsg, wParam, lParam );*/ + break; + } +#endif + default: + /* Handle unhandled messages */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + break; + } + + qb64_os_event_info=2; + qb64_os_event_return=qb64_os_event_windows( + hWnd, uMsg, wParam,lParam, &qb64_os_event_info + ); + if (qb64_os_event_info==3) return qb64_os_event_return; + + return lRet; +} +#endif + +/*** END OF FILE ***/ diff --git a/internal/c/parts/core/src/freeglut_window.c b/internal/c/parts/core/src/freeglut_window.c new file mode 100644 index 000000000..165f56f3b --- /dev/null +++ b/internal/c/parts/core/src/freeglut_window.c @@ -0,0 +1,2284 @@ +#ifndef FREEGLUT_STATIC +#define FREEGLUT_STATIC +#endif + +//QB64 +void QB64_Window_Handle(void *handle); + + +int QB64_Resizable(); +/* +changed: +WS_OVERLAPPEDWINDOW +...to... +((WS_OVERLAPPEDWINDOW*QB64_Resizable())|WS_DLGFRAME|WS_BORDER|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX) +*/ + + +/* + * freeglut_window.c + * + * Window management methods. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Fri Dec 3 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#define FREEGLUT_BUILDING_LIB +#include "freeglut.h" +#include "freeglut_internal.h" + +#if TARGET_HOST_POSIX_X11 +#include /* LONG_MAX */ +#include /* usleep */ +#endif + +#if defined(_WIN32_WCE) +# include +# ifdef FREEGLUT_LIB_PRAGMAS +# pragma comment( lib, "Aygshell.lib" ) +# endif +#endif /* defined(_WIN32_WCE) */ + + +#if TARGET_HOST_POSIX_X11 +#ifndef GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB +#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2 +#endif + +#ifndef GLX_CONTEXT_MAJOR_VERSION_ARB +#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#endif + +#ifndef GLX_CONTEXT_MINOR_VERSION_ARB +#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 +#endif + +#ifndef GLX_CONTEXT_FLAGS_ARB +#define GLX_CONTEXT_FLAGS_ARB 0x2094 +#endif + +#ifndef GLX_CONTEXT_PROFILE_MASK_ARB +#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 +#endif + +#ifndef GLX_CONTEXT_DEBUG_BIT_ARB +#define GLX_CONTEXT_DEBUG_BIT_ARB 0x0001 +#endif + +#ifndef GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB +#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 +#endif + +#ifndef GLX_CONTEXT_CORE_PROFILE_BIT_ARB +#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#endif + +#ifndef GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB +#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#endif + +#ifndef GLX_RGBA_FLOAT_TYPE +#define GLX_RGBA_FLOAT_TYPE 0x20B9 +#endif + +#ifndef GLX_RGBA_FLOAT_BIT +#define GLX_RGBA_FLOAT_BIT 0x00000004 +#endif +#endif /* TARGET_HOST_POSIX_X11 */ + + +#if TARGET_HOST_MS_WINDOWS +/* The following include file is available from SGI but is not standard: + * #include + * So we copy the necessary parts out of it. + * XXX: should local definitions for extensions be put in a separate include file? + */ +typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc); + +typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); + +#define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_ACCELERATION_ARB 0x2003 +#define WGL_SUPPORT_OPENGL_ARB 0x2010 +#define WGL_DOUBLE_BUFFER_ARB 0x2011 +#define WGL_COLOR_BITS_ARB 0x2014 +#define WGL_ALPHA_BITS_ARB 0x201B +#define WGL_DEPTH_BITS_ARB 0x2022 +#define WGL_STENCIL_BITS_ARB 0x2023 +#define WGL_FULL_ACCELERATION_ARB 0x2027 + +#define WGL_SAMPLE_BUFFERS_ARB 0x2041 +#define WGL_SAMPLES_ARB 0x2042 + +#define WGL_TYPE_RGBA_FLOAT_ARB 0x21A0 + +#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9 + +#ifndef WGL_ARB_create_context +#define WGL_ARB_create_context 1 +#ifdef WGL_WGLEXT_PROTOTYPES +extern HGLRC WINAPI wglCreateContextAttribsARB (HDC, HGLRC, const int *); +#endif /* WGL_WGLEXT_PROTOTYPES */ +typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList); + +#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 +#define WGL_CONTEXT_FLAGS_ARB 0x2094 +#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 + +#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 +#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 + +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 + +#define ERROR_INVALID_VERSION_ARB 0x2095 +#define ERROR_INVALID_PROFILE_ARB 0x2096 +#endif + +#endif /* TARGET_HOST_MS_WINDOWS */ + +#ifdef WM_TOUCH + typedef BOOL (WINAPI *pRegisterTouchWindow)(HWND,ULONG); + static pRegisterTouchWindow fghRegisterTouchWindow = (pRegisterTouchWindow)0xDEADBEEF; +#endif + +/* pushing attribute/value pairs into an array */ +#define ATTRIB(a) attributes[where++]=(a) +#define ATTRIB_VAL(a,v) {ATTRIB(a); ATTRIB(v);} + +/* + * TODO BEFORE THE STABLE RELEASE: + * + * fgChooseFBConfig() -- OK, but what about glutInitDisplayString()? + * fgSetupPixelFormat -- ignores the display mode settings + * fgOpenWindow() -- check the Win32 version, -iconic handling! + * fgCloseWindow() -- check the Win32 version + * glutCreateWindow() -- Check when default position and size is {-1,-1} + * glutCreateSubWindow() -- Check when default position and size is {-1,-1} + * glutDestroyWindow() -- check the Win32 version + * glutSetWindow() -- check the Win32 version + * glutGetWindow() -- OK + * glutSetWindowTitle() -- check the Win32 version + * glutSetIconTitle() -- check the Win32 version + * glutShowWindow() -- check the Win32 version + * glutHideWindow() -- check the Win32 version + * glutIconifyWindow() -- check the Win32 version + * glutReshapeWindow() -- check the Win32 version + * glutPositionWindow() -- check the Win32 version + * glutPushWindow() -- check the Win32 version + * glutPopWindow() -- check the Win32 version + */ + +/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ + +static int fghIsLegacyContextVersionRequested( void ) +{ + return fgState.MajorVersion < 2 || (fgState.MajorVersion == 2 && fgState.MinorVersion <= 1); +} + +static int fghIsLegacyContextRequested( void ) +{ + return fghIsLegacyContextVersionRequested() && + fgState.ContextFlags == 0 && + fgState.ContextProfile == 0; +} + +static int fghNumberOfAuxBuffersRequested( void ) +{ + if ( fgState.DisplayMode & GLUT_AUX4 ) { + return 4; + } + if ( fgState.DisplayMode & GLUT_AUX3 ) { + return 3; + } + if ( fgState.DisplayMode & GLUT_AUX2 ) { + return 2; + } + if ( fgState.DisplayMode & GLUT_AUX1 ) { /* NOTE: Same as GLUT_AUX! */ + return fgState.AuxiliaryBufferNumber; + } + return 0; +} + +static int fghMapBit( int mask, int from, int to ) +{ + return ( mask & from ) ? to : 0; + +} + +static void fghContextCreationError( void ) +{ + fgError( "Unable to create OpenGL %d.%d context (flags %x, profile %x)", + fgState.MajorVersion, fgState.MinorVersion, fgState.ContextFlags, + fgState.ContextProfile ); +} + + +/* -- SYSTEM-DEPENDENT PRIVATE FUNCTIONS ------------------------------------ */ + +#if TARGET_HOST_POSIX_X11 +/* + * Chooses a visual basing on the current display mode settings + */ + +GLXFBConfig* fgChooseFBConfig( int *numcfgs ) +{ + GLboolean wantIndexedMode = GL_FALSE; + int attributes[ 100 ]; + int where = 0, numAuxBuffers; + + /* First we have to process the display mode settings... */ + if( fgState.DisplayMode & GLUT_INDEX ) { + ATTRIB_VAL( GLX_BUFFER_SIZE, 8 ); + /* Buffer size is selected later. */ + + ATTRIB_VAL( GLX_RENDER_TYPE, GLX_COLOR_INDEX_BIT ); + wantIndexedMode = GL_TRUE; + } else { + ATTRIB_VAL( GLX_RED_SIZE, 1 ); + ATTRIB_VAL( GLX_GREEN_SIZE, 1 ); + ATTRIB_VAL( GLX_BLUE_SIZE, 1 ); + if( fgState.DisplayMode & GLUT_ALPHA ) { + ATTRIB_VAL( GLX_ALPHA_SIZE, 1 ); + } + } + + if( fgState.DisplayMode & GLUT_DOUBLE ) { + ATTRIB_VAL( GLX_DOUBLEBUFFER, True ); + } + + if( fgState.DisplayMode & GLUT_STEREO ) { + ATTRIB_VAL( GLX_STEREO, True ); + } + + if( fgState.DisplayMode & GLUT_DEPTH ) { + ATTRIB_VAL( GLX_DEPTH_SIZE, 1 ); + } + + if( fgState.DisplayMode & GLUT_STENCIL ) { + ATTRIB_VAL( GLX_STENCIL_SIZE, 1 ); + } + + if( fgState.DisplayMode & GLUT_ACCUM ) { + ATTRIB_VAL( GLX_ACCUM_RED_SIZE, 1 ); + ATTRIB_VAL( GLX_ACCUM_GREEN_SIZE, 1 ); + ATTRIB_VAL( GLX_ACCUM_BLUE_SIZE, 1 ); + if( fgState.DisplayMode & GLUT_ALPHA ) { + ATTRIB_VAL( GLX_ACCUM_ALPHA_SIZE, 1 ); + } + } + + numAuxBuffers = fghNumberOfAuxBuffersRequested(); + if ( numAuxBuffers > 0 ) { + ATTRIB_VAL( GLX_AUX_BUFFERS, numAuxBuffers ); + } + + if( fgState.DisplayMode & GLUT_SRGB ) { + ATTRIB_VAL( GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, True ); + } + + if (fgState.DisplayMode & GLUT_MULTISAMPLE) { + ATTRIB_VAL(GLX_SAMPLE_BUFFERS, 1); + ATTRIB_VAL(GLX_SAMPLES, fgState.SampleNumber); + } + + /* Push a terminator at the end of the list */ + ATTRIB( None ); + + { + GLXFBConfig * fbconfigArray; /* Array of FBConfigs */ + GLXFBConfig * fbconfig; /* The FBConfig we want */ + int fbconfigArraySize; /* Number of FBConfigs in the array */ + + + /* Get all FBConfigs that match "attributes". */ + fbconfigArray = glXChooseFBConfig( fgDisplay.Display, + fgDisplay.Screen, + attributes, + &fbconfigArraySize ); + + if (fbconfigArray != NULL) + { + int result; /* Returned by glXGetFBConfigAttrib, not checked. */ + + + if( wantIndexedMode ) + { + /* + * In index mode, we want the largest buffer size, i.e. visual + * depth. Here, FBConfigs are sorted by increasing buffer size + * first, so FBConfigs with the largest size come last. + */ + + int bufferSizeMin, bufferSizeMax; + + /* Get bufferSizeMin. */ + result = + glXGetFBConfigAttrib( fgDisplay.Display, + fbconfigArray[0], + GLX_BUFFER_SIZE, + &bufferSizeMin ); + /* Get bufferSizeMax. */ + result = + glXGetFBConfigAttrib( fgDisplay.Display, + fbconfigArray[fbconfigArraySize - 1], + GLX_BUFFER_SIZE, + &bufferSizeMax ); + + if (bufferSizeMax > bufferSizeMin) + { + /* + * Free and reallocate fbconfigArray, keeping only FBConfigs + * with the largest buffer size. + */ + XFree(fbconfigArray); + + /* Add buffer size token at the end of the list. */ + where--; + ATTRIB_VAL( GLX_BUFFER_SIZE, bufferSizeMax ); + ATTRIB( None ); + + fbconfigArray = glXChooseFBConfig( fgDisplay.Display, + fgDisplay.Screen, + attributes, + &fbconfigArraySize ); + } + } + + /* + * We now have an array of FBConfigs, the first one being the "best" + * one. So we should return only this FBConfig: + * + * int fbconfigXID; + * + * - pick the XID of the FBConfig we want + * result = glXGetFBConfigAttrib( fgDisplay.Display, + * fbconfigArray[0], + * GLX_FBCONFIG_ID, + * &fbconfigXID ); + * + * - free the array + * XFree(fbconfigArray); + * + * - reset "attributes" with the XID + * where = 0; + * ATTRIB_VAL( GLX_FBCONFIG_ID, fbconfigXID ); + * ATTRIB( None ); + * + * - get our FBConfig only + * fbconfig = glXChooseFBConfig( fgDisplay.Display, + * fgDisplay.Screen, + * attributes, + * &fbconfigArraySize ); + * + * However, for some configurations (for instance multisampling with + * Mesa 6.5.2 and ATI drivers), this does not work: + * glXChooseFBConfig returns NULL, whereas fbconfigXID is a valid + * XID. Further investigation is needed. + * + * So, for now, we return the whole array of FBConfigs. This should + * not produce any side effects elsewhere. + */ + fbconfig = fbconfigArray; + } + else + { + fbconfig = NULL; + } + + if (numcfgs) + *numcfgs = fbconfigArraySize; + + return fbconfig; + } +} + + +static void fghFillContextAttributes( int *attributes ) { + int where = 0, contextFlags, contextProfile; + + if ( !fghIsLegacyContextVersionRequested() ) { + ATTRIB_VAL( GLX_CONTEXT_MAJOR_VERSION_ARB, fgState.MajorVersion ); + ATTRIB_VAL( GLX_CONTEXT_MINOR_VERSION_ARB, fgState.MinorVersion ); + } + + contextFlags = + fghMapBit( fgState.ContextFlags, GLUT_DEBUG, GLX_CONTEXT_DEBUG_BIT_ARB ) | + fghMapBit( fgState.ContextFlags, GLUT_FORWARD_COMPATIBLE, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB ); + if ( contextFlags != 0 ) { + ATTRIB_VAL( GLX_CONTEXT_FLAGS_ARB, contextFlags ); + } + + contextProfile = + fghMapBit( fgState.ContextProfile, GLUT_CORE_PROFILE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB ) | + fghMapBit( fgState.ContextProfile, GLUT_COMPATIBILITY_PROFILE, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB ); + if ( contextProfile != 0 ) { + ATTRIB_VAL( GLX_CONTEXT_PROFILE_MASK_ARB, contextProfile ); + } + + ATTRIB( 0 ); +} + +typedef GLXContext (*CreateContextAttribsProc)(Display *dpy, GLXFBConfig config, + GLXContext share_list, Bool direct, + const int *attrib_list); + +static GLXContext fghCreateNewContext( SFG_Window* window ) +{ + /* for color model calculation */ + int menu = ( window->IsMenu && !fgStructure.MenuContext ); + int index_mode = ( fgState.DisplayMode & GLUT_INDEX ); + + /* "classic" context creation */ + Display *dpy = fgDisplay.Display; + GLXFBConfig config = *(window->Window.FBConfig); + int render_type = ( !menu && index_mode ) ? GLX_COLOR_INDEX_TYPE : GLX_RGBA_TYPE; + GLXContext share_list = NULL; + Bool direct = ( fgState.DirectContext != GLUT_FORCE_INDIRECT_CONTEXT ); + GLXContext context; + + /* new context creation */ + int attributes[9]; + CreateContextAttribsProc createContextAttribs = (CreateContextAttribsProc) fghGetProcAddress( "glXCreateContextAttribsARB" ); + + /* glXCreateContextAttribsARB not found, yet the user has requested the new context creation */ + if ( !createContextAttribs && !fghIsLegacyContextRequested() ) { + fgWarning( "OpenGL >2.1 context requested but glXCreateContextAttribsARB is not available! Falling back to legacy context creation" ); + fgState.MajorVersion = 2; + fgState.MinorVersion = 1; + } + + /* If nothing fancy has been required, simply use the old context creation GLX API entry */ + if ( fghIsLegacyContextRequested() || !createContextAttribs ) + { + context = glXCreateNewContext( dpy, config, render_type, share_list, direct ); + if ( context == NULL ) { + fghContextCreationError(); + } + return context; + } + + /* color index mode is not available anymore with OpenGL 3.0 */ + if ( render_type == GLX_COLOR_INDEX_TYPE ) { + fgWarning( "color index mode is deprecated, using RGBA mode" ); + } + + fghFillContextAttributes( attributes ); + + context = createContextAttribs( dpy, config, share_list, direct, attributes ); + if ( context == NULL ) { + fghContextCreationError(); + } + return context; +} + + +#define _NET_WM_STATE_TOGGLE 2 +static int fghResizeFullscrToggle(void) +{ + XWindowAttributes attributes; + + if(glutGet(GLUT_FULL_SCREEN)) { + /* restore original window size */ + SFG_Window *win = fgStructure.CurrentWindow; + fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE; + fgStructure.CurrentWindow->State.Width = win->State.OldWidth; + fgStructure.CurrentWindow->State.Height = win->State.OldHeight; + + } else { + /* resize the window to cover the entire screen */ + XGetWindowAttributes(fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + &attributes); + + /* + * The "x" and "y" members of "attributes" are the window's coordinates + * relative to its parent, i.e. to the decoration window. + */ + XMoveResizeWindow(fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + -attributes.x, + -attributes.y, + fgDisplay.ScreenWidth, + fgDisplay.ScreenHeight); + } + return 0; +} + +static int fghEwmhFullscrToggle(void) +{ + XEvent xev; + long evmask = SubstructureRedirectMask | SubstructureNotifyMask; + + if(!fgDisplay.State || !fgDisplay.StateFullScreen) { + return -1; + } + + xev.type = ClientMessage; + xev.xclient.window = fgStructure.CurrentWindow->Window.Handle; + xev.xclient.message_type = fgDisplay.State; + xev.xclient.format = 32; + xev.xclient.data.l[0] = _NET_WM_STATE_TOGGLE; + xev.xclient.data.l[1] = fgDisplay.StateFullScreen; + xev.xclient.data.l[2] = 0; /* no second property to toggle */ + xev.xclient.data.l[3] = 1; /* source indication: application */ + xev.xclient.data.l[4] = 0; /* unused */ + + if(!XSendEvent(fgDisplay.Display, fgDisplay.RootWindow, 0, evmask, &xev)) { + return -1; + } + return 0; +} + +static int fghToggleFullscreen(void) +{ + /* first try the EWMH (_NET_WM_STATE) method ... */ + if(fghEwmhFullscrToggle() != -1) { + return 0; + } + + /* fall back to resizing the window */ + if(fghResizeFullscrToggle() != -1) { + return 0; + } + return -1; +} + + +#endif /* TARGET_HOST_POSIX_X11 */ + + +#if TARGET_HOST_MS_WINDOWS +/* + * Setup the pixel format for a Win32 window + */ + +#if defined(_WIN32_WCE) +static wchar_t* fghWstrFromStr(const char* str) +{ + int i,len=strlen(str); + wchar_t* wstr = (wchar_t*)malloc(2*len+2); + for(i=0; iWindow.Device, window->Window.Context ); + + if ( !fghIsExtensionSupported( window->Window.Device, "WGL_ARB_create_context" ) ) + { + return; + } + + /* new context creation */ + fghFillContextAttributes( attributes ); + + wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) wglGetProcAddress( "wglCreateContextAttribsARB" ); + if ( wglCreateContextAttribsARB == NULL ) + { + fgError( "wglCreateContextAttribsARB not found" ); + } + + context = wglCreateContextAttribsARB( window->Window.Device, 0, attributes ); + if ( context == NULL ) + { + fghContextCreationError(); + } + + wglMakeCurrent( NULL, NULL ); + wglDeleteContext( window->Window.Context ); + window->Window.Context = context; +} + +#if !defined(_WIN32_WCE) + +static void fghFillPFD( PIXELFORMATDESCRIPTOR *ppfd, HDC hdc, unsigned char layer_type ) +{ + int flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; + if ( fgState.DisplayMode & GLUT_DOUBLE ) { + flags |= PFD_DOUBLEBUFFER; + } + if ( fgState.DisplayMode & GLUT_STEREO ) { + flags |= PFD_STEREO; + } + +#if defined(_MSC_VER) +#pragma message( "fgSetupPixelFormat(): there is still some work to do here!" ) +#endif + + /* Specify which pixel format do we opt for... */ + ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR); + ppfd->nVersion = 1; + ppfd->dwFlags = flags; + + if( fgState.DisplayMode & GLUT_INDEX ) { + ppfd->iPixelType = PFD_TYPE_COLORINDEX; + ppfd->cRedBits = 0; + ppfd->cGreenBits = 0; + ppfd->cBlueBits = 0; + ppfd->cAlphaBits = 0; + } else { + ppfd->iPixelType = PFD_TYPE_RGBA; + ppfd->cRedBits = 8; + ppfd->cGreenBits = 8; + ppfd->cBlueBits = 8; + ppfd->cAlphaBits = ( fgState.DisplayMode & GLUT_ALPHA ) ? 8 : 0; + } + + ppfd->cColorBits = 24; + ppfd->cRedShift = 0; + ppfd->cGreenShift = 0; + ppfd->cBlueShift = 0; + ppfd->cAlphaShift = 0; + ppfd->cAccumBits = ( fgState.DisplayMode & GLUT_ACCUM ) ? 1 : 0; + ppfd->cAccumRedBits = 0; + ppfd->cAccumGreenBits = 0; + ppfd->cAccumBlueBits = 0; + ppfd->cAccumAlphaBits = 0; + + /* Hmmm, or 32/0 instead of 24/8? */ + ppfd->cDepthBits = 24; + ppfd->cStencilBits = 8; + + ppfd->cAuxBuffers = fghNumberOfAuxBuffersRequested(); + ppfd->iLayerType = layer_type; + ppfd->bReserved = 0; + ppfd->dwLayerMask = 0; + ppfd->dwVisibleMask = 0; + ppfd->dwDamageMask = 0; + + ppfd->cColorBits = (BYTE) GetDeviceCaps( hdc, BITSPIXEL ); +} + +static void fghFillPixelFormatAttributes( int *attributes, const PIXELFORMATDESCRIPTOR *ppfd ) +{ + int where = 0; + + ATTRIB_VAL( WGL_DRAW_TO_WINDOW_ARB, GL_TRUE ); + ATTRIB_VAL( WGL_SUPPORT_OPENGL_ARB, GL_TRUE ); + ATTRIB_VAL( WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB ); + + ATTRIB_VAL( WGL_COLOR_BITS_ARB, ppfd->cColorBits ); + ATTRIB_VAL( WGL_ALPHA_BITS_ARB, ppfd->cAlphaBits ); + ATTRIB_VAL( WGL_DEPTH_BITS_ARB, ppfd->cDepthBits ); + ATTRIB_VAL( WGL_STENCIL_BITS_ARB, ppfd->cStencilBits ); + + ATTRIB_VAL( WGL_DOUBLE_BUFFER_ARB, ( fgState.DisplayMode & GLUT_DOUBLE ) != 0 ); + + if ( fgState.DisplayMode & GLUT_SRGB ) { + ATTRIB_VAL( WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, TRUE ); + } + + ATTRIB_VAL( WGL_SAMPLE_BUFFERS_ARB, GL_TRUE ); + ATTRIB_VAL( WGL_SAMPLES_ARB, fgState.SampleNumber ); + ATTRIB( 0 ); +} +#endif + + +/* +void alert(int x){ + static char str[100]; + memset(&str[0],0,100); + sprintf(str, "%d", x); + MessageBox(0,&str[0], "Alert", MB_OK ); +} +*/ + +void alert(char *x){ + MessageBox(0,x, "Alert", MB_OK ); +} + +PIXELFORMATDESCRIPTOR pfd; + +int ChoosePixelFormatEx(HDC hdc,int *p_bpp,int *p_depth,int *p_dbl,int *p_acc) +{ int wbpp; if (p_bpp==NULL) wbpp=-1; else wbpp=*p_bpp; + int wdepth; if (p_depth==NULL) wdepth=16; else wdepth=*p_depth; + int wdbl; if (p_dbl==NULL) wdbl=-1; else wdbl=*p_dbl; + int wacc; if (p_acc==NULL) wacc=1; else wacc=*p_acc; + ZeroMemory(&pfd,sizeof(pfd)); pfd.nSize=sizeof(pfd); pfd.nVersion=1; + int num=DescribePixelFormat(hdc,1,sizeof(pfd),&pfd); + if (num==0) return 0; + unsigned int maxqual=0; int maxindex=0; + int max_bpp, max_depth, max_dbl, max_acc; + int i; + for (i=1; i<=num; i++) + { ZeroMemory(&pfd,sizeof(pfd)); pfd.nSize=sizeof(pfd); pfd.nVersion=1; + DescribePixelFormat(hdc,i,sizeof(pfd),&pfd); + int bpp=pfd.cColorBits; + int depth=pfd.cDepthBits; + int pal=(pfd.iPixelType==PFD_TYPE_COLORINDEX); + int mcd=((pfd.dwFlags & PFD_GENERIC_FORMAT) && (pfd.dwFlags & PFD_GENERIC_ACCELERATED)); + +//if (pfd.dwFlags & PFD_GENERIC_ACCELERATED) alert ("SHEEP!"); +//alert ("SHEEPzzz!"); + + int soft=((pfd.dwFlags & PFD_GENERIC_FORMAT) && !(pfd.dwFlags & PFD_GENERIC_ACCELERATED)); + int icd=(!(pfd.dwFlags & PFD_GENERIC_FORMAT) && !(pfd.dwFlags & PFD_GENERIC_ACCELERATED)); + +//if (icd) alert("icd"); + + int opengl=(pfd.dwFlags & PFD_SUPPORT_OPENGL); + int window=(pfd.dwFlags & PFD_DRAW_TO_WINDOW); + int bitmap=(pfd.dwFlags & PFD_DRAW_TO_BITMAP); + int dbuff=(pfd.dwFlags & PFD_DOUBLEBUFFER); + // + unsigned int q=0; + if (opengl && window) q=q+0x8000; + if (wdepth==-1 || (wdepth>0 && depth>0)) q=q+0x4000; + if (wdbl==-1 || (wdbl==0 && !dbuff) || (wdbl==1 && dbuff)) q=q+0x2000; + if (wacc==-1 || (wacc==0 && soft) || (wacc==1 && (mcd || icd))) q=q+0x1000; + if (mcd || icd) q=q+0x0040; if (icd) q=q+0x0002; + if (wbpp==-1 || (wbpp==bpp)) q=q+0x0800; + if (bpp>=16) q=q+0x0020; if (bpp==16) q=q+0x0008; + if (wdepth==-1 || (wdepth==depth)) q=q+0x0400; + if (depth>=16) q=q+0x0010; if (depth==16) q=q+0x0004; + if (!pal) q=q+0x0080; + if (bitmap) q=q+0x0001; + if (q>maxqual) {maxqual=q; maxindex=i;max_bpp=bpp; max_depth=depth; max_dbl=dbuff?1:0; max_acc=soft?0:1;} + } + if (maxindex==0) return maxindex; + if (p_bpp!=NULL) *p_bpp=max_bpp; + if (p_depth!=NULL) *p_depth=max_depth; + if (p_dbl!=NULL) *p_dbl=max_dbl; + if (p_acc!=NULL) *p_acc=max_acc; + DescribePixelFormat(hdc,maxindex,sizeof(pfd),&pfd); + return maxindex; +} + + +GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly, + unsigned char layer_type ) +{ +#if defined(_WIN32_WCE) + return GL_TRUE; +#else + ////PIXELFORMATDESCRIPTOR pfd; + PIXELFORMATDESCRIPTOR* ppfd = &pfd; + int pixelformat; + HDC current_hDC; + GLboolean success; + + if (checkOnly) + current_hDC = CreateDC(TEXT("DISPLAY"), NULL ,NULL ,NULL); + else + current_hDC = window->Window.Device; + + fghFillPFD( ppfd, current_hDC, layer_type ); + + //pfd.dwFlags|=PFD_SUPPORT_OPENGL; + + +//pfd.dwFlags + + pixelformat = ChoosePixelFormat( current_hDC, ppfd ); + +// int icd=(!(pfd.dwFlags & PFD_GENERIC_FORMAT) && !(pfd.dwFlags & PFD_GENERIC_ACCELERATED)); +// if (icd) alert("icd"); + + + + +/* + int bpp2=-1; // don't care. (or a positive integer) + int depth2=-1; // don't care. (or a positive integer) + int dbl2=1; // we want double-buffering. (or -1 for 'don't care', or 0 for 'none') + int acc2=1; // we want acceleration. (or -1 or 0) +*/ + +// hWnd = CreateWindow("OpenGL", title, WS_OVERLAPPEDWINDOW | +// WS_CLIPSIBLINGS | WS_CLIPCHILDREN, +// x, y, width, height, NULL, NULL, hInstance, NULL); + + +// HWND hWndx=CreateWindow(_T("FREEGLUT_dummy2"), _T(""), WS_OVERLAPPEDWINDOW , 0,0,800,600, 0, 0, fgDisplay.Instance, 0 ); + // current_hDC=GetDC(hWndx); + + +// pixelformat=ChoosePixelFormatEx(current_hDC,&bpp2,&depth2,&dbl2,&acc2); +/* +if (pfd.dwFlags&PFD_SUPPORT_OPENGL) alert("HIPPO!"); +if (pfd.dwFlags&PFD_GENERIC_ACCELERATED) alert("cheetah!"); +if (pixelformat==0) alert("noooo!"); +if (acc2) alert("acc!"); +*/ + + /* windows hack for multisampling/sRGB */ + if ( ( fgState.DisplayMode & GLUT_MULTISAMPLE ) || + ( fgState.DisplayMode & GLUT_SRGB ) ) + { + + HGLRC rc, rc_before=wglGetCurrentContext(); + HWND hWnd; + HDC hDC, hDC_before=wglGetCurrentDC(); + WNDCLASS wndCls; + + /* create a dummy window */ + ZeroMemory(&wndCls, sizeof(wndCls)); + wndCls.lpfnWndProc = DefWindowProc; + wndCls.hInstance = fgDisplay.Instance; + wndCls.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; + wndCls.lpszClassName = _T("FREEGLUT_dummy"); + RegisterClass( &wndCls ); + + hWnd=CreateWindow(_T("FREEGLUT_dummy"), _T(""), WS_CLIPSIBLINGS | WS_CLIPCHILDREN | ((WS_OVERLAPPEDWINDOW*QB64_Resizable())|WS_DLGFRAME|WS_BORDER|WS_SYSMENU|WS_MINIMIZEBOX|(WS_MAXIMIZEBOX*QB64_Resizable())) , 0,0,0,0, 0, 0, fgDisplay.Instance, 0 ); + hDC=GetDC(hWnd); + SetPixelFormat( hDC, pixelformat, ppfd ); + + rc = wglCreateContext( hDC ); + wglMakeCurrent(hDC, rc); + + if ( fghIsExtensionSupported( hDC, "WGL_ARB_multisample" ) ) + { + PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARBProc = + (PFNWGLCHOOSEPIXELFORMATARBPROC) wglGetProcAddress("wglChoosePixelFormatARB"); + if ( wglChoosePixelFormatARBProc ) + { + int attributes[100]; + int iPixelFormat; + BOOL bValid; + float fAttributes[] = { 0, 0 }; + UINT numFormats; + fghFillPixelFormatAttributes( attributes, ppfd ); + bValid = wglChoosePixelFormatARBProc(hDC, attributes, fAttributes, 1, &iPixelFormat, &numFormats); + + if ( bValid && numFormats > 0 ) + { + pixelformat = iPixelFormat; + } + } + } + + wglMakeCurrent( hDC_before, rc_before); + wglDeleteContext(rc); + ReleaseDC(hWnd, hDC); + DestroyWindow(hWnd); + UnregisterClass(_T("FREEGLUT_dummy"), fgDisplay.Instance); + } + + success = ( pixelformat != 0 ) && ( checkOnly || SetPixelFormat( current_hDC, pixelformat, ppfd ) ); + + if (checkOnly) + DeleteDC(current_hDC); + + return success; +#endif /* defined(_WIN32_WCE) */ +} + +#endif /* TARGET_HOST_MS_WINDOWS */ + +/* + * Sets the OpenGL context and the fgStructure "Current Window" pointer to + * the window structure passed in. + */ +void fgSetWindow ( SFG_Window *window ) +{ +#if TARGET_HOST_POSIX_X11 + if ( window ) + { + glXMakeContextCurrent( + fgDisplay.Display, + window->Window.Handle, + window->Window.Handle, + window->Window.Context + ); + } +#elif TARGET_HOST_MS_WINDOWS + if ( window != fgStructure.CurrentWindow ) + { + if( fgStructure.CurrentWindow ) + ReleaseDC( fgStructure.CurrentWindow->Window.Handle, + fgStructure.CurrentWindow->Window.Device ); + + if ( window ) + { + window->Window.Device = GetDC( window->Window.Handle ); + wglMakeCurrent( + window->Window.Device, + window->Window.Context + ); + } + } +#endif + fgStructure.CurrentWindow = window; +} + +#if TARGET_HOST_MS_WINDOWS + +/* Computes position of corners of window Rect (outer position including + * decorations) based on the provided client rect and based on the style + * of the window in question. + * If posIsOutside is set to true, the input client Rect is taken to follow + * freeGLUT's window specification convention in which the top-left corner + * is at the outside of the window, while the size + * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable + * area. + */ +void fghComputeWindowRectFromClientArea_UseStyle( const DWORD windowStyle, RECT *clientRect, BOOL posIsOutside ) +{ + RECT windowRect = {0, 0, 0, 0}; + DWORD windowExStyle = 0; + + CopyRect(&windowRect, clientRect); + + /* Get rect including non-client area */ + AdjustWindowRectEx(&windowRect, windowStyle, FALSE, windowExStyle); + + /* Move window right and down by non-client area extent on left and top, if wanted */ + if (posIsOutside) { + windowRect.right += clientRect->left - windowRect.left; + windowRect.bottom += clientRect->top - windowRect.top; + windowRect.left = clientRect->left; + windowRect.top = clientRect->top; + } + + /* done, copy windowRect to output */ + CopyRect(clientRect, &windowRect); +} + +/* Computes position of corners of window Rect (outer position including + * decorations) based on the provided client rect and based on the style + * of the window in question. If the window pointer or the window handle + * is NULL, a fully decorated window (caption and border) is assumed. + * Furthermore, if posIsOutside is set to true, the input client Rect is + * taken to follow freeGLUT's window specification convention in which the + * top-left corner is at the outside of the window, while the size + * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable + * area. +*/ +void fghComputeWindowRectFromClientArea_QueryWindow( const SFG_Window *window, RECT *clientRect, BOOL posIsOutside ) +{ + DWORD windowStyle = 0; + + if (window && window->Window.Handle) + windowStyle = GetWindowLong(window->Window.Handle, GWL_STYLE); + else + windowStyle = ((WS_OVERLAPPEDWINDOW*QB64_Resizable())|WS_DLGFRAME|WS_BORDER|WS_SYSMENU|WS_MINIMIZEBOX|(WS_MAXIMIZEBOX*QB64_Resizable())); + + fghComputeWindowRectFromClientArea_UseStyle(windowStyle, clientRect, posIsOutside); +} + +/* Computes position of corners of client area (drawable area) of a window + * based on the provided window Rect (outer position including decorations) + * and based on the style of the window in question. If the window pointer + * or the window handle is NULL, a fully decorated window (caption and + * border) is assumed. + * Furthermore, if wantPosOutside is set to true, the output client Rect + * will follow freeGLUT's window specification convention in which the + * top-left corner is at the outside of the window, the size + * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable + * area. + */ +void fghComputeClientAreaFromWindowRect( const SFG_Window *window, RECT *windowRect, BOOL wantPosOutside ) +{ + DWORD windowStyle = 0; + int xBorderWidth = 0, yBorderWidth = 0; + + if (window && window->Window.Handle) + windowStyle = GetWindowLong(window->Window.Handle, GWL_STYLE); + else + windowStyle = ((WS_OVERLAPPEDWINDOW*QB64_Resizable())|WS_DLGFRAME|WS_BORDER|WS_SYSMENU|WS_MINIMIZEBOX|(WS_MAXIMIZEBOX*QB64_Resizable())); + + /* If window has title bar, correct rect for it */ + if (windowStyle & WS_SYSMENU) /* Need to query for WS_SYSMENU to see if we have a title bar, the WS_CAPTION query is also true for a WS_DLGFRAME only... */ + if (wantPosOutside) + windowRect->bottom -= GetSystemMetrics( SM_CYCAPTION ); + else + windowRect->top += GetSystemMetrics( SM_CYCAPTION ); + + /* get width of window's borders (frame), correct rect for it. + * Note, borders can be of zero width if style does not specify borders + */ + fghGetBorderWidth(windowStyle, &xBorderWidth, &yBorderWidth); + if (wantPosOutside) + { + windowRect->right -= xBorderWidth * 2; + windowRect->bottom -= yBorderWidth * 2; + } + else + { + windowRect->left += xBorderWidth; + windowRect->right -= xBorderWidth; + windowRect->top += yBorderWidth; + windowRect->bottom -= yBorderWidth; + } +} + +/* Gets the rect describing the client area (drawable area) of the + * specified window. + * Returns an empty rect if window pointer or window handle is NULL. + * If wantPosOutside is set to true, the output client Rect + * will follow freeGLUT's window specification convention in which the + * top-left corner is at the outside of the window, while the size + * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable + * area. + */ +RECT fghGetClientArea( const SFG_Window *window, BOOL wantPosOutside ) +{ + RECT windowRect = {0,0,0,0}; + + freeglut_return_val_if_fail((window && window->Window.Handle),windowRect); + + /* + * call GetWindowRect() + * (this returns the pixel coordinates of the outside of the window) + */ + GetWindowRect( window->Window.Handle, &windowRect ); + + /* Then correct the results */ + fghComputeClientAreaFromWindowRect(window, &windowRect, wantPosOutside); + + return windowRect; +} + +/* Returns the width of the window borders based on the window's style. + */ +void fghGetBorderWidth(const DWORD windowStyle, int* xBorderWidth, int* yBorderWidth) +{ + if (windowStyle & WS_THICKFRAME) + { + *xBorderWidth = GetSystemMetrics(SM_CXSIZEFRAME); + *yBorderWidth = GetSystemMetrics(SM_CYSIZEFRAME); + } + else if (windowStyle & WS_DLGFRAME) + { + *xBorderWidth = GetSystemMetrics(SM_CXFIXEDFRAME); + *yBorderWidth = GetSystemMetrics(SM_CYFIXEDFRAME); + } + else + { + *xBorderWidth = 0; + *yBorderWidth = 0; + } +} + +#if(WINVER >= 0x500) +typedef struct +{ + int *x; + int *y; + const char *name; +} m_proc_t; + +static BOOL CALLBACK m_proc(HMONITOR mon, + HDC hdc, + LPRECT rect, + LPARAM data) +{ + m_proc_t *dp=(m_proc_t *)data; + MONITORINFOEX info; + BOOL res; + info.cbSize=sizeof(info); + res=GetMonitorInfo(mon,(LPMONITORINFO)&info); + if( res ) + { + if( strcmp(dp->name,info.szDevice)==0 ) + { + *(dp->x)=info.rcMonitor.left; + *(dp->y)=info.rcMonitor.top; + return FALSE; + } + } + return TRUE; +} + +/* + * this function returns the origin of the screen identified by + * fgDisplay.DisplayName, and 0 otherwise. + * This is used in fgOpenWindow to open the gamemode window on the screen + * identified by the -display command line argument. The function should + * not be called otherwise. + */ + +static void get_display_origin(int *xp,int *yp) +{ + *xp = 0; + *yp = 0; + + if( fgDisplay.DisplayName ) + { + m_proc_t st; + st.x=xp; + st.y=yp; + st.name=fgDisplay.DisplayName; + EnumDisplayMonitors(0,0,m_proc,(LPARAM)&st); + } +} +#else +#pragma message( "-display parameter only works if compiled with WINVER >= 0x0500") + +static void get_display_origin(int *xp,int *yp) +{ + *xp = 0; + *yp = 0; + + if( fgDisplay.DisplayName ) + { + fgWarning( "for working -display support FreeGLUT must be compiled with WINVER >= 0x0500"); + } +} +#endif +#endif + + +#if TARGET_HOST_POSIX_X11 +static Bool fghWindowIsVisible( Display *display, XEvent *event, XPointer arg) +{ + Window window = (Window)arg; + return (event->type == MapNotify) && (event->xmap.window == window); +} +#endif + + +/* + * Opens a window. Requires a SFG_Window object created and attached + * to the freeglut structure. OpenGL context is created here. + */ +void fgOpenWindow( SFG_Window* window, const char* title, + GLboolean positionUse, int x, int y, + GLboolean sizeUse, int w, int h, + GLboolean gameMode, GLboolean isSubWindow ) +{ +#if TARGET_HOST_POSIX_X11 + XVisualInfo * visualInfo = NULL; + XSetWindowAttributes winAttr; + XTextProperty textProperty; + XSizeHints sizeHints; + XWMHints wmHints; + XEvent eventReturnBuffer; /* return buffer required for a call */ + unsigned long mask; + int num_FBConfigs, i; + unsigned int current_DisplayMode = fgState.DisplayMode ; + + /* Save the display mode if we are creating a menu window */ + if( window->IsMenu && ( ! fgStructure.MenuContext ) ) + fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB ; + + window->Window.FBConfig = fgChooseFBConfig( &num_FBConfigs ); + + if( window->IsMenu && ( ! fgStructure.MenuContext ) ) + fgState.DisplayMode = current_DisplayMode ; + + if( ! window->Window.FBConfig ) + { + /* + * The "fgChooseFBConfig" returned a null meaning that the visual + * context is not available. + * Try a couple of variations to see if they will work. + */ + if( !( fgState.DisplayMode & GLUT_DOUBLE ) ) + { + fgState.DisplayMode |= GLUT_DOUBLE ; + window->Window.FBConfig = fgChooseFBConfig( &num_FBConfigs ); + fgState.DisplayMode &= ~GLUT_DOUBLE; + } + + if( fgState.DisplayMode & GLUT_MULTISAMPLE ) + { + fgState.DisplayMode &= ~GLUT_MULTISAMPLE ; + window->Window.FBConfig = fgChooseFBConfig( &num_FBConfigs ); + fgState.DisplayMode |= GLUT_MULTISAMPLE; + } + } + + FREEGLUT_INTERNAL_ERROR_EXIT( window->Window.FBConfig != NULL, + "FBConfig with necessary capabilities not found", "fgOpenWindow" ); + + /* Get the X visual. */ + for (i = 0; i < num_FBConfigs; i++) { + visualInfo = glXGetVisualFromFBConfig( fgDisplay.Display, + window->Window.FBConfig[i] ); + if (visualInfo) + break; + } + + FREEGLUT_INTERNAL_ERROR_EXIT( visualInfo != NULL, + "visualInfo could not be retrieved from FBConfig", "fgOpenWindow" ); + + /* + * XXX HINT: the masks should be updated when adding/removing callbacks. + * XXX This might speed up message processing. Is that true? + * XXX + * XXX A: Not appreciably, but it WILL make it easier to debug. + * XXX Try tracing old GLUT and try tracing freeglut. Old GLUT + * XXX turns off events that it doesn't need and is a whole lot + * XXX more pleasant to trace. (Think mouse-motion! Tons of + * XXX ``bonus'' GUI events stream in.) + */ + winAttr.event_mask = + StructureNotifyMask | SubstructureNotifyMask | ExposureMask | + ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | + VisibilityChangeMask | EnterWindowMask | LeaveWindowMask | + PointerMotionMask | ButtonMotionMask; + winAttr.background_pixmap = None; + winAttr.background_pixel = 0; + winAttr.border_pixel = 0; + + winAttr.colormap = XCreateColormap( + fgDisplay.Display, fgDisplay.RootWindow, + visualInfo->visual, AllocNone + ); + + mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask; + + if( window->IsMenu || ( gameMode == GL_TRUE ) ) + { + winAttr.override_redirect = True; + mask |= CWOverrideRedirect; + } + + if( ! positionUse ) + x = y = -1; /* default window position */ + if( ! sizeUse ) + w = h = 300; /* default window size */ + + window->Window.Handle = XCreateWindow( + fgDisplay.Display, + window->Parent == NULL ? fgDisplay.RootWindow : + window->Parent->Window.Handle, + x, y, w, h, 0, + visualInfo->depth, InputOutput, + visualInfo->visual, mask, + &winAttr + ); + + /* + * The GLX context creation, possibly trying the direct context rendering + * or else use the current context if the user has so specified + */ + + if( window->IsMenu ) + { + /* + * If there isn't already an OpenGL rendering context for menu + * windows, make one + */ + if( !fgStructure.MenuContext ) + { + fgStructure.MenuContext = + (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) ); + fgStructure.MenuContext->MContext = fghCreateNewContext( window ); + } + + /* window->Window.Context = fgStructure.MenuContext->MContext; */ + window->Window.Context = fghCreateNewContext( window ); + } + else if( fgState.UseCurrentContext ) + { + window->Window.Context = glXGetCurrentContext( ); + + if( ! window->Window.Context ) + window->Window.Context = fghCreateNewContext( window ); + } + else + window->Window.Context = fghCreateNewContext( window ); + +#if !defined( __FreeBSD__ ) && !defined( __NetBSD__ ) + if( !glXIsDirect( fgDisplay.Display, window->Window.Context ) ) + { + if( fgState.DirectContext == GLUT_FORCE_DIRECT_CONTEXT ) + fgError( "Unable to force direct context rendering for window '%s'", + title ); + } +#endif + + /* + * XXX Assume the new window is visible by default + * XXX Is this a safe assumption? + */ + window->State.Visible = GL_TRUE; + + sizeHints.flags = 0; + if ( positionUse ) + sizeHints.flags |= USPosition; + if ( sizeUse ) + sizeHints.flags |= USSize; + + /* + * Fill in the size hints values now (the x, y, width and height + * settings are obsolete, are there any more WMs that support them?) + * Unless the X servers actually stop supporting these, we should + * continue to fill them in. It is *not* our place to tell the user + * that they should replace a window manager that they like, and which + * works, just because *we* think that it's not "modern" enough. + */ + sizeHints.x = x; + sizeHints.y = y; + sizeHints.width = w; + sizeHints.height = h; + + wmHints.flags = StateHint; + wmHints.initial_state = fgState.ForceIconic ? IconicState : NormalState; + /* Prepare the window and iconified window names... */ + XStringListToTextProperty( (char **) &title, 1, &textProperty ); + + XSetWMProperties( + fgDisplay.Display, + window->Window.Handle, + &textProperty, + &textProperty, + 0, + 0, + &sizeHints, + &wmHints, + NULL + ); + XFree( textProperty.value ); + + XSetWMProtocols( fgDisplay.Display, window->Window.Handle, + &fgDisplay.DeleteWindow, 1 ); + + glXMakeContextCurrent( + fgDisplay.Display, + window->Window.Handle, + window->Window.Handle, + window->Window.Context + ); + + /* register extension events _before_ window is mapped */ + #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H + fgRegisterDevices( fgDisplay.Display, &(window->Window.Handle) ); + #endif + + XMapWindow( fgDisplay.Display, window->Window.Handle ); + + XFree(visualInfo); + + if( !isSubWindow) + XPeekIfEvent( fgDisplay.Display, &eventReturnBuffer, &fghWindowIsVisible, (XPointer)(window->Window.Handle) ); + +#elif TARGET_HOST_MS_WINDOWS + + WNDCLASS wc; + DWORD flags = 0; + DWORD exFlags = 0; + ATOM atom; + + /* Grab the window class we have registered on glutInit(): */ + atom = GetClassInfo( fgDisplay.Instance, _T("FREEGLUT"), &wc ); + FREEGLUT_INTERNAL_ERROR_EXIT ( atom, "Window Class Info Not Found", + "fgOpenWindow" ); + + /* Determine window style flags*/ + if( gameMode ) + { + FREEGLUT_INTERNAL_ERROR_EXIT ( window->Parent == NULL, + "Game mode being invoked on a subwindow", + "fgOpenWindow" ); + + /* + * Set the window creation flags appropriately to make the window + * entirely visible: + */ + flags = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE; + } + else + { + flags = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; + + /* + * There's a small difference between creating the top, child and + * menu windows + */ + if ( window->IsMenu ) + { + flags |= WS_POPUP; + exFlags |= WS_EX_TOOLWINDOW; + } +#if defined(_WIN32_WCE) + /* no decorations for windows CE */ +#else + /* if this is not a subwindow (child), set its style based on the requested display mode */ + else if( window->Parent == NULL ) + if ( fgState.DisplayMode & GLUT_BORDERLESS ) + { + /* no window decorations needed */ + } + else if ( fgState.DisplayMode & GLUT_CAPTIONLESS ) + /* only window decoration is a border, no title bar or buttons */ + flags |= WS_DLGFRAME; + else + /* window decoration are a border, title bar and buttons. + * NB: we later query whether the window has a title bar or + * not by testing for the maximize button, as the test for + * WS_CAPTION can be true without the window having a title + * bar. This style ((WS_OVERLAPPEDWINDOW*QB64_Resizable())|WS_DLGFRAME|WS_BORDER|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX) gives you a maximize + * button. */ + flags |= ((WS_OVERLAPPEDWINDOW*QB64_Resizable())|WS_DLGFRAME|WS_BORDER|WS_SYSMENU|WS_MINIMIZEBOX|(WS_MAXIMIZEBOX*QB64_Resizable())); +#endif + else + /* subwindows always have no decoration, but are marked as a child window to the OS */ + flags |= WS_CHILD; + } + + /* determine window size and position */ + if( gameMode ) + { + /* if in gamemode, query the origin of specified by the -display + * command line parameter (if any) and offset the upper-left corner + * of the window so we create the window on that screen. + * The -display argument doesn't do anything if not trying to enter + * gamemode. + */ + int xoff=0, yoff=0; + get_display_origin(&xoff,&yoff); + x += xoff; + y += yoff; + } + if( !positionUse ) + { + x = CW_USEDEFAULT; + y = CW_USEDEFAULT; + } + if( !sizeUse ) + { + if( ! window->IsMenu ) + { + w = CW_USEDEFAULT; + h = CW_USEDEFAULT; + } + else /* fail safe - Windows can make a window of size (0, 0) */ + w = h = 300; /* default window size */ + } + /* store requested client area width and height */ + window->State.Width = w; + window->State.Height = h; + +#if !defined(_WIN32_WCE) /* no decorations for windows CE */ + if( sizeUse ) + { + RECT windowRect; + /* + * Update the window dimensions, taking the window decorations + * into account. FreeGLUT is to create the window with the + * topleft outside corner at (x,y) and with client area + * dimensions (w,h). + * note: don't need to do this when w=h=CW_USEDEFAULT, so in the + * if( sizeUse ) here is convenient. + */ + windowRect.left = x; + windowRect.top = y; + windowRect.right = x+w; + windowRect.bottom = y+h; + + fghComputeWindowRectFromClientArea_UseStyle(flags,&windowRect,TRUE); + + w = windowRect.right - windowRect.left; + h = windowRect.bottom- windowRect.top; + } +#endif /* !defined(_WIN32_WCE) */ + +#if defined(_WIN32_WCE) + { + wchar_t* wstr = fghWstrFromStr(title); + + window->Window.Handle = CreateWindow( + _T("FREEGLUT"), + wstr, + WS_VISIBLE | WS_POPUP, + 0,0, 240,320, + NULL, + NULL, + fgDisplay.Instance, + (LPVOID) window + ); + + free(wstr); + + SHFullScreen(window->Window.Handle, SHFS_HIDESTARTICON); + SHFullScreen(window->Window.Handle, SHFS_HIDESIPBUTTON); + SHFullScreen(window->Window.Handle, SHFS_HIDETASKBAR); + MoveWindow(window->Window.Handle, 0, 0, 240, 320, TRUE); + ShowWindow(window->Window.Handle, SW_SHOW); + UpdateWindow(window->Window.Handle); + } +#else + window->Window.Handle = CreateWindowEx( + exFlags, + _T("FREEGLUT"), + title, + flags, + x, y, w, h, + (HWND) window->Parent == NULL ? NULL : window->Parent->Window.Handle, + (HMENU) NULL, + fgDisplay.Instance, + (LPVOID) window + ); +#endif /* defined(_WIN32_WCE) */ + + if( !( window->Window.Handle ) ) + fgError( "Failed to create a window (%s)!", title ); + +//QB64 +QB64_Window_Handle((void*)window->Window.Handle); + +#if !defined(_WIN32_WCE) + /* Need to set requested style again, apparently Windows doesn't listen when requesting windows without title bar or borders */ + SetWindowLong(window->Window.Handle, GWL_STYLE, flags); + SetWindowPos(window->Window.Handle, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); +#endif /* defined(_WIN32_WCE) */ + + /* Make a menu window always on top - fix Feature Request 947118 */ + if( window->IsMenu || gameMode ) + SetWindowPos( + window->Window.Handle, + HWND_TOPMOST, + 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE + ); + + /* Enable multitouch: additional flag TWF_FINETOUCH, TWF_WANTPALM */ + #ifdef WM_TOUCH + if (fghRegisterTouchWindow == (pRegisterTouchWindow)0xDEADBEEF) + fghRegisterTouchWindow = (pRegisterTouchWindow)GetProcAddress(GetModuleHandle("user32"),"RegisterTouchWindow"); + if (fghRegisterTouchWindow) + fghRegisterTouchWindow( window->Window.Handle, TWF_FINETOUCH | TWF_WANTPALM ); + #endif + +#if defined(_WIN32_WCE) + ShowWindow( window->Window.Handle, SW_SHOW ); +#else + ShowWindow( window->Window.Handle, + fgState.ForceIconic ? SW_SHOWMINIMIZED : SW_SHOW ); +#endif /* defined(_WIN32_WCE) */ + + UpdateWindow( window->Window.Handle ); + ShowCursor( TRUE ); /* XXX Old comments say "hide cursor"! */ + +#endif + + fgSetWindow( window ); + + window->Window.DoubleBuffered = + ( fgState.DisplayMode & GLUT_DOUBLE ) ? 1 : 0; + + if ( ! window->Window.DoubleBuffered ) + { + glDrawBuffer ( GL_FRONT ); + glReadBuffer ( GL_FRONT ); + } +} + +/* + * Closes a window, destroying the frame and OpenGL context + */ +void fgCloseWindow( SFG_Window* window ) +{ + /* if we're in gamemode and we're closing the gamemode window, + * call glutLeaveGameMode first to make sure the gamemode is + * properly closed before closing the window + */ + if (fgStructure.GameModeWindow != NULL && fgStructure.GameModeWindow->ID==window->ID) + glutLeaveGameMode(); + +#if TARGET_HOST_POSIX_X11 + + if( window->Window.Context ) + glXDestroyContext( fgDisplay.Display, window->Window.Context ); + XFree( window->Window.FBConfig ); + + if( window->Window.Handle ) { + XDestroyWindow( fgDisplay.Display, window->Window.Handle ); + } + /* XFlush( fgDisplay.Display ); */ /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS + + /* Make sure we don't close a window with current context active */ + if( fgStructure.CurrentWindow == window ) + wglMakeCurrent( NULL, NULL ); + + /* + * Step through the list of windows. If the rendering context + * is not being used by another window, then we delete it. + */ + { + int used = FALSE ; + SFG_Window *iter ; + + for( iter = (SFG_Window *)fgStructure.Windows.First; + iter; + iter = (SFG_Window *)iter->Node.Next ) + { + if( ( iter->Window.Context == window->Window.Context ) && + ( iter != window ) ) + used = TRUE; + } + + if( ! used ) + wglDeleteContext( window->Window.Context ); + } + + DestroyWindow( window->Window.Handle ); +#endif +} + + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * Creates a new top-level freeglut window + */ +int FGAPIENTRY glutCreateWindow( const char* title ) +{ + /* XXX GLUT does not exit; it simply calls "glutInit" quietly if the + * XXX application has not already done so. The "freeglut" community + * XXX decided not to go this route (freeglut-developer e-mail from + * XXX Steve Baker, 12/16/04, 4:22 PM CST, "Re: [Freeglut-developer] + * XXX Desired 'freeglut' behaviour when there is no current window" + */ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateWindow" ); + + return fgCreateWindow( NULL, title, fgState.Position.Use, + fgState.Position.X, fgState.Position.Y, + fgState.Size.Use, fgState.Size.X, fgState.Size.Y, + GL_FALSE, GL_FALSE )->ID; +} + +#if TARGET_HOST_MS_WINDOWS +int FGAPIENTRY __glutCreateWindowWithExit( const char *title, void (__cdecl *exit_function)(int) ) +{ + __glutExitFunc = exit_function; + return glutCreateWindow( title ); +} +#endif + +/* + * This function creates a sub window. + */ +int FGAPIENTRY glutCreateSubWindow( int parentID, int x, int y, int w, int h ) +{ + int ret = 0; + SFG_Window* window = NULL; + SFG_Window* parent = NULL; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateSubWindow" ); + parent = fgWindowByID( parentID ); + freeglut_return_val_if_fail( parent != NULL, 0 ); + if ( x < 0 ) + { + x = parent->State.Width + x ; + if ( w >= 0 ) x -= w ; + } + + if ( w < 0 ) w = parent->State.Width - x + w ; + if ( w < 0 ) + { + x += w ; + w = -w ; + } + + if ( y < 0 ) + { + y = parent->State.Height + y ; + if ( h >= 0 ) y -= h ; + } + + if ( h < 0 ) h = parent->State.Height - y + h ; + if ( h < 0 ) + { + y += h ; + h = -h ; + } + + window = fgCreateWindow( parent, "", GL_TRUE, x, y, GL_TRUE, w, h, GL_FALSE, GL_FALSE ); + ret = window->ID; + + return ret; +} + +/* + * Destroys a window and all of its subwindows + */ +void FGAPIENTRY glutDestroyWindow( int windowID ) +{ + SFG_Window* window; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDestroyWindow" ); + window = fgWindowByID( windowID ); + freeglut_return_if_fail( window != NULL ); + { + fgExecutionState ExecState = fgState.ExecState; + fgAddToWindowDestroyList( window ); + fgState.ExecState = ExecState; + } +} + +/* + * This function selects the current window + */ +void FGAPIENTRY glutSetWindow( int ID ) +{ + SFG_Window* window = NULL; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindow" ); + if( fgStructure.CurrentWindow != NULL ) + if( fgStructure.CurrentWindow->ID == ID ) + return; + + window = fgWindowByID( ID ); + if( window == NULL ) + { + fgWarning( "glutSetWindow(): window ID %d not found!", ID ); + return; + } + + fgSetWindow( window ); +} + +/* + * This function returns the ID number of the current window, 0 if none exists + */ +int FGAPIENTRY glutGetWindow( void ) +{ + SFG_Window *win = fgStructure.CurrentWindow; + /* + * Since GLUT did not throw an error if this function was called without a prior call to + * "glutInit", this function shouldn't do so here. Instead let us return a zero. + * See Feature Request "[ 1307049 ] glutInit check". + */ + if ( ! fgState.Initialised ) + return 0; + + while ( win && win->IsMenu ) + win = win->Parent; + return win ? win->ID : 0; +} + +/* + * This function makes the current window visible + */ +void FGAPIENTRY glutShowWindow( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutShowWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutShowWindow" ); + +#if TARGET_HOST_POSIX_X11 + + XMapWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle ); + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS + + ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_SHOW ); + +#endif + + fgStructure.CurrentWindow->State.Redisplay = GL_TRUE; +} + +/* + * This function hides the current window + */ +void FGAPIENTRY glutHideWindow( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutHideWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutHideWindow" ); + +#if TARGET_HOST_POSIX_X11 + + if( fgStructure.CurrentWindow->Parent == NULL ) + XWithdrawWindow( fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + fgDisplay.Screen ); + else + XUnmapWindow( fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle ); + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS + + ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_HIDE ); + +#endif + + fgStructure.CurrentWindow->State.Redisplay = GL_FALSE; +} + +/* + * Iconify the current window (top-level windows only) + */ +void FGAPIENTRY glutIconifyWindow( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIconifyWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutIconifyWindow" ); + + fgStructure.CurrentWindow->State.Visible = GL_FALSE; +#if TARGET_HOST_POSIX_X11 + + XIconifyWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle, + fgDisplay.Screen ); + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS + + ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_MINIMIZE ); + +#endif + + fgStructure.CurrentWindow->State.Redisplay = GL_FALSE; +} + +/* + * Set the current window's title + */ +void FGAPIENTRY glutSetWindowTitle( const char* title ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowTitle" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowTitle" ); + if( ! fgStructure.CurrentWindow->Parent ) + { +#if TARGET_HOST_POSIX_X11 + + XTextProperty text; + + text.value = (unsigned char *) title; + text.encoding = XA_STRING; + text.format = 8; + text.nitems = strlen( title ); + + XSetWMName( + fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + &text + ); + + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS +# ifdef _WIN32_WCE + { + wchar_t* wstr = fghWstrFromStr(title); + SetWindowText( fgStructure.CurrentWindow->Window.Handle, wstr ); + free(wstr); + } +# else + SetWindowText( fgStructure.CurrentWindow->Window.Handle, title ); +# endif + +#endif + } +} + +/* + * Set the current window's iconified title + */ +void FGAPIENTRY glutSetIconTitle( const char* title ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetIconTitle" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetIconTitle" ); + + if( ! fgStructure.CurrentWindow->Parent ) + { +#if TARGET_HOST_POSIX_X11 + + XTextProperty text; + + text.value = (unsigned char *) title; + text.encoding = XA_STRING; + text.format = 8; + text.nitems = strlen( title ); + + XSetWMIconName( + fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + &text + ); + + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS +# ifdef _WIN32_WCE + { + wchar_t* wstr = fghWstrFromStr(title); + SetWindowText( fgStructure.CurrentWindow->Window.Handle, wstr ); + free(wstr); + } +# else + SetWindowText( fgStructure.CurrentWindow->Window.Handle, title ); +# endif + +#endif + } +} + +/* + * Change the current window's size + */ +void FGAPIENTRY glutReshapeWindow( int width, int height ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutReshapeWindow" ); + + if (glutGet(GLUT_FULL_SCREEN)) + { + /* Leave full screen state before resizing. */ + glutLeaveFullScreen(); + } + + fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE; + fgStructure.CurrentWindow->State.Width = width ; + fgStructure.CurrentWindow->State.Height = height; +} + +/* + * Change the current window's position + */ +void FGAPIENTRY glutPositionWindow( int x, int y ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPositionWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPositionWindow" ); + + if (glutGet(GLUT_FULL_SCREEN)) + { + /* Leave full screen state before moving. */ + glutLeaveFullScreen(); + } + +#if TARGET_HOST_POSIX_X11 + + XMoveWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle, + x, y ); + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS + + { + RECT winRect; + + /* "GetWindowRect" returns the pixel coordinates of the outside of the window */ + GetWindowRect( fgStructure.CurrentWindow->Window.Handle, &winRect ); + MoveWindow( + fgStructure.CurrentWindow->Window.Handle, + x, + y, + winRect.right - winRect.left, + winRect.bottom - winRect.top, + TRUE + ); + } + +#endif +} + +/* + * Lowers the current window (by Z order change) + */ +void FGAPIENTRY glutPushWindow( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPushWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPushWindow" ); + +#if TARGET_HOST_POSIX_X11 + + XLowerWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle ); + +#elif TARGET_HOST_MS_WINDOWS + + SetWindowPos( + fgStructure.CurrentWindow->Window.Handle, + HWND_BOTTOM, + 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE + ); + +#endif +} + +/* + * Raises the current window (by Z order change) + */ +void FGAPIENTRY glutPopWindow( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPopWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPopWindow" ); + +#if TARGET_HOST_POSIX_X11 + + XRaiseWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle ); + +#elif TARGET_HOST_MS_WINDOWS + + SetWindowPos( + fgStructure.CurrentWindow->Window.Handle, + HWND_TOP, + 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE + ); + +#endif +} + +/* + * Resize the current window so that it fits the whole screen + */ +void FGAPIENTRY glutFullScreen( void ) +{ + SFG_Window *win; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" ); + + win = fgStructure.CurrentWindow; + + if (win->Parent) + { + /* Child windows cannot be made fullscreen, consistent with GLUT's behavior + * Also, what would it mean for a child window to be fullscreen, given that it + * is confined to its parent? + */ + fgWarning("glutFullScreen called on a child window, ignoring..."); + return; + } + else if (fgStructure.GameModeWindow != NULL && fgStructure.GameModeWindow->ID==win->ID) + { + /* Ignore fullscreen call on GameMode window, those are always fullscreen already */ + return; + } + +#if TARGET_HOST_POSIX_X11 + if(!glutGet(GLUT_FULL_SCREEN)) { + if(fghToggleFullscreen() != -1) { + win->State.IsFullscreen = GL_TRUE; + } + } + +#elif TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) /* FIXME: what about WinCE */ + + if (glutGet(GLUT_FULL_SCREEN)) + { + /* Leave full screen state before entering fullscreen again (resizing?) */ + glutLeaveFullScreen(); + } + + { +#if(WINVER >= 0x0500) /* Windows 2000 or later */ + DWORD s; + RECT rect; + HMONITOR hMonitor; + MONITORINFO mi; + + /* For fullscreen mode, first remove all window decoration + * and set style to popup so it will overlap the taskbar + * then force to maximize on the screen on which it has the most + * overlap. + */ + + + /* store current window rect */ + GetWindowRect( win->Window.Handle, &win->State.OldRect ); + + /* store current window style */ + win->State.OldStyle = s = GetWindowLong(win->Window.Handle, GWL_STYLE); + + /* remove decorations from style and add popup style*/ + s &= ~((WS_OVERLAPPEDWINDOW*QB64_Resizable())|WS_DLGFRAME|WS_BORDER|WS_SYSMENU|WS_MINIMIZEBOX|(WS_MAXIMIZEBOX*QB64_Resizable())); + s |= WS_POPUP; + SetWindowLong(win->Window.Handle, GWL_STYLE, s); + SetWindowPos(win->Window.Handle, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); + + /* For fullscreen mode, find the monitor that is covered the most + * by the window and get its rect as the resize target. + */ + hMonitor= MonitorFromRect(&win->State.OldRect, MONITOR_DEFAULTTONEAREST); + mi.cbSize = sizeof(mi); + GetMonitorInfo(hMonitor, &mi); + rect = mi.rcMonitor; +#else /* if (WINVER >= 0x0500) */ + RECT rect; + + /* For fullscreen mode, force the top-left corner to 0,0 + * and adjust the window rectangle so that the client area + * covers the whole screen. + */ + + rect.left = 0; + rect.top = 0; + rect.right = fgDisplay.ScreenWidth; + rect.bottom = fgDisplay.ScreenHeight; + + AdjustWindowRect ( &rect, ((WS_OVERLAPPEDWINDOW*QB64_Resizable())|WS_DLGFRAME|WS_BORDER|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX) | WS_CLIPSIBLINGS | + WS_CLIPCHILDREN, FALSE ); +#endif /* (WINVER >= 0x0500) */ + + /* + * then resize window + * SWP_NOACTIVATE Do not activate the window + * SWP_NOOWNERZORDER Do not change position in z-order + * SWP_NOSENDCHANGING Suppress WM_WINDOWPOSCHANGING message + * SWP_NOZORDER Retains the current Z order (ignore 2nd param) + */ + SetWindowPos( fgStructure.CurrentWindow->Window.Handle, + HWND_TOP, + rect.left, + rect.top, + rect.right - rect.left, + rect.bottom - rect.top, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | + SWP_NOZORDER + ); + + win->State.IsFullscreen = GL_TRUE; + } +#endif +} + +/* + * If we are fullscreen, resize the current window back to its original size + */ +void FGAPIENTRY glutLeaveFullScreen( void ) +{ + SFG_Window *win; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" ); + + win = fgStructure.CurrentWindow; + +#if TARGET_HOST_POSIX_X11 + if(glutGet(GLUT_FULL_SCREEN)) { + if(fghToggleFullscreen() != -1) { + win->State.IsFullscreen = GL_FALSE; + } + } + +#elif TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) /* FIXME: what about WinCE */ + if (!glutGet(GLUT_FULL_SCREEN)) + { + /* nothing to do */ + return; + } + + /* restore style of window before making it fullscreen */ + SetWindowLong(win->Window.Handle, GWL_STYLE, win->State.OldStyle); + SetWindowPos(win->Window.Handle, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); + + /* Then resize */ + SetWindowPos(win->Window.Handle, + HWND_TOP, + win->State.OldRect.left, + win->State.OldRect.top, + win->State.OldRect.right - win->State.OldRect.left, + win->State.OldRect.bottom - win->State.OldRect.top, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | + SWP_NOZORDER + ); + + win->State.IsFullscreen = GL_FALSE; +#endif +} + +/* + * Toggle the window's full screen state. + */ +void FGAPIENTRY glutFullScreenToggle( void ) +{ + SFG_Window *win; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreenToggle" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreenToggle" ); + + win = fgStructure.CurrentWindow; + +#if TARGET_HOST_POSIX_X11 + if(fghToggleFullscreen() != -1) { + win->State.IsFullscreen = !win->State.IsFullscreen; + } +#elif TARGET_HOST_MS_WINDOWS + if (!win->State.IsFullscreen) + glutFullScreen(); + else + glutLeaveFullScreen(); +#endif +} + +/* + * A.Donev: Set and retrieve the window's user data + */ +void* FGAPIENTRY glutGetWindowData( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetWindowData" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutGetWindowData" ); + return fgStructure.CurrentWindow->UserData; +} + +void FGAPIENTRY glutSetWindowData(void* data) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowData" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowData" ); + fgStructure.CurrentWindow->UserData = data; +} + +/*** END OF FILE ***/