1
1
Fork 0
mirror of https://github.com/QB64-Phoenix-Edition/QB64pe.git synced 2024-07-25 10:35:14 +00:00

Merge pull request #270 from mkilgore/glut-fix

Only call GLUT functions from the GLUT thread.
This commit is contained in:
Matt Kilgore 2022-12-03 11:41:15 -05:00 committed by GitHub
commit acf918bafd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
51 changed files with 1308 additions and 580 deletions

View file

@ -401,13 +401,8 @@ endif
QBLIB := $(PATH_INTERNAL_C)/$(QBLIB_NAME).o
ifneq ($(OS),osx)
$(QBLIB): $(PATH_INTERNAL_C)/libqb.cpp
$(CXX) $(CXXFLAGS) $< -c -o $@
else
$(QBLIB): $(PATH_INTERNAL_C)/libqb.mm
$(CXX) $(CXXFLAGS) $< -c -o $@
endif
ifeq ($(OS),win)
CLEAN_LIST += $(ICON_OBJ)
@ -421,6 +416,11 @@ EXE_OBJS := $(QBLIB) $(EXE_OBJS)
%.o: %.cpp
$(CXX) $(CXXFLAGS) $< -c -o $@
ifeq ($(OS),osx)
%.o: %.mm
$(CXX) $(CXXFLAGS) $< -c -o $@
endif
$(PATH_INTERNAL_TEMP)/data.o: $(PATH_INTERNAL_TEMP)/data.bin
$(OBJCOPY) -Ibinary $(OBJCOPY_FLAGS) $< $@

View file

@ -13,13 +13,7 @@
#ifdef QB64_MACOSX
# include <ApplicationServices/ApplicationServices.h>
# include "Cocoa/Cocoa.h"
# include <CoreFoundation/CoreFoundation.h>
# include <objc/objc-runtime.h>
# include <objc/objc.h>
# include <mach-o/dyld.h> //required for _NSGetExecutablePath
#endif
#include "mutex.h"
@ -29,6 +23,8 @@
#include "image.h"
#include "gui.h"
#include "http.h"
#include "keyhandler.h"
#include "glut-thread.h"
int32 disableEvents = 0;
@ -243,26 +239,10 @@ extern "C" void QB64_Window_Handle(void *handle) {
//...
}
static bool is_glut_up();
static void start_glut_thread();
#define NEEDS_GLUT(error_result) do { \
if (!is_glut_up()) { \
error(5); \
return error_result; \
} \
} while (0)
#define OPTIONAL_GLUT(result) do { \
if (!is_glut_up()) \
return result; \
} while (0)
// forward references
void set_view(int32 new_mode);
void set_render_source(int32 new_handle);
void set_render_dest(int32 new_handle);
void reinit_glut_callbacks();
int32 framebufferobjects_supported = 0;
@ -283,7 +263,6 @@ int32 environment_2d__letterbox = 0; // 1=vertical black stripes required, 2
int32 window_focused = 0; // Not used on Windows
uint8 *window_title = NULL;
int32 temp_window_title_set = 0;
double max_fps = 60; // 60 is the default
int32 auto_fps = 0; // set to 1 to make QB64 auto-adjust fps based on load
@ -515,14 +494,6 @@ int32 dont_call_sub_gl = 0;
void GLUT_DISPLAY_REQUEST();
void timerCB(int millisec) // not currently being used
{
#ifdef QB64_GLUT
glutPostRedisplay();
glutTimerFunc(millisec, timerCB, millisec);
#endif
}
struct display_frame_struct {
int32 state;
int64 order;
@ -1243,294 +1214,6 @@ int64 GetTicks() { return orwl_gettime(); }
int64 GetTicks() { return ((((int64)clock()) * ((int64)1000)) / ((int64)CLOCKS_PER_SEC)); }
#endif
#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,
// If more modifiers are added, the window defocus code in qb64_os_event_linux must be altered
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)
/* Restricted Functionality: (Security focused approach, does not include restricting sound etc)
Block while compiling: (ONLY things that cannot be caught at runtime)
@ -23784,7 +23467,7 @@ void sub__mousehide() {
#ifdef QB64_GUI
# ifdef QB64_GLUT
OPTIONAL_GLUT();
glutSetCursor(GLUT_CURSOR_NONE);
libqb_glut_set_cursor(GLUT_CURSOR_NONE);
# endif
#endif
}
@ -23856,7 +23539,7 @@ void sub__mouseshow(qbs *style, int32 passed) {
}
cursor_valid:
glutSetCursor(mouse_cursor_style);
libqb_glut_set_cursor(mouse_cursor_style);
#endif
}
@ -23938,7 +23621,7 @@ void sub__mousemove(float x, float y) {
x2 += environment_2d__screen_x1;
y2 += environment_2d__screen_y1;
glutWarpPointer(x2, y2);
libqb_glut_warp_pointer(x2, y2);
return;
error:
@ -27518,7 +27201,7 @@ int32 func_screenwidth() {
#else
# ifdef QB64_GLUT
OPTIONAL_GLUT(0);
return glutGet(GLUT_SCREEN_WIDTH);
return libqb_glut_get(GLUT_SCREEN_WIDTH);
# else
return 0;
# endif
@ -27531,7 +27214,7 @@ int32 func_screenheight() {
#else
# ifdef QB64_GLUT
OPTIONAL_GLUT(0);
return glutGet(GLUT_SCREEN_HEIGHT);
return libqb_glut_get(GLUT_SCREEN_HEIGHT);
# else
return 0;
# endif
@ -27541,13 +27224,13 @@ int32 func_screenheight() {
void sub_screenicon() {
#ifdef QB64_GLUT
NEEDS_GLUT();
glutIconifyWindow();
libqb_glut_iconify_window();
#endif
}
int32 func_windowexists() {
#ifdef QB64_GLUT
return is_glut_up();
return libqb_is_glut_up();
#else
return -1;
#endif
@ -32951,10 +32634,10 @@ qbs *func__os() {
int32 func__screenx() {
#if defined(QB64_GUI) && defined(QB64_WINDOWS) && defined(QB64_GLUT)
NEEDS_GLUT(0);
return glutGet(GLUT_WINDOW_X) - glutGet(GLUT_WINDOW_BORDER_WIDTH);
return libqb_glut_get(GLUT_WINDOW_X) - libqb_glut_get(GLUT_WINDOW_BORDER_WIDTH);
#elif defined(QB64_GUI) && defined(QB64_MACOSX) && defined(QB64_GLUT)
NEEDS_GLUT(0);
return glutGet(GLUT_WINDOW_X);
return libqb_glut_get(GLUT_WINDOW_X);
#endif
return 0; // if not windows then return 0
}
@ -32962,10 +32645,10 @@ int32 func__screenx() {
int32 func__screeny() {
#if defined(QB64_GUI) && defined(QB64_WINDOWS) && defined(QB64_GLUT)
NEEDS_GLUT(0);
return glutGet(GLUT_WINDOW_Y) - glutGet(GLUT_WINDOW_BORDER_WIDTH) - glutGet(GLUT_WINDOW_HEADER_HEIGHT);
return libqb_glut_get(GLUT_WINDOW_Y) - libqb_glut_get(GLUT_WINDOW_BORDER_WIDTH) - libqb_glut_get(GLUT_WINDOW_HEADER_HEIGHT);
#elif defined(QB64_GUI) && defined(QB64_MACOSX) && defined(QB64_GLUT)
NEEDS_GLUT(0);
return glutGet(GLUT_WINDOW_Y);
return libqb_glut_get(GLUT_WINDOW_Y);
#endif
return 0; // if not windows then return 0
}
@ -32984,18 +32667,18 @@ void sub__screenmove(int32 x, int32 y, int32 passed) {
NEEDS_GLUT();
if (passed == 2) {
glutPositionWindow(x, y);
libqb_glut_position_window(x, y);
} else {
int32 SW = -1, SH, WW, WH;
while (SW == -1) {
SW = glutGet(GLUT_SCREEN_WIDTH);
SW = libqb_glut_get(GLUT_SCREEN_WIDTH);
}
SH = glutGet(GLUT_SCREEN_HEIGHT);
WW = glutGet(GLUT_WINDOW_WIDTH);
WH = glutGet(GLUT_WINDOW_HEIGHT);
SH = libqb_glut_get(GLUT_SCREEN_HEIGHT);
WW = libqb_glut_get(GLUT_WINDOW_WIDTH);
WH = libqb_glut_get(GLUT_WINDOW_HEIGHT);
x = (SW - WW) / 2;
y = (SH - WH) / 2;
glutPositionWindow(x, y);
libqb_glut_position_window(x, y);
}
#endif
@ -34286,8 +33969,8 @@ void sub__screenshow() {
#ifdef QB64_GLUT
screen_hide = 0;
// $SCREENHIDE programs will not have the window running
start_glut_thread();
glutShowWindow();
libqb_start_glut_thread();
libqb_glut_show_window();
#endif
}
@ -34296,8 +33979,10 @@ void sub__screenhide() {
return;
#ifdef QB64_GLUT
// start_glut_thread();
glutHideWindow();
// This is probably unnecessary, no conditions allow for screen_hide==0
// without GLUT running, but it doesn't hurt anything.
libqb_start_glut_thread();
libqb_glut_hide_window();
#endif
screen_hide = 1;
@ -34957,6 +34642,8 @@ void GLUT_SPECIALUP_FUNC(int key, int x, int y) { GLUT_key_special(key, 0); }
#ifdef QB64_WINDOWS
void GLUT_TIMER_EVENT(int ignore) {
libqb_process_glut_queue();
# ifdef QB64_GLUT
glutPostRedisplay();
int32 msdelay = 1000.0 / max_fps;
@ -34969,6 +34656,7 @@ void GLUT_TIMER_EVENT(int ignore) {
}
#else
void GLUT_IDLEFUNC() {
libqb_process_glut_queue();
# ifdef QB64_MACOSX
# ifdef DEPENDENCY_DEVICEINPUT
@ -36210,13 +35898,6 @@ void GLUT_DISPLAY_REQUEST() {
}
in_GLUT_DISPLAY_REQUEST = 1;
# ifdef QB64_MACOSX
if (temp_window_title_set == 1) {
glutSetWindowTitle((char *)window_title);
temp_window_title_set = 0;
}
# endif
// general use variables
static int32 i, i2, i3;
static int32 x, y, x2, y2;
@ -37026,15 +36707,9 @@ void sub__title(qbs *title) {
if (old_buf)
free(old_buf);
#ifdef QB64_GLUT
# ifdef QB64_MACOSX
temp_window_title_set = 1;
# else
OPTIONAL_GLUT();
glutSetWindowTitle((char *)window_title);
# endif
#endif
libqb_glut_set_window_title((char *)window_title);
} // title
void sub__echo(qbs *message) {
@ -37367,165 +37042,6 @@ qbs *func__dir(qbs *context_in) {
#endif
}
static void glutWarning(const char *fmt, va_list lst) {
// Do something
}
// Performs all of the FreeGLUT initialization except for calling glutMainLoop()
static void initialize_glut(int argc, char **argv) {
#ifdef QB64_GLUT
# ifdef CORE_FREEGLUT
// This keeps FreeGlut from dumping warnings to console
glutInitWarningFunc(glutWarning);
glutInitErrorFunc(glutWarning);
# endif
glutInit(&argc, argv);
# ifdef QB64_MACOSX
[NSEvent addLocalMonitorForEventsMatchingMask:NSFlagsChangedMask
handler:^NSEvent *(NSEvent *event) {
// notes on bitfields:
// if ([event modifierFlags] == 131330) keydown_vk(VK+QBVK_LSHIFT);// 100000000100000010
// if ([event modifierFlags] == 131332) keydown_vk(VK+QBVK_RSHIFT);// 100000000100000100
// if ([event modifierFlags] == 262401) keydown_vk(VK+QBVK_LCTRL); //1000000000100000001
// if ([event modifierFlags] == 270592) keydown_vk(VK+QBVK_RCTRL); //1000010000100000000
// if ([event modifierFlags] == 524576) keydown_vk(VK+QBVK_LALT); //10000000000100100000
// if ([event modifierFlags] == 524608) keydown_vk(VK+QBVK_RALT); //10000000000101000000
// caps lock // 10000000100000000
int x = [event modifierFlags];
if (x & (1 << 0)) {
if (!keyheld(VK + QBVK_LCTRL))
keydown_vk(VK + QBVK_LCTRL);
} else {
if (keyheld(VK + QBVK_LCTRL))
keyup_vk(VK + QBVK_LCTRL);
}
if (x & (1 << 13)) {
if (!keyheld(VK + QBVK_RCTRL))
keydown_vk(VK + QBVK_RCTRL);
} else {
if (keyheld(VK + QBVK_RCTRL))
keyup_vk(VK + QBVK_RCTRL);
}
if (x & (1 << 1)) {
if (!keyheld(VK + QBVK_LSHIFT))
keydown_vk(VK + QBVK_LSHIFT);
} else {
if (keyheld(VK + QBVK_LSHIFT))
keyup_vk(VK + QBVK_LSHIFT);
}
if (x & (1 << 2)) {
if (!keyheld(VK + QBVK_RSHIFT))
keydown_vk(VK + QBVK_RSHIFT);
} else {
if (keyheld(VK + QBVK_RSHIFT))
keyup_vk(VK + QBVK_RSHIFT);
}
if (x & (1 << 5)) {
if (!keyheld(VK + QBVK_LALT))
keydown_vk(VK + QBVK_LALT);
} else {
if (keyheld(VK + QBVK_LALT))
keyup_vk(VK + QBVK_LALT);
}
if (x & (1 << 6)) {
if (!keyheld(VK + QBVK_RALT))
keydown_vk(VK + QBVK_RALT);
} else {
if (keyheld(VK + QBVK_RALT))
keyup_vk(VK + QBVK_RALT);
}
if (x & (1 << 16)) {
if (!keyheld(VK + QBVK_CAPSLOCK))
keydown_vk(VK + QBVK_CAPSLOCK);
} else {
if (keyheld(VK + QBVK_CAPSLOCK))
keyup_vk(VK + QBVK_CAPSLOCK);
}
return event;
}];
# endif
# ifdef QB64_WINDOWS
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
# else
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
# endif
glutInitWindowSize(640, 400); // cannot be changed unless display_x(etc) are modified
if (!glutGet(GLUT_DISPLAY_MODE_POSSIBLE)) // must be called on Linux or GLUT crashes
{
exit(1);
}
if (!window_title) {
glutCreateWindow("Untitled");
} else {
glutCreateWindow((char *)window_title);
}
GLenum err = glewInit();
if (GLEW_OK != err) {
gui_alert((char *)glewGetErrorString(err));
}
if (glewIsSupported("GL_EXT_framebuffer_object"))
framebufferobjects_supported = 1;
glutDisplayFunc(GLUT_DISPLAY_REQUEST);
# ifdef QB64_WINDOWS
glutTimerFunc(8, GLUT_TIMER_EVENT, 0);
# else
glutIdleFunc(GLUT_IDLEFUNC);
# endif
glutKeyboardFunc(GLUT_KEYBOARD_FUNC);
glutKeyboardUpFunc(GLUT_KEYBOARDUP_FUNC);
glutSpecialFunc(GLUT_SPECIAL_FUNC);
glutSpecialUpFunc(GLUT_SPECIALUP_FUNC);
glutMouseFunc(GLUT_MOUSE_FUNC);
glutMotionFunc(GLUT_MOTION_FUNC);
glutPassiveMotionFunc(GLUT_PASSIVEMOTION_FUNC);
glutReshapeFunc(GLUT_RESHAPE_FUNC);
# ifdef CORE_FREEGLUT
glutMouseWheelFunc(GLUT_MOUSEWHEEL_FUNC);
# endif
#endif // QB64_GLUT
}
static bool glut_is_started;
static struct completion glut_thread_starter;
static struct completion *glut_thread_initialized;
static void start_glut_thread() {
if (glut_is_started)
return;
struct completion init;
completion_init(&init);
glut_thread_initialized = &init;
completion_finish(&glut_thread_starter);
completion_wait(&init);
completion_clear(&init);
}
// Checks whether the GLUT thread is running
static bool is_glut_up() {
return glut_is_started;
}
extern void set_dynamic_info();
int main(int argc, char *argv[]) {
@ -37967,14 +37483,7 @@ int main(int argc, char *argv[]) {
libqb_http_init();
#ifdef QB64_GUI
if (!screen_hide) {
initialize_glut(argc, argv); // Initialize GLUT if the screen isn't hidden
glut_is_started = true;
} else {
completion_init(&glut_thread_starter);
}
#endif
libqb_glut_presetup(argc, argv);
struct libqb_thread *qbmain = libqb_thread_new();
libqb_thread_start(qbmain, QBMAIN, NULL);
@ -37984,32 +37493,9 @@ int main(int argc, char *argv[]) {
lock_display_required = 1;
#ifdef QB64_GUI
libqb_start_main_thread(argc, argv);
struct libqb_thread *main_loop = libqb_thread_new();
libqb_thread_start(main_loop, MAIN_LOOP, NULL);
// This happens for $SCREENHIDE programs. This thread waits on the
// `glut_thread_starter` completion, which will get completed if a
// _ScreenShow is used.
if (!glut_is_started) {
completion_wait(&glut_thread_starter);
initialize_glut(argc, argv);
glut_is_started = true;
if (glut_thread_initialized)
completion_finish(glut_thread_initialized);
}
glutMainLoop();
#else
// normally MAIN_LOOP() is launched in a separate thread to reserve the primary thread for GLUT
// that is not required, so run MAIN_LOOP() in our primary thread
MAIN_LOOP(NULL);
return 0;
#endif
return 0; // Should never get here
}
//###################### Main Loop ####################
@ -38200,7 +37686,7 @@ end_program:
snd_un_init();
exit(exit_code);
libqb_exit(exit_code);
}
// used to preserve the previous frame's content for comparison/reuse purposes
@ -40238,31 +39724,6 @@ extern "C" int qb64_custom_event(int event, int v1, int v2, int v3, int v4, int
return -1; // Unknown command (use for debugging purposes only)
} // qb64_custom_event
void reinit_glut_callbacks() {
#ifdef QB64_GLUT
glutDisplayFunc(GLUT_DISPLAY_REQUEST);
# ifdef QB64_WINDOWS
glutTimerFunc(8, GLUT_TIMER_EVENT, 0);
# else
glutIdleFunc(GLUT_IDLEFUNC);
# endif
glutKeyboardFunc(GLUT_KEYBOARD_FUNC);
glutKeyboardUpFunc(GLUT_KEYBOARDUP_FUNC);
glutSpecialFunc(GLUT_SPECIAL_FUNC);
glutSpecialUpFunc(GLUT_SPECIALUP_FUNC);
glutMouseFunc(GLUT_MOUSE_FUNC);
glutMotionFunc(GLUT_MOTION_FUNC);
glutPassiveMotionFunc(GLUT_PASSIVEMOTION_FUNC);
glutReshapeFunc(GLUT_RESHAPE_FUNC);
# ifdef CORE_FREEGLUT
glutMouseWheelFunc(GLUT_MOUSEWHEEL_FUNC);
# endif
#endif
}
int32 func__capslock() {
#ifdef QB64_WINDOWS
return -GetKeyState(VK_CAPITAL);

View file

@ -1,2 +0,0 @@
#include "libqb.cpp"

View file

@ -8,4 +8,14 @@ libqb-objs-y$(DEP_HTTP) += $(PATH_LIBQB)/src/http-stub.o
libqb-objs-y += $(PATH_LIBQB)/src/threading-$(PLATFORM).o
libqb-objs-y$(DEP_CONSOLE_ONLY) += $(PATH_LIBQB)/src/glut-main-thread.o
libqb-objs-y$(DEP_CONSOLE_ONLY) += $(PATH_LIBQB)/src/glut-message.o
libqb-objs-y$(DEP_CONSOLE_ONLY) += $(PATH_LIBQB)/src/glut-msg-queue.o
libqb-objs-$(DEP_CONSOLE_ONLY) += $(PATH_LIBQB)/src/console-only-main-thread.o
ifeq ($(OS),osx)
libqb-objs-y$(DEP_CONSOLE_ONLY) += $(PATH_LIBQB)/src/mac-key-monitor.o
endif
CLEAN_LIST += $(libqb-objs-y) $(libqb-objs-yy) $(libqb-objs-)

View file

@ -0,0 +1,50 @@
#ifndef INCLUDE_LIBQB_GLUT_THREAD_H
#define INCLUDE_LIBQB_GLUT_THREAD_H
// Called to potentially setup GLUT before starting the program.
void libqb_glut_presetup(int argc, char **argv);
// Starts the "main thread", including handling all the GLUT setup.
void libqb_start_main_thread(int argc, char **argv);
// Used to support _ScreenShow, which can start the GLUT thread after the
// program is started
void libqb_start_glut_thread();
// Indicates whether GLUT is currently running (and thus whether we're able to
// do any GLUT-related stuff
bool libqb_is_glut_up();
// Called at consistent intervals from a GLUT callback
void libqb_process_glut_queue();
// Called to properly exit the program. Necessary because GLUT requires a
// special care to not seg-fault when exiting the program.
void libqb_exit(int);
// These functions perform the same actions as their coresponding glut* functions.
// They tell the GLUT thread to perform the command, returning the result if applicable
void libqb_glut_set_cursor(int style);
void libqb_glut_warp_pointer(int x, int y);
int libqb_glut_get(int id);
void libqb_glut_iconify_window();
void libqb_glut_position_window(int x, int y);
void libqb_glut_show_window();
void libqb_glut_hide_window();
void libqb_glut_set_window_title(const char *title);
void libqb_glut_exit_program(int exitcode);
// Convinence macros, exists a function depending on the state of GLUT
#define NEEDS_GLUT(error_result) do { \
if (!libqb_is_glut_up()) { \
error(5); \
return error_result; \
} \
} while (0)
#define OPTIONAL_GLUT(result) do { \
if (!libqb_is_glut_up()) \
return result; \
} while (0)
#endif

View file

@ -0,0 +1,299 @@
#ifndef INCLUDE_LIBQB_KEYHANDLER_h
#define INCLUDE_LIBQB_KEYHANDLER_h
#include <stdint.h>
int32_t keyheld(uint32_t x);
void keydown_vk(uint32_t key);
void keyup_vk(uint32_t key);
#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,
// If more modifiers are added, the window defocus code in qb64_os_event_linux must be altered
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)
#endif

View file

@ -0,0 +1,72 @@
#include "libqb-common.h"
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include "glut-thread.h"
// This file is for Console-Only programs. They never invoke GLUT so the setup
// here is much simpler.
// FIXME: PUt this definition somewhere else
void MAIN_LOOP(void *);
void libqb_glut_presetup(int argc, char **argv) {
}
void libqb_start_main_thread(int argc, char **argv) {
// Because GLUT is not used, we can just run MAIN_LOOP without creating a
// new thread for it.
MAIN_LOOP(NULL);
}
void libqb_start_glut_thread() {
}
bool libqb_is_glut_up() {
return false;
}
void libqb_process_glut_queue() {
}
void libqb_glut_set_cursor(int style) {
}
void libqb_glut_warp_pointer(int x, int y)
{
}
int libqb_glut_get(int id) {
return 0;
}
void libqb_glut_iconify_window() {
}
void libqb_glut_position_window(int x, int y) {
}
void libqb_glut_show_window() {
}
void libqb_glut_hide_window() {
}
void libqb_glut_set_window_title(const char *title) {
}
void libqb_glut_exit_program(int exitcode) {
libqb_exit(exitcode);
}
// Since there's no GLUT thread to deal with we can just exit() like normal
void libqb_exit(int code) {
exit(code);
}

View file

@ -0,0 +1,188 @@
#include "libqb-common.h"
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <list>
#include <queue>
#include <unordered_map>
#include "GL/glew.h"
// note: MacOSX uses Apple's GLUT not FreeGLUT
#ifdef QB64_MACOSX
# include <GLUT/glut.h>
#else
# define CORE_FREEGLUT
# include "freeglut.h"
#endif
#include "mutex.h"
#include "thread.h"
#include "completion.h"
#include "gui.h"
#include "mac-key-monitor.h"
#include "glut-thread.h"
// FIXME: These extern variable and function definitions should probably go
// somewhere more global so that they can be referenced by libqb.cpp
extern uint8_t *window_title;
extern int32_t framebufferobjects_supported;
extern int32_t screen_hide;
void MAIN_LOOP(void *);
void GLUT_KEYBOARD_FUNC(unsigned char key, int x, int y);
void GLUT_DISPLAY_REQUEST();
void GLUT_KEYBOARDUP_FUNC(unsigned char key, int x, int y);
void GLUT_SPECIAL_FUNC(int key, int x, int y);
void GLUT_SPECIALUP_FUNC(int key, int x, int y);
void GLUT_MOUSE_FUNC(int glut_button, int state, int x, int y);
void GLUT_MOTION_FUNC(int x, int y);
void GLUT_PASSIVEMOTION_FUNC(int x, int y);
void GLUT_RESHAPE_FUNC(int width, int height);
#ifdef QB64_WINDOWS
void GLUT_TIMER_EVENT(int ignore);
#else
void GLUT_IDLEFUNC();
#endif
#ifdef CORE_FREEGLUT
void GLUT_MOUSEWHEEL_FUNC(int wheel, int direction, int x, int y);
#endif
static void glutWarning(const char *fmt, va_list lst) {
// This keeps FreeGlut from dumping warnings to console
}
// Performs all of the FreeGLUT initialization except for calling glutMainLoop()
static void initialize_glut(int argc, char **argv) {
# ifdef CORE_FREEGLUT
glutInitWarningFunc(glutWarning);
glutInitErrorFunc(glutWarning);
# endif
glutInit(&argc, argv);
mac_register_key_handler();
# ifdef QB64_WINDOWS
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
# else
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
# endif
glutInitWindowSize(640, 400); // cannot be changed unless display_x(etc) are modified
if (!glutGet(GLUT_DISPLAY_MODE_POSSIBLE)) // must be called on Linux or GLUT crashes
{
exit(1);
}
if (!window_title) {
glutCreateWindow("Untitled");
} else {
glutCreateWindow((char *)window_title);
}
GLenum err = glewInit();
if (GLEW_OK != err) {
gui_alert((char *)glewGetErrorString(err));
}
if (glewIsSupported("GL_EXT_framebuffer_object"))
framebufferobjects_supported = 1;
glutDisplayFunc(GLUT_DISPLAY_REQUEST);
# ifdef QB64_WINDOWS
glutTimerFunc(8, GLUT_TIMER_EVENT, 0);
# else
glutIdleFunc(GLUT_IDLEFUNC);
# endif
glutKeyboardFunc(GLUT_KEYBOARD_FUNC);
glutKeyboardUpFunc(GLUT_KEYBOARDUP_FUNC);
glutSpecialFunc(GLUT_SPECIAL_FUNC);
glutSpecialUpFunc(GLUT_SPECIALUP_FUNC);
glutMouseFunc(GLUT_MOUSE_FUNC);
glutMotionFunc(GLUT_MOTION_FUNC);
glutPassiveMotionFunc(GLUT_PASSIVEMOTION_FUNC);
glutReshapeFunc(GLUT_RESHAPE_FUNC);
# ifdef CORE_FREEGLUT
glutMouseWheelFunc(GLUT_MOUSEWHEEL_FUNC);
# endif
}
static bool glut_is_started;
static struct completion glut_thread_starter;
static struct completion *glut_thread_initialized;
void libqb_start_glut_thread() {
if (glut_is_started)
return;
struct completion init;
completion_init(&init);
glut_thread_initialized = &init;
completion_finish(&glut_thread_starter);
completion_wait(&init);
completion_clear(&init);
}
// Checks whether the GLUT thread is running
bool libqb_is_glut_up() {
return glut_is_started;
}
void libqb_glut_presetup(int argc, char **argv) {
if (!screen_hide) {
initialize_glut(argc, argv); // Initialize GLUT if the screen isn't hidden
glut_is_started = true;
} else {
completion_init(&glut_thread_starter);
}
}
void libqb_start_main_thread(int argc, char **argv) {
// Start the 'MAIN_LOOP' in a separate thread, as GLUT has to run on the
// initial thread.
struct libqb_thread *main_loop = libqb_thread_new();
libqb_thread_start(main_loop, MAIN_LOOP, NULL);
// This happens for $SCREENHIDE programs. This thread waits on the
// `glut_thread_starter` completion, which will get completed if a
// _ScreenShow is used.
if (!glut_is_started) {
completion_wait(&glut_thread_starter);
initialize_glut(argc, argv);
glut_is_started = true;
if (glut_thread_initialized)
completion_finish(glut_thread_initialized);
}
glutMainLoop();
}
// Due to GLUT making use of cleanup via atexit, we have to call exit() from
// the same thread handling the GLUT logic so that the atexit handler also runs
// from that thread (not doing that can result in a segfault due to using GLUT
// from two threads at the same time).
//
// This is acomplished by simply queuing a GLUT message that calls exit() for us.
void libqb_exit(int exitcode)
{
// If GLUT isn't running then we're free to do the exit() call from here
if (!libqb_is_glut_up())
exit(exitcode);
libqb_glut_exit_program(exitcode);
}

View file

@ -0,0 +1,54 @@
#include "libqb-common.h"
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
// note: MacOSX uses Apple's GLUT not FreeGLUT
#ifdef QB64_MACOSX
# include <GLUT/glut.h>
#else
# define CORE_FREEGLUT
# include "freeglut.h"
#endif
#include "glut-message.h"
void glut_message_set_cursor::execute() {
glutSetCursor(style);
}
void glut_message_warp_pointer::execute() {
glutWarpPointer(x, y);
}
void glut_message_get::execute() {
response_value = glutGet(id);
}
void glut_message_iconify_window::execute() {
glutIconifyWindow();
}
void glut_message_position_window::execute() {
glutPositionWindow(x, y);
}
void glut_message_show_window::execute() {
glutShowWindow();
}
void glut_message_hide_window::execute() {
glutHideWindow();
}
void glut_message_set_window_title::execute() {
glutSetWindowTitle(newTitle);
}
void glut_message_exit_program::execute() {
exit(exitCode);
}

View file

@ -0,0 +1,133 @@
#ifndef INCLUDE_LIBQB_GLUT_MESSAGE_H
#define INCLUDE_LIBQB_GLUT_MESSAGE_H
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "completion.h"
class glut_message {
private:
completion *finished = NULL;
void initCompletion() {
finished = new completion();
completion_init(finished);
}
protected:
glut_message(bool withCompletion) {
if (withCompletion)
initCompletion();
}
public:
// Calling this indicates to the creator of the message that it has been
// completed, and any response data is availiable to be read.
//
// If `finsihed` is NULL that means nobody is waiting for the response. In
// that situation we're free to simply delete the object.
void finish() {
if (finished)
completion_finish(finished);
else
delete this;
}
void wait_for_response() {
completion_wait(finished);
}
virtual ~glut_message() {
if (finished) {
completion_wait(finished); // Should be a NOP, but better to check anyway
completion_clear(finished);
delete finished;
}
}
virtual void execute() = 0;
};
class glut_message_set_cursor : public glut_message {
public:
int style;
void execute();
glut_message_set_cursor(int _style) : glut_message(false), style(_style) { }
};
class glut_message_warp_pointer : public glut_message {
public:
int x, y;
void execute();
glut_message_warp_pointer(int _x, int _y) : glut_message(false), x(_x), y(_y) { }
};
class glut_message_get : public glut_message {
public:
int id;
int response_value;
void execute();
glut_message_get(int _id) : glut_message(true), id(_id), response_value(0) { }
};
class glut_message_iconify_window : public glut_message {
public:
void execute();
glut_message_iconify_window() : glut_message(false) { }
};
class glut_message_position_window : public glut_message {
public:
int x, y;
void execute();
glut_message_position_window(int _x, int _y) : glut_message(false), x(_x), y(_y) { }
};
class glut_message_show_window : public glut_message {
public:
void execute();
glut_message_show_window() : glut_message(false) { }
};
class glut_message_hide_window : public glut_message {
public:
void execute();
glut_message_hide_window() : glut_message(false) { }
};
class glut_message_set_window_title : public glut_message {
public:
char *newTitle;
void execute();
glut_message_set_window_title(const char *title) : glut_message(false) {
newTitle = strdup(title);
}
virtual ~glut_message_set_window_title() {
free(newTitle);
}
};
class glut_message_exit_program : public glut_message {
public:
int exitCode;
void execute();
glut_message_exit_program(int _exitCode) : glut_message(true), exitCode(_exitCode) { }
};
// Queues a glut_message to be processed. Returns false if the message was not
// queued.
bool libqb_queue_glut_message(glut_message *msg);
#endif

View file

@ -0,0 +1,137 @@
#include "libqb-common.h"
#include <unistd.h>
#include <queue>
// note: MacOSX uses Apple's GLUT not FreeGLUT
#ifdef QB64_MACOSX
# include <GLUT/glut.h>
#else
# define CORE_FREEGLUT
# include "freeglut.h"
#endif
#include "mutex.h"
#include "glut-message.h"
#include "glut-thread.h"
static libqb_mutex *glut_msg_queue_lock = libqb_mutex_new();
static std::queue<glut_message *> glut_msg_queue;
// These values from GLUT are read on every process of the msg queue. Calls to
// libqb_glut_get() can then read from these values directly rather than wait
// for the GLUT thread to process the command.
static int glut_window_x, glut_window_y;
#ifdef CORE_FREEGLUT
static int glut_window_border_width, glut_window_header_height;
#endif
bool libqb_queue_glut_message(glut_message *msg) {
if (!libqb_is_glut_up()) {
msg->finish();
return false;
}
libqb_mutex_guard guard(glut_msg_queue_lock);
glut_msg_queue.push(msg);
return true;
}
void libqb_process_glut_queue() {
libqb_mutex_guard guard(glut_msg_queue_lock);
glut_window_x = glutGet(GLUT_WINDOW_X);
glut_window_y = glutGet(GLUT_WINDOW_Y);
#ifdef CORE_FREEGLUT
glut_window_border_width = glutGet(GLUT_WINDOW_BORDER_WIDTH);
glut_window_header_height = glutGet(GLUT_WINDOW_HEADER_HEIGHT);
#endif
while (!glut_msg_queue.empty()) {
glut_message *msg = glut_msg_queue.front();
glut_msg_queue.pop();
msg->execute();
msg->finish();
}
}
void libqb_glut_set_cursor(int style) {
libqb_queue_glut_message(new glut_message_set_cursor(style));
}
void libqb_glut_warp_pointer(int x, int y) {
libqb_queue_glut_message(new glut_message_warp_pointer(x, y));
}
static bool is_static_glut_value(int id) {
return id == GLUT_WINDOW_Y
|| id == GLUT_WINDOW_X
#ifdef CORE_FREEGLUT
|| id == GLUT_WINDOW_BORDER_WIDTH
|| id == GLUT_WINDOW_HEADER_HEIGHT
#endif
;
}
static int __get_static_glut_value(int id) {
switch (id) {
case GLUT_WINDOW_Y: return glut_window_y;
case GLUT_WINDOW_X: return glut_window_x;
#ifdef CORE_FREEGLUT
case GLUT_WINDOW_BORDER_WIDTH: return glut_window_border_width;
case GLUT_WINDOW_HEADER_HEIGHT: return glut_window_header_height;
#endif
default: return -1;
}
}
int libqb_glut_get(int id) {
if (is_static_glut_value(id)) {
libqb_mutex_guard guard(glut_msg_queue_lock);
return __get_static_glut_value(id);
}
glut_message_get msg(id);
libqb_queue_glut_message(&msg);
msg.wait_for_response();
return msg.response_value;
}
void libqb_glut_iconify_window() {
libqb_queue_glut_message(new glut_message_iconify_window());
}
void libqb_glut_position_window(int x, int y) {
libqb_queue_glut_message(new glut_message_position_window(x, y));
}
void libqb_glut_show_window() {
libqb_queue_glut_message(new glut_message_show_window());
}
void libqb_glut_hide_window() {
libqb_queue_glut_message(new glut_message_hide_window());
}
void libqb_glut_set_window_title(const char *title) {
libqb_queue_glut_message(new glut_message_set_window_title(title));
}
void libqb_glut_exit_program(int exitcode) {
glut_message_exit_program msg(exitcode);
libqb_queue_glut_message(&msg);
msg.wait_for_response();
// Should never return
exit(exitcode);
}

View file

@ -0,0 +1,10 @@
#ifndef INCLUDE_INTERNAL_MAC_KEY_MONITOR_H
#define INCLUDE_INTERNAL_MAC_KEY_MONITOR_H
#ifdef QB64_MACOSX
void mac_register_key_handler();
#else
static inline void mac_register_key_handler() { };
#endif
#endif

View file

@ -0,0 +1,85 @@
#include "libqb-common.h"
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include "Cocoa/Cocoa.h"
#include <CoreFoundation/CoreFoundation.h>
#include "keyhandler.h"
#include "mac-key-monitor.h"
void mac_register_key_handler()
{
[NSEvent addLocalMonitorForEventsMatchingMask:NSFlagsChangedMask
handler:^NSEvent *(NSEvent *event) {
// notes on bitfields:
// if ([event modifierFlags] == 131330) keydown_vk(VK+QBVK_LSHIFT);// 100000000100000010
// if ([event modifierFlags] == 131332) keydown_vk(VK+QBVK_RSHIFT);// 100000000100000100
// if ([event modifierFlags] == 262401) keydown_vk(VK+QBVK_LCTRL); //1000000000100000001
// if ([event modifierFlags] == 270592) keydown_vk(VK+QBVK_RCTRL); //1000010000100000000
// if ([event modifierFlags] == 524576) keydown_vk(VK+QBVK_LALT); //10000000000100100000
// if ([event modifierFlags] == 524608) keydown_vk(VK+QBVK_RALT); //10000000000101000000
// caps lock // 10000000100000000
int x = [event modifierFlags];
if (x & (1 << 0)) {
if (!keyheld(VK + QBVK_LCTRL))
keydown_vk(VK + QBVK_LCTRL);
} else {
if (keyheld(VK + QBVK_LCTRL))
keyup_vk(VK + QBVK_LCTRL);
}
if (x & (1 << 13)) {
if (!keyheld(VK + QBVK_RCTRL))
keydown_vk(VK + QBVK_RCTRL);
} else {
if (keyheld(VK + QBVK_RCTRL))
keyup_vk(VK + QBVK_RCTRL);
}
if (x & (1 << 1)) {
if (!keyheld(VK + QBVK_LSHIFT))
keydown_vk(VK + QBVK_LSHIFT);
} else {
if (keyheld(VK + QBVK_LSHIFT))
keyup_vk(VK + QBVK_LSHIFT);
}
if (x & (1 << 2)) {
if (!keyheld(VK + QBVK_RSHIFT))
keydown_vk(VK + QBVK_RSHIFT);
} else {
if (keyheld(VK + QBVK_RSHIFT))
keyup_vk(VK + QBVK_RSHIFT);
}
if (x & (1 << 5)) {
if (!keyheld(VK + QBVK_LALT))
keydown_vk(VK + QBVK_LALT);
} else {
if (keyheld(VK + QBVK_LALT))
keyup_vk(VK + QBVK_LALT);
}
if (x & (1 << 6)) {
if (!keyheld(VK + QBVK_RALT))
keydown_vk(VK + QBVK_RALT);
} else {
if (keyheld(VK + QBVK_RALT))
keyup_vk(VK + QBVK_RALT);
}
if (x & (1 << 16)) {
if (!keyheld(VK + QBVK_CAPSLOCK))
keydown_vk(VK + QBVK_CAPSLOCK);
} else {
if (keyheld(VK + QBVK_CAPSLOCK))
keyup_vk(VK + QBVK_CAPSLOCK);
}
return event;
}];
}

View file

@ -12,5 +12,7 @@ $(FREEGLUT_LIB): $(FREEGLUT_OBJS)
QB_CORE_LIB := $(FREEGLUT_LIB)
CXXFLAGS += -I$(PATH_INTERNAL_C)/parts/core/src/ -I$(PATH_INTERNAL_C)/parts/core/glew/include/
CLEAN_LIST += $(FREEGLUT_LIB) $(FREEGLUT_OBJS)

View file

@ -32,6 +32,12 @@ show_incorrect_result()
# This is either win, lnx, or osx
OS=$CI_OS
# On Linux, we make use of xvfb-run to provide each test with a framebuffer
# based X server, which allows graphics to work.
if [ "$OS" == "lnx" ]; then
LNX_PREFIX=xvfb-run
fi
# Each .bas file represents a separate test.
while IFS= read -r test
do
@ -107,7 +113,7 @@ do
pushd . > /dev/null
cd "./tests/compile_tests/$category"
testResult=$("../../../$EXE" "../../../$RESULTS_DIR" "$category-$testName" 2>&1)
testResult=$($LNX_PREFIX "../../../$EXE" "../../../$RESULTS_DIR" "$category-$testName" 2>&1)
ERR=$?
popd > /dev/null

View file

@ -0,0 +1,6 @@
Glut
====
These tests cover the initialization of GLUT, and verify that even when these
statements which make use of GLUT are the first thing in the program they still
execute correctly.

View file

@ -0,0 +1,5 @@
$CONSOLE
_Dest _Console
Print _DesktopHeight > 0
System

View file

@ -0,0 +1 @@
-1

View file

@ -0,0 +1,5 @@
$CONSOLE
_Dest _Console
Print _DesktopWidth > 0
System

View file

@ -0,0 +1 @@
-1

View file

@ -0,0 +1,6 @@
$CONSOLE
_Dest _Console
_Icon
Print "Got Past Icon!"
System

View file

@ -0,0 +1 @@
Got Past Icon!

View file

@ -0,0 +1,6 @@
$CONSOLE
_Dest _Console
_MouseHide
Print "Got Past MouseHide!"
System

View file

@ -0,0 +1 @@
Got Past MouseHide!

View file

@ -0,0 +1,6 @@
$CONSOLE
_Dest _Console
_MouseShow
Print "Got Past MouseShow!"
System

View file

@ -0,0 +1 @@
Got Past MouseShow!

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

View file

@ -0,0 +1,5 @@
$CONSOLE
_Dest _Console
Print _ScreenExists
System

View file

@ -0,0 +1 @@
1

View file

@ -0,0 +1,6 @@
$CONSOLE
_Dest _Console
_ScreenHide
Print "Got Past ScreenHide!"
System

View file

@ -0,0 +1 @@
Got Past ScreenHide!

View file

@ -0,0 +1,58 @@
$SCREENHIDE
$CONSOLE
_Dest _Console
ON ERROR GOTO errorhand
$IF WIN THEN
Print _DesktopHeight > 0
$ELSE
Print _DesktopHeight = 0
$END IF
$IF WIN THEN
Print _DesktopWidth > 0
$ELSE
Print _DesktopWidth = 0
$END IF
_Icon
Print "Got past icon!"
_MouseHide
Print "Got past MouseHide!"
_MouseShow
Print "Got past MouseHide!"
Print _ScreenExists
_ScreenHide
Print "Got past ScreenHide"
Print _ScreenIcon <> 0
$IF LINUX THEN
' Since these functions don't work on linux they also don't trigger errors
' We're just printing the error manually so the test passes on Linux
Print "Error:"; 5
Print "Error:"; 5
$ELSE
Print _ScreenX >= 0
Print _ScreenY >= 0
$END IF
_Title "foobar"
Print "Title: "; _Title$
Print _WindowHandle <> 0
Print _WindowHasFocus <= 0 ' This can be a bit random
_ScreenShow
Print "Got past ScreenShow!"
System
System
errorhand:
PRINT "Error:"; ERR
RESUME NEXT

View file

@ -0,0 +1,14 @@
-1
-1
Got past icon!
Got past MouseHide!
Got past MouseHide!
0
Got past ScreenHide
0
Error: 5
Error: 5
Title: foobar
0
-1
Got past ScreenShow!

View file

@ -0,0 +1,30 @@
$CONSOLE
_Dest _Console
_ScreenHide
Print _DesktopHeight > 0
Print _DesktopWidth > 0
_Icon
Print "Got Past Icon!"
_MouseHide
Print "Got Past MouseHide!"
_MouseShow
Print "Got Past MouseShow!"
Print _ScreenExists
Print _ScreenIcon <> 0
Print _ScreenX >= 0
Print _ScreenY >= 0
_Title "foobar"
Print "Title: "; _Title$
$IF WIN THEN
Print _WindowHandle <> 0
$ELSE
Print _WindowHandle = 0
$END IF
Print _WindowHasFocus <= 0 ' This can be a bit random
_ScreenShow
Print "Got past ScreenShow!"
System

View file

@ -0,0 +1,13 @@
-1
-1
Got Past Icon!
Got Past MouseHide!
Got Past MouseShow!
1
0
-1
-1
Title: foobar
-1
-1
Got past ScreenShow!

View file

@ -0,0 +1,5 @@
$CONSOLE
_Dest _Console
Print _ScreenIcon <> 0
System

View file

@ -0,0 +1 @@
0

View file

@ -0,0 +1,6 @@
$CONSOLE
_Dest _Console
_ScreenShow
Print "Got past ScreenShow!"
System

View file

@ -0,0 +1 @@
Got past ScreenShow!

View file

@ -0,0 +1,5 @@
$CONSOLE
_Dest _Console
Print _ScreenX >= 0
System

View file

@ -0,0 +1 @@
-1

View file

@ -0,0 +1,5 @@
$CONSOLE
_Dest _Console
Print _ScreenY >= 0
System

View file

@ -0,0 +1 @@
-1

View file

@ -0,0 +1,6 @@
$CONSOLE
_Dest _Console
_Title "foobar"
Print "Got past Title!"
System

View file

@ -0,0 +1 @@
Got past Title!

View file

@ -0,0 +1,5 @@
$CONSOLE
_Dest _Console
Print "Title: "; _Title$
System

View file

@ -0,0 +1 @@
Title:

View file

@ -0,0 +1,11 @@
$CONSOLE
_Dest _Console
' _WindowHandle only returns an actual handle on Windows
$IF WIN THEN
Print _WindowHandle <> 0
$ELSE
Print _WindowHandle = 0
$END IF
System

View file

@ -0,0 +1 @@
-1

View file

@ -0,0 +1,5 @@
$CONSOLE
_Dest _Console
Print _WindowHasFocus <= 0 ' This can be a bit random
System

View file

@ -0,0 +1 @@
-1