From 79697257a5378666a9fa0e7215de1e61673dfe8d Mon Sep 17 00:00:00 2001 From: jgravelle-google Date: Thu, 20 Apr 2017 11:01:18 -0700 Subject: [PATCH 01/22] Re-add missing SIGSTKSZ defines from musl 1.1.15 (#5149) --- system/lib/libc/musl/arch/emscripten/bits/signal.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/system/lib/libc/musl/arch/emscripten/bits/signal.h b/system/lib/libc/musl/arch/emscripten/bits/signal.h index 523a61d284942..58bc5e2c3a780 100644 --- a/system/lib/libc/musl/arch/emscripten/bits/signal.h +++ b/system/lib/libc/musl/arch/emscripten/bits/signal.h @@ -1,6 +1,11 @@ #if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \ || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define MINSIGSTKSZ 2048 +#define SIGSTKSZ 8192 +#endif + #ifdef _GNU_SOURCE #define REG_GS 0 #define REG_FS 1 From c43eb9f70296abca4395f8a95badb9fa5e6dfe45 Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Mon, 24 Apr 2017 11:17:34 -0700 Subject: [PATCH 02/22] add stub for __wait in src/library_pthreads_stub.js --- src/library_pthread_stub.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/library_pthread_stub.js b/src/library_pthread_stub.js index b85b50c37c49c..4683416f8119b 100644 --- a/src/library_pthread_stub.js +++ b/src/library_pthread_stub.js @@ -337,6 +337,8 @@ var LibraryPThreadStub = { _emscripten_atomic_fetch_and_and_u64: '__atomic_fetch_and_8', _emscripten_atomic_fetch_and_or_u64: '__atomic_fetch_or_8', _emscripten_atomic_fetch_and_xor_u64: '__atomic_fetch_xor_8', + + __wait: function() {}, }; mergeInto(LibraryManager.library, LibraryPThreadStub); From 263dbab4ecfcbea2390506dfcc207fd4745b5cc9 Mon Sep 17 00:00:00 2001 From: Matthew Collins Date: Mon, 24 Apr 2017 21:39:21 +0100 Subject: [PATCH 03/22] Fix emscripten_get_mouse_status (#5152) * Fix emscripten_get_mouse_status Fixes two issues: * `subarray`'s last argument is the end index not the length. * Used HEAP32 without shifting the pointer, changed to HEAP8 to simplify as well. * Add a test for emscripten_get_mouse_status --- AUTHORS | 1 + src/library_html5.js | 2 +- tests/test_html5_mouse.c | 15 ++++++++++++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index 70b4a235d9970..aa324ae746b2a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -287,3 +287,4 @@ a license to everyone to use it as detailed in LICENSE.) * Jakub Jirutka * Loo Rong Jie * Jean-François Geyelin +* Matthew Collins diff --git a/src/library_html5.js b/src/library_html5.js index 37604db5460b9..2cff046fc474e 100644 --- a/src/library_html5.js +++ b/src/library_html5.js @@ -1124,7 +1124,7 @@ var LibraryJSEvents = { // HTML5 does not really have a polling API for mouse events, so implement one manually by // returning the data from the most recently received event. This requires that user has registered // at least some no-op function as an event handler to any of the mouse function. - HEAP32.set(HEAP32.subarray(JSEvents.mouseEvent, {{{ C_STRUCTS.EmscriptenMouseEvent.__size__ }}}), mouseState); + HEAP8.set(HEAP8.subarray(JSEvents.mouseEvent, JSEvents.mouseEvent + {{{ C_STRUCTS.EmscriptenMouseEvent.__size__ }}}), mouseState); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, diff --git a/tests/test_html5_mouse.c b/tests/test_html5_mouse.c index 01f54de3ef113..84c4ff4e3d279 100644 --- a/tests/test_html5_mouse.c +++ b/tests/test_html5_mouse.c @@ -130,8 +130,21 @@ int main() for(var d in data) event[d] = data[d]; window.dispatchEvent(event); } - sendEvent('click', { screenX: 1, screenY: 1, clientX: 1, clientY: 1, button: 0, buttons: 1 }); + sendEvent('click', { screenX: 123, screenY: 456, clientX: 123, clientY: 456, button: 0, buttons: 1 }); ); + + // get_mouse_status should contain the results of the last event + EmscriptenMouseEvent mouseEvent; + ret = emscripten_get_mouse_status(&mouseEvent); + TEST_RESULT(emscripten_get_mouse_status); + + if (mouseEvent.screenX != 123 || mouseEvent.screenY != 456 + || mouseEvent.clientX != 123 || mouseEvent.clientY != 456) + { + printf("ERROR! Incorrect mouse status\n"); + report_result(1); + } + // Test that unregistering a callback works. Clicks should no longer be received. ret = emscripten_set_click_callback(0, 0, 1, 0); TEST_RESULT(emscripten_set_click_callback); From e9ba13b56511fadab7f83907b440d1030ae3de8d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 25 Apr 2017 14:01:03 -0700 Subject: [PATCH 04/22] add some -g testing to fuzzer --- tests/fuzz/csmith_driver.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/fuzz/csmith_driver.py b/tests/fuzz/csmith_driver.py index 24e85f0aa331d..f2346683458c2 100755 --- a/tests/fuzz/csmith_driver.py +++ b/tests/fuzz/csmith_driver.py @@ -103,6 +103,8 @@ def try_js(args=[]): js_args = [shared.PYTHON, shared.EMCC, fullname, '-o', filename + '.js'] + [opts] + llvm_opts + CSMITH_CFLAGS + args + ['-w'] if TEST_BINARYEN: js_args += ['-s', 'BINARYEN=1', '-s', 'BINARYEN_TRAP_MODE="js"'] + if random.random() < 0.5: + js_args += ['-g'] if random.random() < 0.1: if random.random() < 0.5: js_args += ['--js-opts', '0'] From 969bb16d89bb5fd0b35d5b85c858f6dc8e0b9369 Mon Sep 17 00:00:00 2001 From: haraldreingruber Date: Tue, 25 Apr 2017 23:23:53 +0200 Subject: [PATCH 05/22] =?UTF-8?q?updating=20empterpreter=20docs=20accordin?= =?UTF-8?q?g=20to=20this=20discussion:=20https://grou=E2=80=A6=20(#5156)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * updating empterpreter docs according to this discussion: https://groups.google.com/d/msg/emscripten-discuss/j9C2ndhcN1E/7M6AnWFrEQAJ * add explanation why EMTERPRETIFY=1 forces js-opts=1 (feedback from PR) --- site/source/docs/porting/emterpreter.rst | 2 ++ site/source/docs/tools_reference/emcc.rst | 2 ++ 2 files changed, 4 insertions(+) diff --git a/site/source/docs/porting/emterpreter.rst b/site/source/docs/porting/emterpreter.rst index 86bd5395c5d25..1538e67c4e37d 100644 --- a/site/source/docs/porting/emterpreter.rst +++ b/site/source/docs/porting/emterpreter.rst @@ -24,6 +24,8 @@ You can optionally use ``-s 'EMTERPRETIFY_FILE="data.binary"'`` to store the emt As usual, you can grep the ``tests/`` folder for examples of emterpreter usage in the test suite (search for ``EMTERPRETIFY``). + .. note:: Setting ``EMTERPRETIFY=1`` forces ``js-opts=1``, because we convert to the emterpreter's binary format using a js-optimizer pass. + Specific Use Cases ================== diff --git a/site/source/docs/tools_reference/emcc.rst b/site/source/docs/tools_reference/emcc.rst index f53b3ff8932a2..cda2ab112c867 100644 --- a/site/source/docs/tools_reference/emcc.rst +++ b/site/source/docs/tools_reference/emcc.rst @@ -202,6 +202,8 @@ Options that are modified or new in *emcc* are listed below: You normally don't need to specify this option, as ``-O`` with an optimization level will set a good value. + .. note:: Some options might override this flag (e.g. ``EMTERPRETIFY``, ``DEAD_FUNCTIONS``, ``OUTLINING_LIMIT``, ``SAFE_HEAP`` and ``SPLIT_MEMORY`` override the value with ``js-opts=1``), because they depend on the js-optimizer. + .. _emcc-llvm-opts: ``--llvm-opts `` From d64ea61f47dd46e6166bcc906a4f252ae7aee872 Mon Sep 17 00:00:00 2001 From: jgravelle-google Date: Tue, 25 Apr 2017 14:42:36 -0700 Subject: [PATCH 06/22] Refactor emscripten py pt2 - finished pass of asmjs emscript (#5150) * Shorten local variable namein get_exported_implemented_functions * Split creation and warning from get_implemented_functions * Rename check_implemented_functions to check_all_implemented, on account of that's what it checks. Also extract is_already_implemented for readability * Extract create_first_in_asm, make make_get_set a top-level function * Extract create_named_globals * Extract create_runtime_funcs * Extract finalize_funcs_js * Hoist finalize_funcs_js, remove unused args from finalize_output * Remove unused return value (forwarded_json) * Extract create_memory_views * Programmatically generate create_memory_views * Share heap type information in a class * Tweak make_get_set * Change array concatenation to one array literal ('+'s to ','s) * Hoist bigger funcs_js parts into explanatory variables * Extract and refactor create_asm_start_pre * Extract and refactor create_runtime_library_overrides * Dedent finalize_output * Reorder function declarations to move higher-level functions to the top of emscripten.py * Extract big string literal constructions from finalize_funcs_js * Single -> double newline between functions * Move more backend arg construction into backend_args_for_settings * Rename backend_args_for_settings to create_backend_args * Better names for mftCall creation and module finalizing * Dedent function_tables_and_exports * Remove post-processing pass to replace '{{{ FTM_[sig] }}}', just write masks directly * Move module modification to finalize_module, rename finalize_output to write_output_file * Rename finalize_module to create_module for consistency * Remove unused tempBigInt*s * Use heap_name for greppability, also add docstrings with generated symbols also for greppability --- emscripten.py | 860 +++++++++++++++++++++++++++----------------------- 1 file changed, 467 insertions(+), 393 deletions(-) diff --git a/emscripten.py b/emscripten.py index 1c5b293fc8c1b..b48f0ec445ca4 100755 --- a/emscripten.py +++ b/emscripten.py @@ -98,13 +98,14 @@ def emscript(infile, settings, outfile, libraries=None, compiler_engine=None, with ToolchainProfiler.profile_block('function_tables_and_exports'): (post, funcs_js, sending, receiving, asm_setup, the_global, asm_global_vars, - asm_global_funcs, pre_tables, final_function_tables, exports, function_table_data, - forwarded_json) = function_tables_and_exports(funcs, metadata, mem_init, glue, - forwarded_data, settings, outfile, DEBUG) - with ToolchainProfiler.profile_block('finalize_output'): - finalize_output(metadata, post, funcs_js, sending, receiving, asm_setup, the_global, - asm_global_vars, asm_global_funcs, pre_tables, final_function_tables, - exports, function_table_data, forwarded_json, settings, outfile, DEBUG) + asm_global_funcs, pre_tables, final_function_tables, exports, function_table_data) = ( + function_tables_and_exports(funcs, metadata, mem_init, glue, forwarded_data, settings, outfile, DEBUG)) + with ToolchainProfiler.profile_block('write_output_file'): + function_table_sigs = function_table_data.keys() + module = create_module(funcs_js, asm_setup, the_global, sending, receiving, asm_global_vars, + asm_global_funcs, pre_tables, final_function_tables, function_table_sigs, + exports, metadata, settings) + write_output_file(metadata, post, module, function_table_data, settings, outfile, DEBUG) success = True @@ -113,12 +114,11 @@ def emscript(infile, settings, outfile, libraries=None, compiler_engine=None, if not success: shared.try_delete(outfile.name) # remove partial output + def compile_js(infile, settings, temp_files, DEBUG): """Compile infile with asm.js backend, return the contents of the compiled js""" with temp_files.get_file('.4.js') as temp_js: - backend_compiler = os.path.join(shared.LLVM_ROOT, 'llc') - backend_args = [backend_compiler, infile, '-march=js', '-filetype=asm', '-o', temp_js] - backend_args += backend_args_for_settings(settings) + backend_args = create_backend_args(infile, temp_js, settings) if DEBUG: logging.debug('emscript: llvm backend: ' + ' '.join(backend_args)) @@ -134,52 +134,6 @@ def compile_js(infile, settings, temp_files, DEBUG): return backend_output -def backend_args_for_settings(settings): - """Create args for asm.js backend from settings dict""" - args = [ - '-emscripten-stack-size=%d' % settings['TOTAL_STACK'], - '-O' + str(settings['OPT_LEVEL']), - ] - if settings['PRECISE_F32']: - args += ['-emscripten-precise-f32'] - if settings['USE_PTHREADS']: - args += ['-emscripten-enable-pthreads'] - if settings['WARN_UNALIGNED']: - args += ['-emscripten-warn-unaligned'] - if settings['RESERVED_FUNCTION_POINTERS'] > 0: - args += ['-emscripten-reserved-function-pointers=%d' % settings['RESERVED_FUNCTION_POINTERS']] - if settings['ASSERTIONS'] > 0: - args += ['-emscripten-assertions=%d' % settings['ASSERTIONS']] - if settings['ALIASING_FUNCTION_POINTERS'] == 0: - args += ['-emscripten-no-aliasing-function-pointers'] - if settings['EMULATED_FUNCTION_POINTERS']: - args += ['-emscripten-emulated-function-pointers'] - if settings['RELOCATABLE']: - args += ['-emscripten-relocatable'] - args += ['-emscripten-global-base=0'] - elif settings['GLOBAL_BASE'] >= 0: - args += ['-emscripten-global-base=%d' % settings['GLOBAL_BASE']] - if settings['SIDE_MODULE']: - args += ['-emscripten-side-module'] - if settings['DISABLE_EXCEPTION_CATCHING'] != 1: - args += ['-enable-emscripten-cpp-exceptions'] - if settings['DISABLE_EXCEPTION_CATCHING'] == 2: - args += ['-emscripten-cpp-exceptions-whitelist=' + ','.join(settings['EXCEPTION_CATCHING_WHITELIST'] or ['fake'])] - if settings['ASYNCIFY']: - args += ['-emscripten-asyncify'] - args += ['-emscripten-asyncify-functions=' + ','.join(settings['ASYNCIFY_FUNCTIONS'])] - args += ['-emscripten-asyncify-whitelist=' + ','.join(settings['ASYNCIFY_WHITELIST'])] - if settings['NO_EXIT_RUNTIME']: - args += ['-emscripten-no-exit-runtime'] - if settings['BINARYEN']: - args += ['-emscripten-wasm'] - if shared.Building.is_wasm_only(): - args += ['-emscripten-only-wasm'] - if settings['CYBERDWARF']: - args += ['-enable-cyberdwarf'] - return args - - def parse_backend_output(backend_output, DEBUG): start_funcs_marker = '// EMSCRIPTEN_START_FUNCTIONS' end_funcs_marker = '// EMSCRIPTEN_END_FUNCTIONS' @@ -277,6 +231,229 @@ def compiler_glue(metadata, settings, libraries, compiler_engine, temp_files, DE return glue, forwarded_data +def function_tables_and_exports(funcs, metadata, mem_init, glue, forwarded_data, settings, outfile, DEBUG): + if DEBUG: + logging.debug('emscript: python processing: function tables and exports') + t = time.time() + + forwarded_json = json.loads(forwarded_data) + + # merge in information from llvm backend + + function_table_data = metadata['tables'] + + # merge forwarded data + settings['EXPORTED_FUNCTIONS'] = forwarded_json['EXPORTED_FUNCTIONS'] + + pre, post = glue.split('// EMSCRIPTEN_END_FUNCS') + + #print >> sys.stderr, 'glue:', pre, '\n\n||||||||||||||||\n\n', post, '...............' + + pre = memory_and_global_initializers(pre, metadata, mem_init, settings) + pre, funcs_js = get_js_funcs(pre, funcs) + all_exported_functions = get_all_exported_functions(function_table_data, settings) + all_implemented = get_all_implemented(forwarded_json, metadata) + check_all_implemented(all_implemented, pre, settings) + implemented_functions = get_implemented_functions(metadata) + pre = include_asm_consts(pre, forwarded_json, metadata, settings) + #if DEBUG: outfile.write('// pre\n') + outfile.write(pre) + pre = None + + #if DEBUG: outfile.write('// funcs\n') + + # Move preAsms to their right place + def move_preasm(m): + contents = m.groups(0)[0] + outfile.write(contents + '\n') + return '' + if not settings['BOOTSTRAPPING_STRUCT_INFO'] and len(funcs_js) > 1: + funcs_js[1] = re.sub(r'/\* PRE_ASM \*/(.*)\n', move_preasm, funcs_js[1]) + + if 'pre' in function_table_data: + pre_tables = function_table_data['pre'] + del function_table_data['pre'] + else: + pre_tables = '' + + function_table_sigs = function_table_data.keys() + + in_table, debug_tables, function_tables_defs = make_function_tables_defs( + implemented_functions, all_implemented, function_table_data, settings, metadata) + + exported_implemented_functions = get_exported_implemented_functions( + all_exported_functions, all_implemented, metadata, settings) + + asm_setup = create_asm_setup(debug_tables, function_table_data, metadata, settings) + basic_funcs = create_basic_funcs(function_table_sigs, settings) + basic_vars = create_basic_vars(exported_implemented_functions, forwarded_json, metadata, settings) + + shared.Settings.copy(settings) + + funcs_js += create_mftCall_funcs(function_table_data, settings) + + exports = create_exports(exported_implemented_functions, in_table, function_table_data, metadata, settings) + + # calculate globals + try: + del forwarded_json['Variables']['globals']['_llvm_global_ctors'] # not a true variable + except: + pass + if not settings['RELOCATABLE']: + global_vars = metadata['externs'] + else: + global_vars = [] # linkable code accesses globals through function calls + global_funcs = list(set([key for key, value in forwarded_json['Functions']['libraryFunctions'].iteritems() if value != 2]) + .difference(set(global_vars)).difference(implemented_functions)) + if settings['RELOCATABLE']: + global_funcs += ['g$' + extern for extern in metadata['externs']] + + bg_funcs = basic_funcs + global_funcs + bg_vars = basic_vars + global_vars + asm_global_funcs= create_asm_global_funcs(bg_funcs, metadata, settings) + asm_global_vars = create_asm_global_vars(bg_vars, settings) + + the_global = create_the_global(metadata, settings) + sending_vars = basic_funcs + global_funcs + basic_vars + global_vars + sending = '{ ' + ', '.join(['"' + math_fix(s) + '": ' + s for s in sending_vars]) + ' }' + + receiving = create_receiving(function_table_data, function_tables_defs, + exported_implemented_functions, settings) + + function_tables_impls = make_function_tables_impls(function_table_data, settings) + final_function_tables = '\n'.join(function_tables_impls) + '\n' + function_tables_defs + if settings.get('EMULATED_FUNCTION_POINTERS'): + final_function_tables = ( + final_function_tables + .replace("asm['", '') + .replace("']", '') + .replace('var SIDE_FUNCTION_TABLE_', 'var FUNCTION_TABLE_') + .replace('var dynCall_', '//') + ) + + if DEBUG: + logging.debug('asm text sizes' + str([ + map(len, funcs_js), len(asm_setup), len(asm_global_vars), len(asm_global_funcs), len(pre_tables), + len('\n'.join(function_tables_impls)), len(function_tables_defs) + (function_tables_defs.count('\n') * len(' ')), + len(exports), len(the_global), len(sending), len(receiving)])) + logging.debug(' emscript: python processing: function tables and exports took %s seconds' % (time.time() - t)) + + return (post, funcs_js, sending, receiving, asm_setup, the_global, asm_global_vars, + asm_global_funcs, pre_tables, final_function_tables, exports, function_table_data) + + +def create_module(funcs_js, asm_setup, the_global, sending, receiving, asm_global_vars, + asm_global_funcs, pre_tables, final_function_tables, function_table_sigs, + exports, metadata, settings): + receiving += create_named_globals(metadata, settings) + runtime_funcs = create_runtime_funcs(exports, settings) + + asm_start_pre = create_asm_start_pre(asm_setup, the_global, sending, metadata, settings) + asm_temp_vars = create_asm_temp_vars(settings) + asm_start = asm_start_pre + '\n' + asm_global_vars + asm_temp_vars + '\n' + asm_global_funcs + + temp_float = ' var tempFloat = %s;\n' % ('Math_fround(0)' if provide_fround(settings) else '0.0') + async_state = ' var asyncState = 0;\n' if settings.get('EMTERPRETIFY_ASYNC') else '' + f0_fround = ' const f0 = Math_fround(0);\n' if provide_fround(settings) else '' + + replace_memory = create_replace_memory(settings) + + start_funcs_marker = '\n// EMSCRIPTEN_START_FUNCS\n' + + asm_end = create_asm_end(exports, settings) + + runtime_library_overrides = create_runtime_library_overrides(settings) + + module = [ + asm_start, + temp_float, + async_state, + f0_fround, + replace_memory, + start_funcs_marker + ] + runtime_funcs + funcs_js + ['\n ', + pre_tables, final_function_tables, asm_end, + '\n', receiving, ';\n', runtime_library_overrides] + + if settings['SIDE_MODULE']: + module.append(''' +Runtime.registerFunctions(%(sigs)s, Module); +''' % { 'sigs': str(map(str, function_table_sigs)) }) + + return module + + +def write_output_file(metadata, post, module, function_table_data, settings, outfile, DEBUG): + if DEBUG: + logging.debug('emscript: python processing: finalize') + t = time.time() + + for i in range(len(module)): # do this loop carefully to save memory + if WINDOWS: module[i] = module[i].replace('\r\n', '\n') # Normalize to UNIX line endings, otherwise writing to text file will duplicate \r\n to \r\r\n! + outfile.write(module[i]) + module = None + + if WINDOWS: post = post.replace('\r\n', '\n') # Normalize to UNIX line endings, otherwise writing to text file will duplicate \r\n to \r\r\n! + outfile.write(post) + + if DEBUG: + logging.debug(' emscript: python processing: finalize took %s seconds' % (time.time() - t)) + + if settings['CYBERDWARF']: + assert('cyberdwarf_data' in metadata) + cd_file_name = outfile.name + ".cd" + with open(cd_file_name, "w") as cd_file: + json.dump({ 'cyberdwarf': metadata['cyberdwarf_data'] }, cd_file) + + +def create_backend_args(infile, temp_js, settings): + """Create args for asm.js backend from settings dict""" + backend_compiler = os.path.join(shared.LLVM_ROOT, 'llc') + args = [ + backend_compiler, infile, '-march=js', '-filetype=asm', '-o', temp_js, + '-emscripten-stack-size=%d' % settings['TOTAL_STACK'], + '-O' + str(settings['OPT_LEVEL']), + ] + if settings['PRECISE_F32']: + args += ['-emscripten-precise-f32'] + if settings['USE_PTHREADS']: + args += ['-emscripten-enable-pthreads'] + if settings['WARN_UNALIGNED']: + args += ['-emscripten-warn-unaligned'] + if settings['RESERVED_FUNCTION_POINTERS'] > 0: + args += ['-emscripten-reserved-function-pointers=%d' % settings['RESERVED_FUNCTION_POINTERS']] + if settings['ASSERTIONS'] > 0: + args += ['-emscripten-assertions=%d' % settings['ASSERTIONS']] + if settings['ALIASING_FUNCTION_POINTERS'] == 0: + args += ['-emscripten-no-aliasing-function-pointers'] + if settings['EMULATED_FUNCTION_POINTERS']: + args += ['-emscripten-emulated-function-pointers'] + if settings['RELOCATABLE']: + args += ['-emscripten-relocatable'] + args += ['-emscripten-global-base=0'] + elif settings['GLOBAL_BASE'] >= 0: + args += ['-emscripten-global-base=%d' % settings['GLOBAL_BASE']] + if settings['SIDE_MODULE']: + args += ['-emscripten-side-module'] + if settings['DISABLE_EXCEPTION_CATCHING'] != 1: + args += ['-enable-emscripten-cpp-exceptions'] + if settings['DISABLE_EXCEPTION_CATCHING'] == 2: + args += ['-emscripten-cpp-exceptions-whitelist=' + ','.join(settings['EXCEPTION_CATCHING_WHITELIST'] or ['fake'])] + if settings['ASYNCIFY']: + args += ['-emscripten-asyncify'] + args += ['-emscripten-asyncify-functions=' + ','.join(settings['ASYNCIFY_FUNCTIONS'])] + args += ['-emscripten-asyncify-whitelist=' + ','.join(settings['ASYNCIFY_WHITELIST'])] + if settings['NO_EXIT_RUNTIME']: + args += ['-emscripten-no-exit-runtime'] + if settings['BINARYEN']: + args += ['-emscripten-wasm'] + if shared.Building.is_wasm_only(): + args += ['-emscripten-only-wasm'] + if settings['CYBERDWARF']: + args += ['-enable-cyberdwarf'] + return args + + def optimize_syscalls(declares, settings, DEBUG): """Disables filesystem if only a limited subset of syscalls is used. @@ -345,117 +522,6 @@ def save_settings(): cwd=path_from_root('src'), error_limit=300) -def function_tables_and_exports(funcs, metadata, mem_init, glue, forwarded_data, settings, outfile, DEBUG): - if DEBUG: - logging.debug('emscript: python processing: function tables and exports') - t = time.time() - - forwarded_json = json.loads(forwarded_data) - - # merge in information from llvm backend - - function_table_data = metadata['tables'] - - # merge forwarded data - settings['EXPORTED_FUNCTIONS'] = forwarded_json['EXPORTED_FUNCTIONS'] - - pre, post = glue.split('// EMSCRIPTEN_END_FUNCS') - - #print >> sys.stderr, 'glue:', pre, '\n\n||||||||||||||||\n\n', post, '...............' - - pre = memory_and_global_initializers(pre, metadata, mem_init, settings) - pre, funcs_js = get_js_funcs(pre, funcs) - all_exported_functions = get_all_exported_functions(function_table_data, settings) - all_implemented = get_all_implemented(forwarded_json, metadata) - implemented_functions = get_implemented_functions(pre, metadata, settings, all_implemented) - pre = include_asm_consts(pre, forwarded_json, metadata, settings) - #if DEBUG: outfile.write('// pre\n') - outfile.write(pre) - pre = None - - #if DEBUG: outfile.write('// funcs\n') - - # Move preAsms to their right place - def move_preasm(m): - contents = m.groups(0)[0] - outfile.write(contents + '\n') - return '' - if not settings['BOOTSTRAPPING_STRUCT_INFO'] and len(funcs_js) > 1: - funcs_js[1] = re.sub(r'/\* PRE_ASM \*/(.*)\n', move_preasm, funcs_js[1]) - - if 'pre' in function_table_data: - pre_tables = function_table_data['pre'] - del function_table_data['pre'] - else: - pre_tables = '' - - function_table_sigs = function_table_data.keys() - - in_table, debug_tables, function_tables_defs = make_function_tables_defs( - implemented_functions, all_implemented, function_table_data, settings, metadata) - - exported_implemented_functions = get_exported_implemented_functions( - all_exported_functions, all_implemented, metadata, settings) - - asm_setup = create_asm_setup(debug_tables, function_table_data, metadata, settings) - basic_funcs = create_basic_funcs(function_table_sigs, settings) - basic_vars = create_basic_vars(exported_implemented_functions, forwarded_json, metadata, settings) - - shared.Settings.copy(settings) - - funcs_js += setup_funcs_js(function_table_sigs, settings) - - exports = create_exports(exported_implemented_functions, in_table, function_table_data, metadata, settings) - - # calculate globals - try: - del forwarded_json['Variables']['globals']['_llvm_global_ctors'] # not a true variable - except: - pass - if not settings['RELOCATABLE']: - global_vars = metadata['externs'] - else: - global_vars = [] # linkable code accesses globals through function calls - global_funcs = list(set([key for key, value in forwarded_json['Functions']['libraryFunctions'].iteritems() if value != 2]) - .difference(set(global_vars)).difference(implemented_functions)) - if settings['RELOCATABLE']: - global_funcs += ['g$' + extern for extern in metadata['externs']] - - bg_funcs = basic_funcs + global_funcs - bg_vars = basic_vars + global_vars - asm_global_funcs= create_asm_global_funcs(bg_funcs, metadata, settings) - asm_global_vars = create_asm_global_vars(bg_vars, settings) - - the_global = create_the_global(metadata, settings) - sending_vars = basic_funcs + global_funcs + basic_vars + global_vars - sending = '{ ' + ', '.join(['"' + math_fix(s) + '": ' + s for s in sending_vars]) + ' }' - - receiving = create_receiving(function_table_data, function_tables_defs, - exported_implemented_functions, settings) - - function_tables_impls = make_function_tables_impls(function_table_sigs, settings) - final_function_tables = '\n'.join(function_tables_impls) + '\n' + function_tables_defs - if settings.get('EMULATED_FUNCTION_POINTERS'): - final_function_tables = ( - final_function_tables - .replace("asm['", '') - .replace("']", '') - .replace('var SIDE_FUNCTION_TABLE_', 'var FUNCTION_TABLE_') - .replace('var dynCall_', '//') - ) - - if DEBUG: - logging.debug('asm text sizes' + str([ - map(len, funcs_js), len(asm_setup), len(asm_global_vars), len(asm_global_funcs), len(pre_tables), - len('\n'.join(function_tables_impls)), len(function_tables_defs) + (function_tables_defs.count('\n') * len(' ')), - len(exports), len(the_global), len(sending), len(receiving)])) - logging.debug(' emscript: python processing: function tables and exports took %s seconds' % (time.time() - t)) - - return (post, funcs_js, sending, receiving, asm_setup, the_global, asm_global_vars, - asm_global_funcs, pre_tables, final_function_tables, exports, - function_table_data, forwarded_json) - - def memory_and_global_initializers(pre, metadata, mem_init, settings): global_initializers = str(', '.join(map(lambda i: '{ func: function() { %s() } }' % i, metadata['initializers']))) @@ -506,45 +572,50 @@ def get_all_implemented(forwarded_json, metadata): return metadata['implementedFunctions'] + forwarded_json['Functions']['implementedFunctions'].keys() # XXX perf? +def check_all_implemented(all_implemented, pre, settings): + if settings['ASSERTIONS'] and settings.get('ORIGINAL_EXPORTED_FUNCTIONS'): + original_exports = settings['ORIGINAL_EXPORTED_FUNCTIONS'] + if original_exports[0] == '@': + original_exports = json.loads(open(original_exports[1:]).read()) + for requested in original_exports: + if not is_already_implemented(requested, pre, all_implemented): + # could be a js library func + logging.warning('function requested to be exported, but not implemented: "%s"', requested) + + +def is_already_implemented(requested, pre, all_implemented): + is_implemented = requested in all_implemented + # special-case malloc, EXPORTED by default for internal use, but we bake in a trivial allocator and warn at runtime if used in ASSERTIONS + is_exception = requested == '_malloc' + in_pre = ('function ' + requested.encode('utf-8')) in pre + return is_implemented or is_exception or in_pre + def get_exported_implemented_functions(all_exported_functions, all_implemented, metadata, settings): - exported_implemented_functions = set(metadata['exports']) + funcs = set(metadata['exports']) export_bindings = settings['EXPORT_BINDINGS'] export_all = settings['EXPORT_ALL'] for key in all_implemented: if key in all_exported_functions or export_all or (export_bindings and key.startswith('_emscripten_bind')): - exported_implemented_functions.add(key) + funcs.add(key) - exported_implemented_functions = list(exported_implemented_functions) + metadata['initializers'] + funcs = list(funcs) + metadata['initializers'] if not settings['ONLY_MY_CODE']: - exported_implemented_functions.append('runPostSets') + funcs.append('runPostSets') if settings['ALLOW_MEMORY_GROWTH']: - exported_implemented_functions.append('_emscripten_replace_memory') + funcs.append('_emscripten_replace_memory') if not settings['SIDE_MODULE']: - exported_implemented_functions += ['stackAlloc', 'stackSave', 'stackRestore', 'establishStackSpace'] + funcs += ['stackAlloc', 'stackSave', 'stackRestore', 'establishStackSpace'] if settings['SAFE_HEAP']: - exported_implemented_functions += ['setDynamicTop'] + funcs += ['setDynamicTop'] if not settings['RELOCATABLE']: - exported_implemented_functions += ['setTempRet0', 'getTempRet0'] + funcs += ['setTempRet0', 'getTempRet0'] if not (settings['BINARYEN'] and settings['SIDE_MODULE']): - exported_implemented_functions += ['setThrew'] - exported_implemented_functions = list(set(exported_implemented_functions)) - return exported_implemented_functions - + funcs += ['setThrew'] + return list(set(funcs)) -def get_implemented_functions(pre, metadata, settings, all_implemented): - implemented_functions = set(metadata['implementedFunctions']) - if settings['ASSERTIONS'] and settings.get('ORIGINAL_EXPORTED_FUNCTIONS'): - original_exports = settings['ORIGINAL_EXPORTED_FUNCTIONS'] - if original_exports[0] == '@': original_exports = json.loads(open(original_exports[1:]).read()) - for requested in original_exports: - # check if already implemented - # special-case malloc, EXPORTED by default for internal use, but we bake in a trivial allocator and warn at runtime if used in ASSERTIONS \ - if requested not in all_implemented and \ - requested != '_malloc' and \ - (('function ' + requested.encode('utf-8')) not in pre): # could be a js library func - logging.warning('function requested to be exported, but not implemented: "%s"', requested) - return implemented_functions +def get_implemented_functions(metadata): + return set(metadata['implementedFunctions']) def include_asm_consts(pre, forwarded_json, metadata, settings): @@ -736,13 +807,14 @@ def math_fix(g): return g if not g.startswith('Math_') else g.split('_')[1] -def make_function_tables_impls(function_table_sigs, settings): +def make_function_tables_impls(function_table_data, settings): function_tables_impls = [] - for sig in function_table_sigs: + for sig, table in function_table_data.iteritems(): args = ','.join(['a' + str(i) for i in range(1, len(sig))]) arg_coercions = ' '.join(['a' + str(i) + '=' + shared.JS.make_coercion('a' + str(i), sig[i], settings) + ';' for i in range(1, len(sig))]) coerced_args = ','.join([shared.JS.make_coercion('a' + str(i), sig[i], settings) for i in range(1, len(sig))]) - ret = ('return ' if sig[0] != 'v' else '') + shared.JS.make_coercion('FUNCTION_TABLE_%s[index&{{{ FTM_%s }}}](%s)' % (sig, sig, coerced_args), sig[0], settings) + sig_mask = str(table.count(',')) + ret = ('return ' if sig[0] != 'v' else '') + shared.JS.make_coercion('FUNCTION_TABLE_%s[index&%s](%s)' % (sig, sig_mask, coerced_args), sig[0], settings) if not settings['EMULATED_FUNCTION_POINTERS']: function_tables_impls.append(''' function dynCall_%s(index%s%s) { @@ -769,11 +841,11 @@ def make_function_tables_impls(function_table_sigs, settings): return function_tables_impls -def setup_funcs_js(function_table_sigs, settings): - funcs_js = [] - for sig in function_table_sigs: - if settings.get('EMULATED_FUNCTION_POINTERS'): - if settings.get('RELOCATABLE') and not settings['BINARYEN']: # in wasm, emulated function pointers are just simple table calls +def create_mftCall_funcs(function_table_data, settings): + mftCall_funcs = [] + if settings.get('EMULATED_FUNCTION_POINTERS'): + if settings.get('RELOCATABLE') and not settings['BINARYEN']: # in wasm, emulated function pointers are just simple table calls + for sig, table in function_table_data.iteritems(): params = ','.join(['ptr'] + ['p%d' % p for p in range(len(sig)-1)]) coerced_params = ','.join([shared.JS.make_coercion('ptr', 'i', settings)] + [shared.JS.make_coercion('p%d', unfloat(sig[p+1]), settings) % p for p in range(len(sig)-1)]) coercions = ';'.join(['ptr = ptr | 0'] + ['p%d = %s' % (p, shared.JS.make_coercion('p%d' % p, unfloat(sig[p+1]), settings)) for p in range(len(sig)-1)]) + ';' @@ -783,13 +855,14 @@ def setup_funcs_js(function_table_sigs, settings): if settings['EMULATED_FUNCTION_POINTERS'] == 1: body = final_return else: - body = ('if (((ptr|0) >= (fb|0)) & ((ptr|0) < (fb + {{{ FTM_' + sig + ' }}} | 0))) { ' + maybe_return + ' ' + + sig_mask = str(table.count(',')) + body = ('if (((ptr|0) >= (fb|0)) & ((ptr|0) < (fb + ' + sig_mask + ' | 0))) { ' + maybe_return + ' ' + shared.JS.make_coercion( - 'FUNCTION_TABLE_' + sig + '[(ptr-fb)&{{{ FTM_' + sig + ' }}}](' + + 'FUNCTION_TABLE_' + sig + '[(ptr-fb)&' + sig_mask + '](' + mini_coerced_params + ')', sig[0], settings, ffi_arg=True ) + '; ' + ('return;' if sig[0] == 'v' else '') + ' }' + final_return) - funcs_js.append(make_func('mftCall_' + sig, body, params, coercions) + '\n') - return funcs_js + mftCall_funcs.append(make_func('mftCall_' + sig, body, params, coercions) + '\n') + return mftCall_funcs def get_function_pointer_error(sig, function_table_sigs, settings): @@ -807,10 +880,10 @@ def get_function_pointer_error(sig, function_table_sigs, settings): extra += other + ': " + debug_table_' + other + '[x] + " ' extra += '"); ' return 'Module["printErr"]("Invalid function pointer' + pointer + 'called with signature \'' + sig + '\'. ' + \ - 'Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? ' + \ - 'Or calling a function with an incorrect type, which will fail? ' + \ - '(it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)' + \ - '"); ' + extra + 'Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? ' + \ + 'Or calling a function with an incorrect type, which will fail? ' + \ + '(it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)' + \ + '"); ' + extra def signature_sort_key(sig): @@ -1020,7 +1093,7 @@ def check(extern): asm_setup += setup_function_pointers(function_table_sigs, settings) if settings.get('EMULATED_FUNCTION_POINTERS'): - function_tables_impls = make_function_tables_impls(function_table_sigs, settings) + function_tables_impls = make_function_tables_impls(function_table_data, settings) asm_setup += '\n' + '\n'.join(function_tables_impls) + '\n' return asm_setup @@ -1080,6 +1153,7 @@ def create_basic_funcs(function_table_sigs, settings): basic_funcs.append('ftCall_%s' % sig) return basic_funcs + def create_basic_vars(exported_implemented_functions, forwarded_json, metadata, settings): basic_vars = ['DYNAMICTOP_PTR', 'tempDoublePtr', 'ABORT'] if not (settings['BINARYEN'] and settings['SIDE_MODULE']): @@ -1101,6 +1175,7 @@ def create_basic_vars(exported_implemented_functions, forwarded_json, metadata, basic_vars += ['___async', '___async_unwind', '___async_retval', '___async_cur_frame'] return basic_vars + def create_exports(exported_implemented_functions, in_table, function_table_data, metadata, settings): quote = quoter(settings) asm_runtime_funcs = create_asm_runtime_funcs(settings) @@ -1193,83 +1268,36 @@ def create_receiving(function_table_data, function_tables_defs, exported_impleme return receiving -def finalize_output(metadata, post, funcs_js, sending, receiving, asm_setup, the_global, - asm_global_vars, asm_global_funcs, pre_tables, final_function_tables, exports, - function_table_data, forwarded_json, settings, outfile, DEBUG): - if DEBUG: - logging.debug('emscript: python processing: finalize') - t = time.time() - - access_quote = access_quoter(settings) - - if settings['RELOCATABLE']: - receiving += ''' +def create_named_globals(metadata, settings): + named_globals = '' + if settings['RELOCATABLE']: + named_globals += ''' var NAMED_GLOBALS = { %s }; for (var named in NAMED_GLOBALS) { Module['_' + named] = gb + NAMED_GLOBALS[named]; } Module['NAMED_GLOBALS'] = NAMED_GLOBALS; ''' % ', '.join('"' + k + '": ' + str(v) for k, v in metadata['namedGlobals'].iteritems()) - if settings['BINARYEN']: - # wasm side modules are pure wasm, and cannot create their g$..() methods, so we help them out - # TODO: this works if we are the main module, but if the supplying module is later, it won't, so - # we'll need another solution for that. one option is to scan the module imports, if/when - # wasm supports that, then the loader can do this. - receiving += ''' + if settings['BINARYEN']: + # wasm side modules are pure wasm, and cannot create their g$..() methods, so we help them out + # TODO: this works if we are the main module, but if the supplying module is later, it won't, so + # we'll need another solution for that. one option is to scan the module imports, if/when + # wasm supports that, then the loader can do this. + named_globals += ''' for (var named in NAMED_GLOBALS) { (function(named) { Module['g$_' + named] = function() { return Module['_' + named] }; })(named); } ''' - receiving += ''.join(["Module['%s'] = Module['%s']\n" % (k, v) for k, v in metadata['aliases'].iteritems()]) + named_globals += ''.join(["Module['%s'] = Module['%s']\n" % (k, v) for k, v in metadata['aliases'].iteritems()]) + return named_globals - if settings['USE_PTHREADS']: - shared_array_buffer = "Module.asmGlobalArg['Atomics'] = Atomics;" - else: - shared_array_buffer = '' - - first_in_asm = '' - if settings['SPLIT_MEMORY']: - if not settings['SAFE_SPLIT_MEMORY']: - def make_get_set(name, coercer, shift): - access = 'HEAP{name}s[ptr >> SPLIT_MEMORY_BITS][(ptr & SPLIT_MEMORY_MASK) >> {shift}]'.format(name=name, shift=shift) - format_data = { - 'name': name, - 'coerced_value': coercer('value'), - 'access': access, - 'coerced_access': coercer(access), - } - return ''' -function get{name}(ptr) {{ - ptr = ptr | 0; - return {coerced_access}; -}} -function set{name}(ptr, value) {{ - ptr = ptr | 0; - value = {coerced_value}; - {access} = value; -}}'''.format(**format_data) - def int_coerce(s): - return s + ' | 0' - def float_coerce(s): - return '+' + s - get_set_types = [ - ('8', int_coerce, 0), - ('16', int_coerce, 1), - ('32', int_coerce, 2), - ('U8', int_coerce, 0), - ('U16', int_coerce, 1), - ('U32', int_coerce, 2), - ('F32', float_coerce, 2), # TODO: fround when present - ('F64', float_coerce, 3), - ] - first_in_asm += ''.join([make_get_set(*args) for args in get_set_types]) + '\n' - first_in_asm += 'buffer = new ArrayBuffer(32); // fake\n' - - runtime_funcs = [] - if not settings['ONLY_MY_CODE']: - runtime_funcs = [''' + +def create_runtime_funcs(exports, settings): + if settings['ONLY_MY_CODE']: + return [] + return [''' function stackAlloc(size) { size = size|0; var ret = 0; @@ -1407,77 +1435,55 @@ def float_coerce(s): } ''' if not settings['RELOCATABLE'] else ''] - funcs_js = [''' -%s -Module%s = %s; -%s -Module%s = %s; -// EMSCRIPTEN_START_ASM -var asm = (function(global, env, buffer) { - %s - %s - %s -''' % (asm_setup, - access_quote('asmGlobalArg'), the_global, - shared_array_buffer, - access_quote('asmLibraryArg'), sending, - "'use asm';" if not metadata.get('hasInlineJS') and settings['ASM_JS'] == 1 else "'almost asm';", - first_in_asm, - ''' - var HEAP8 = new global%s(buffer); - var HEAP16 = new global%s(buffer); - var HEAP32 = new global%s(buffer); - var HEAPU8 = new global%s(buffer); - var HEAPU16 = new global%s(buffer); - var HEAPU32 = new global%s(buffer); - var HEAPF32 = new global%s(buffer); - var HEAPF64 = new global%s(buffer); -''' % (access_quote('Int8Array'), - access_quote('Int16Array'), - access_quote('Int32Array'), - access_quote('Uint8Array'), - access_quote('Uint16Array'), - access_quote('Uint32Array'), - access_quote('Float32Array'), - access_quote('Float64Array')) - if not settings['ALLOW_MEMORY_GROWTH'] else ''' - var Int8View = global%s; - var Int16View = global%s; - var Int32View = global%s; - var Uint8View = global%s; - var Uint16View = global%s; - var Uint32View = global%s; - var Float32View = global%s; - var Float64View = global%s; - var HEAP8 = new Int8View(buffer); - var HEAP16 = new Int16View(buffer); - var HEAP32 = new Int32View(buffer); - var HEAPU8 = new Uint8View(buffer); - var HEAPU16 = new Uint16View(buffer); - var HEAPU32 = new Uint32View(buffer); - var HEAPF32 = new Float32View(buffer); - var HEAPF64 = new Float64View(buffer); - var byteLength = global.byteLength; -''' % (access_quote('Int8Array'), - access_quote('Int16Array'), - access_quote('Int32Array'), - access_quote('Uint8Array'), - access_quote('Uint16Array'), - access_quote('Uint32Array'), - access_quote('Float32Array'), - access_quote('Float64Array'))) + '\n' + asm_global_vars + (''' + +def create_asm_start_pre(asm_setup, the_global, sending, metadata, settings): + access_quote = access_quoter(settings) + + shared_array_buffer = '' + if settings['USE_PTHREADS']: + shared_array_buffer = "Module.asmGlobalArg['Atomics'] = Atomics;" + + module_get = 'Module{access} = {val};' + module_global = module_get.format(access=access_quote('asmGlobalArg'), val=the_global) + module_library = module_get.format(access=access_quote('asmLibraryArg'), val=sending) + + asm_function_top = ('// EMSCRIPTEN_START_ASM\n' + 'var asm = (function(global, env, buffer) {') + + use_asm = "'almost asm';" + if not metadata.get('hasInlineJS') and settings['ASM_JS'] == 1: + use_asm = "'use asm';" + + lines = [ + asm_setup, + module_global, + shared_array_buffer, + module_library, + asm_function_top, + use_asm, + create_first_in_asm(settings), + create_memory_views(settings), + ] + return '\n'.join(lines) + + +def create_asm_temp_vars(settings): + access_quote = access_quoter(settings) + return ''' var __THREW__ = 0; var threwValue = 0; var setjmpId = 0; var undef = 0; var nan = global%s, inf = global%s; - var tempInt = 0, tempBigInt = 0, tempBigIntP = 0, tempBigIntS = 0, tempBigIntR = 0.0, tempBigIntI = 0, tempBigIntD = 0, tempValue = 0, tempDouble = 0.0; + var tempInt = 0, tempBigInt = 0, tempBigIntS = 0, tempValue = 0, tempDouble = 0.0; var tempRet0 = 0; -''' % (access_quote('NaN'), access_quote('Infinity'))) + '\n' + asm_global_funcs] + \ - [' var tempFloat = %s;\n' % ('Math_fround(0)' if provide_fround(settings) else '0.0')] + \ - [' var asyncState = 0;\n' if settings.get('EMTERPRETIFY_ASYNC') else ''] + \ - ([' const f0 = Math_fround(0);\n'] if provide_fround(settings) else []) + \ - ['' if not settings['ALLOW_MEMORY_GROWTH'] else ''' +''' % (access_quote('NaN'), access_quote('Infinity')) + + +def create_replace_memory(settings): + if not settings['ALLOW_MEMORY_GROWTH']: + return '' + return ''' function _emscripten_replace_memory(newBuffer) { if ((byteLength(newBuffer) & 0xffffff || byteLength(newBuffer) <= 0xffffff) || byteLength(newBuffer) > 0x80000000) return false; HEAP8 = new Int8View(newBuffer); @@ -1491,10 +1497,12 @@ def float_coerce(s): buffer = newBuffer; return true; } -'''] + [''' -// EMSCRIPTEN_START_FUNCS -'''] + runtime_funcs + funcs_js + [''' - ''', pre_tables, final_function_tables, ''' +''' + + +def create_asm_end(exports, settings): + access_quote = access_quoter(settings) + return ''' return %s; }) @@ -1502,64 +1510,130 @@ def float_coerce(s): (%s, %s, buffer); ''' % (exports, 'Module' + access_quote('asmGlobalArg'), - 'Module' + access_quote('asmLibraryArg')), ''' -''', receiving, '''; -'''] + 'Module' + access_quote('asmLibraryArg')) + + +def create_runtime_library_overrides(settings): + overrides = [] + if not settings.get('SIDE_MODULE'): + overrides += [ + 'stackAlloc', + 'stackSave', + 'stackRestore', + 'establishStackSpace', + ] + if settings['SAFE_HEAP']: + overrides.append('setDynamicTop') - if not settings.get('SIDE_MODULE'): - funcs_js.append(''' -Runtime.stackAlloc = Module['stackAlloc']; -Runtime.stackSave = Module['stackSave']; -Runtime.stackRestore = Module['stackRestore']; -Runtime.establishStackSpace = Module['establishStackSpace']; -''') - if settings['SAFE_HEAP']: - funcs_js.append(''' -Runtime.setDynamicTop = Module['setDynamicTop']; -''') + if not settings['RELOCATABLE']: + overrides += ['setTempRet0', 'getTempRet0'] - if not settings['RELOCATABLE']: - funcs_js.append(''' -Runtime.setTempRet0 = Module['setTempRet0']; -Runtime.getTempRet0 = Module['getTempRet0']; -''') + lines = ["Runtime.{0} = Module['{0}'];".format(func) for func in overrides] + return '\n'.join(lines) - # Set function table masks - masks = {} - max_mask = 0 - for sig, table in function_table_data.iteritems(): - mask = table.count(',') - masks[sig] = str(mask) - max_mask = max(mask, max_mask) - def function_table_maskize(js, masks): - def fix(m): - sig = m.groups(0)[0] - return masks[sig] - return re.sub(r'{{{ FTM_([\w\d_$]+) }}}', fix, js) # masks[m.groups(0)[0]] - for i in range(len(funcs_js)): # in-place as this can be large - funcs_js[i] = function_table_maskize(funcs_js[i], masks) - - if settings['SIDE_MODULE']: - funcs_js.append(''' -Runtime.registerFunctions(%(sigs)s, Module); -''' % { 'sigs': str(map(str, function_table_data.keys())) }) - for i in range(len(funcs_js)): # do this loop carefully to save memory - if WINDOWS: funcs_js[i] = funcs_js[i].replace('\r\n', '\n') # Normalize to UNIX line endings, otherwise writing to text file will duplicate \r\n to \r\r\n! - outfile.write(funcs_js[i]) - funcs_js = None +def create_first_in_asm(settings): + first_in_asm = '' + if settings['SPLIT_MEMORY']: + if not settings['SAFE_SPLIT_MEMORY']: + first_in_asm += ''.join([make_get_set(info) for info in HEAP_TYPE_INFOS]) + '\n' + first_in_asm += 'buffer = new ArrayBuffer(32); // fake\n' + return first_in_asm - if WINDOWS: post = post.replace('\r\n', '\n') # Normalize to UNIX line endings, otherwise writing to text file will duplicate \r\n to \r\r\n! - outfile.write(post) - if DEBUG: - logging.debug(' emscript: python processing: finalize took %s seconds' % (time.time() - t)) +def make_get_set(info): + """Generates get*/set* functions for the different heap types. + + Generated symbols: + get8 get16 get32 getU8 getU16 getU32 getF32 getF64 + set8 set16 set32 setU8 setU16 setU32 setF32 setF64 + """ + access = ('{name}s[ptr >> SPLIT_MEMORY_BITS][(ptr & SPLIT_MEMORY_MASK) >> {shift}]' + .format(name=info.heap_name, shift=info.shift_amount)) + # TODO: fround when present for Float32 + return ''' +function get{short}(ptr) {{ + ptr = ptr | 0; + return {coerced_access}; +}} +function set{short}(ptr, value) {{ + ptr = ptr | 0; + value = {coerced_value}; + {access} = value; +}}'''.format( + short=info.short_name(), + coerced_value=info.coerce('value'), + access=access, + coerced_access=info.coerce(access)) + + +def create_memory_views(settings): + """Generates memory views for the different heap types. + + Generated symbols: + Int8View Int16View Int32View + Uint8View Uint16View Uint32View + Float32View Float64View + """ + access_quote = access_quoter(settings) + ret = '\n' + grow_memory = settings['ALLOW_MEMORY_GROWTH'] + for info in HEAP_TYPE_INFOS: + access = access_quote('{}Array'.format(info.long_name)) + format_args = { + 'heap': info.heap_name, + 'long': info.long_name, + 'access': access, + } + if grow_memory: + ret += (' var {long}View = global{access};\n' + ' var {heap} = new {long}View(buffer);\n').format(**format_args) + else: + ret += ' var {heap} = new global{access}(buffer);\n'.format(**format_args) + if grow_memory: + ret += ' var byteLength = global.byteLength;\n' + return ret + + +class HeapTypeInfo(object): + """Struct that holds data for a type of HEAP* views.""" + def __init__(self, heap_name, long_name, shift_amount): + assert heap_name.startswith('HEAP') + self.heap_name = heap_name + self.long_name = long_name + self.shift_amount = shift_amount + + def short_name(self): + """The unique part of the heap name for this type. + + Derive this from heap_name instead of the other way around so that searching, + e.g. for HEAP8, from the generated JS code leads back here. + """ + return self.heap_name[len('HEAP'):] + + def is_int(self): + """Whether this heap type is an integer type or not.""" + return self.short_name()[0] != 'F' + + def coerce(self, expression): + """Adds asm.js type coercion to a string expression.""" + if self.is_int(): + return expression + '| 0' + else: + return '+' + expression + + +HEAP_TYPE_INFOS = [ + HeapTypeInfo(heap_name='HEAP8', long_name='Int8', shift_amount=0), + HeapTypeInfo(heap_name='HEAP16', long_name='Int16', shift_amount=1), + HeapTypeInfo(heap_name='HEAP32', long_name='Int32', shift_amount=2), + HeapTypeInfo(heap_name='HEAPU8', long_name='Uint8', shift_amount=0), + HeapTypeInfo(heap_name='HEAPU16', long_name='Uint16', shift_amount=1), + HeapTypeInfo(heap_name='HEAPU32', long_name='Uint32', shift_amount=2), + HeapTypeInfo(heap_name='HEAPF32', long_name='Float32', shift_amount=2), + HeapTypeInfo(heap_name='HEAPF64', long_name='Float64', shift_amount=3), +] - if settings['CYBERDWARF']: - assert('cyberdwarf_data' in metadata) - cd_file_name = outfile.name + ".cd" - with open(cd_file_name, "w") as cd_file: - json.dump({ 'cyberdwarf': metadata['cyberdwarf_data'] }, cd_file) def emscript_wasm_backend(infile, settings, outfile, libraries=None, compiler_engine=None, temp_files=None, DEBUG=None): From 4ee1557a8f2473405971d4872bf71199174a2776 Mon Sep 17 00:00:00 2001 From: satoshinm Date: Tue, 25 Apr 2017 20:31:19 -0700 Subject: [PATCH 07/22] Implement getting glfw input cursor mode from Pointer Lock. Closes GH-5120 (#5157) * Implement glfwGetInputMode(GLFW_CURSOR) as Pointer Lock. Closes GH-5120 * Add interactive test for GH-5120 glfw_cursor_disabled * Add satoshinm to authors --- AUTHORS | 1 + src/library_glfw.js | 11 ++++ tests/test_glfw_cursor_disabled.c | 88 +++++++++++++++++++++++++++++++ tests/test_interactive.py | 3 ++ 4 files changed, 103 insertions(+) create mode 100644 tests/test_glfw_cursor_disabled.c diff --git a/AUTHORS b/AUTHORS index aa324ae746b2a..9161e567cbf94 100644 --- a/AUTHORS +++ b/AUTHORS @@ -288,3 +288,4 @@ a license to everyone to use it as detailed in LICENSE.) * Loo Rong Jie * Jean-François Geyelin * Matthew Collins +* Satoshi N. M diff --git a/src/library_glfw.js b/src/library_glfw.js index dfa4896c4420b..028dc5329fd87 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -1230,6 +1230,17 @@ var LibraryGLFW = { glfwGetInputMode: function(winid, mode) { var win = GLFW.WindowFromId(winid); if (!win) return; + + switch (mode) { + case 0x00033001: { // GLFW_CURSOR + if (Browser.pointerLock) { + win.inputModes[mode] = 0x00034003; // GLFW_CURSOR_DISABLED + } else { + win.inputModes[mode] = 0x00034001; // GLFW_CURSOR_NORMAL + } + } + } + return win.inputModes[mode]; }, diff --git a/tests/test_glfw_cursor_disabled.c b/tests/test_glfw_cursor_disabled.c new file mode 100644 index 0000000000000..ca7ec7b11f13f --- /dev/null +++ b/tests/test_glfw_cursor_disabled.c @@ -0,0 +1,88 @@ +#include +#include +#include +#ifdef __EMSCRIPTEN__ +#include +#include +#endif + +GLFWwindow *window; + +int last_cursor_disabled = -1; +int pointerlock_isActive = 0; +int result = 0; +void render() { + glClearColor(0.5f, 0.5f, 0.5f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + int cursor_disabled = glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED; + + if (cursor_disabled != last_cursor_disabled) { + last_cursor_disabled = cursor_disabled; + + printf("GLFW_CURSOR_DISABLED? %d\n", cursor_disabled); + + static int step = 2; + if (cursor_disabled == pointerlock_isActive) { + printf("Pass %d: glfwGetInputMode GLFW_CURSOR matches pointerlockchange event\n\n", step++); + + if (step == 5) { + printf("All tests passed.\n"); + result = 1; + REPORT_RESULT(); + exit(0); + } + + if (cursor_disabled) printf("Press escape to exit Pointer Lock\n"); + else printf("Click again to enable Pointer Lock\n"); + } else { + printf("FAIL: cursor_disabled(%d) != pointerlock_isActive(%d)\n", cursor_disabled, pointerlock_isActive); + REPORT_RESULT(); + exit(1); + } + } +} + + +#ifdef __EMSCRIPTEN__ +EM_BOOL on_pointerlockchange(int eventType, const EmscriptenPointerlockChangeEvent *event, void *userData) { + printf("pointerlockchange, isActive=%d\n", event->isActive); + pointerlock_isActive = event->isActive; + return 0; +} +#endif + +int main() { + if (!glfwInit()) { + return -1; + } + + window = glfwCreateWindow(640, 480, "test_glfw_cursor_disabled", NULL, NULL); + if (!window) { + glfwTerminate(); + return -1; + } + + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + + if (glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) { + // Browsers do not allow disabling the cursor (Pointer Lock) without a gesture. + printf("FAIL: glfwGetInputMode returned GLFW_CURSOR_DISABLED prematurely\n"); + REPORT_RESULT(); + exit(1); + } + printf("Pass 1: glfwGetInputMode not prematurely returning cursor disabled\n"); + printf("Click within the canvas to activate Pointer Lock\n"); + +#ifdef __EMSCRIPTEN__ + emscripten_set_pointerlockchange_callback(NULL, NULL, 0, on_pointerlockchange); + emscripten_set_main_loop(render, 0, 1); +#else + while (!glfwWindowShouldClose(window)) { + glfwPollEvents(); + } +#endif + + glfwTerminate(); + return 0; +} diff --git a/tests/test_interactive.py b/tests/test_interactive.py index c18f8a34b6b95..b565bc8d7fb0d 100644 --- a/tests/test_interactive.py +++ b/tests/test_interactive.py @@ -131,6 +131,9 @@ def test_freealut(self): def test_vr(self): self.btest(path_from_root('tests', 'test_vr.c'), expected='0') + def test_glfw_cursor_disabled(self): + self.btest('test_glfw_cursor_disabled.c', expected='1', args=['-s', 'USE_GLFW=3', '-lglfw', '-lGL']) + def test_glfw_fullscreen(self): self.btest('test_glfw_fullscreen.c', expected='1', args=['-s', 'NO_EXIT_RUNTIME=1', '-s', 'USE_GLFW=3']) From 2ec641a5bd034ca7b3dffab10be02c8aef0445cb Mon Sep 17 00:00:00 2001 From: Jukka Jylanki Date: Wed, 26 Apr 2017 14:00:17 +0300 Subject: [PATCH 08/22] Fix _mm_set_epi64x() from truncating the 64-bit values to 32-bit before storing. Fixes #5103. --- system/include/SSE/emmintrin.h | 2 +- tests/core/test_simd_set_epi64x.c | 14 ++++++++++++++ tests/core/test_simd_set_epi64x.out | 1 + tests/test_core.py | 5 +++++ 4 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 tests/core/test_simd_set_epi64x.c create mode 100644 tests/core/test_simd_set_epi64x.out diff --git a/system/include/SSE/emmintrin.h b/system/include/SSE/emmintrin.h index 81637b1b91ab2..bbda1e0432982 100644 --- a/system/include/SSE/emmintrin.h +++ b/system/include/SSE/emmintrin.h @@ -1898,7 +1898,7 @@ _mm_loadl_epi64(__m128i const *__p) static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_set_epi64x(long long q1, long long q0) { - return (__m128i){ q0, q1 }; + return (__m128i){ (unsigned long long)q0, (unsigned long long)q0 >> 32, (unsigned long long)q1, (unsigned long long)q1 >> 32 }; } #ifndef __EMSCRIPTEN__ // MMX support is not available in Emscripten/SIMD.js. diff --git a/tests/core/test_simd_set_epi64x.c b/tests/core/test_simd_set_epi64x.c new file mode 100644 index 0000000000000..ae95b8f219e70 --- /dev/null +++ b/tests/core/test_simd_set_epi64x.c @@ -0,0 +1,14 @@ +#include +#include +#include + +void print128_num(__m128i var) +{ + int32_t *v32val = (int32_t*) &var; + printf("%.8d %.8d %.8d %.8d\n", v32val[3], v32val[2], v32val[1], v32val[0]); +} + +int main() { + __m128i var = _mm_set_epi64x(-1588454185101182573, 437384867522774919); + print128_num(var); +} diff --git a/tests/core/test_simd_set_epi64x.out b/tests/core/test_simd_set_epi64x.out new file mode 100644 index 0000000000000..384b555c4f696 --- /dev/null +++ b/tests/core/test_simd_set_epi64x.out @@ -0,0 +1 @@ +-369840811 -1425032813 101836600 986941319 diff --git a/tests/test_core.py b/tests/test_core.py index 2a04724d5a304..ee6b7068945a3 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -5137,6 +5137,11 @@ def test_simd16(self): self.emcc_args = self.emcc_args + ['-msse', '-msse2'] self.do_run_in_out_file_test('tests', 'core', 'test_simd16') + @SIMD + def test_simd_set_epi64x(self): + self.emcc_args = self.emcc_args + ['-msse2'] + self.do_run_in_out_file_test('tests', 'core', 'test_simd_set_epi64x') + @SIMD def test_simd_float64x2(self): self.do_run_in_out_file_test('tests', 'core', 'test_simd_float64x2') From a7cc81c74a4a0eca1ad2ea87c7ebac73e9d6c724 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Wed, 26 Apr 2017 15:07:42 -0700 Subject: [PATCH 09/22] Pass d8 flag to disable wasm async compilation (#5166) Tests are currently failing due to V8 bug https://bugs.chromium.org/p/v8/issues/detail?id=6263 so pass a flag to disable async compilation (the same APIs are used but they will not actually be async). Also remove --expose-wasm as wasm is now on by default. --- tools/jsrun.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/jsrun.py b/tools/jsrun.py index b746c12e69156..84e3d8f324b1b 100644 --- a/tools/jsrun.py +++ b/tools/jsrun.py @@ -33,7 +33,13 @@ def make_command(filename, engine=None, args=[]): # label a path to nodejs containing a 'd8' as spidermonkey instead. jsengine = os.path.split(engine[0])[-1] # Use "'d8' in" because the name can vary, e.g. d8_g, d8, etc. - return engine + [filename] + (['--expose-wasm', '--'] if 'd8' in jsengine or 'jsc' in jsengine else []) + args + is_d8 = 'd8' in jsengine + # Disable true async compilation (async apis will in fact be synchronous) for now + # due to https://bugs.chromium.org/p/v8/issues/detail?id=6263 + shell_option_flags = ['--no-wasm-async-compilation'] if is_d8 else [] + # Separates engine flags from script flags + flag_separator = ['--'] if is_d8 or 'jsc' in jsengine else [] + return engine + [filename] + shell_option_flags + flag_separator + args def check_engine(engine): From 5f559e26ffde4243dffb5bfd42076684abb1af48 Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Thu, 27 Apr 2017 18:23:48 -0700 Subject: [PATCH 10/22] fix typo in emterpretify-async docs --- site/source/docs/api_reference/emscripten.h.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/source/docs/api_reference/emscripten.h.rst b/site/source/docs/api_reference/emscripten.h.rst index ec79b830c828a..f7c28bf04ebbf 100644 --- a/site/source/docs/api_reference/emscripten.h.rst +++ b/site/source/docs/api_reference/emscripten.h.rst @@ -1085,7 +1085,7 @@ Typedefs Emterpreter-Async functions =========================== -Emterpreter-async functions are asynchronous functions that appear synchronously in C, the linker flags ``-s EMTERPRETIFY -s EMTERPRETIFY_ASYNC=1`` are required to use these functions. See `Emterpreter `_ for more details. +Emterpreter-async functions are asynchronous functions that appear synchronously in C, the linker flags ``-s EMTERPRETIFY=1 -s EMTERPRETIFY_ASYNC=1`` are required to use these functions. See `Emterpreter `_ for more details. Sleeping -------- From 74b10400186e43f72c93705937ff4801df84421e Mon Sep 17 00:00:00 2001 From: CHIBA Fumiya Date: Sat, 29 Apr 2017 02:15:25 +0900 Subject: [PATCH 11/22] Fix address of motion event timestamp (#5171) * Fix base address of motion event timestamp * Add myself to AUTHORS --- AUTHORS | 1 + src/library_html5.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 9161e567cbf94..5ad95c9d114c4 100644 --- a/AUTHORS +++ b/AUTHORS @@ -289,3 +289,4 @@ a license to everyone to use it as detailed in LICENSE.) * Jean-François Geyelin * Matthew Collins * Satoshi N. M +* Fumiya Chiba diff --git a/src/library_html5.js b/src/library_html5.js index 2cff046fc474e..ed16ba167b338 100644 --- a/src/library_html5.js +++ b/src/library_html5.js @@ -475,7 +475,7 @@ var LibraryJSEvents = { var handlerFunc = function(event) { var e = event || window.event; - {{{ makeSetValue('JSEvents.deviceOrientationEvent', C_STRUCTS.EmscriptenDeviceMotionEvent.timestamp, 'JSEvents.tick()', 'double') }}}; + {{{ makeSetValue('JSEvents.deviceMotionEvent', C_STRUCTS.EmscriptenDeviceMotionEvent.timestamp, 'JSEvents.tick()', 'double') }}}; {{{ makeSetValue('JSEvents.deviceMotionEvent', C_STRUCTS.EmscriptenDeviceMotionEvent.accelerationX, 'e.acceleration.x', 'double') }}}; {{{ makeSetValue('JSEvents.deviceMotionEvent', C_STRUCTS.EmscriptenDeviceMotionEvent.accelerationY, 'e.acceleration.y', 'double') }}}; {{{ makeSetValue('JSEvents.deviceMotionEvent', C_STRUCTS.EmscriptenDeviceMotionEvent.accelerationZ, 'e.acceleration.z', 'double') }}}; From e4345076c20c7b17f2debe85757ae5dc870c9a52 Mon Sep 17 00:00:00 2001 From: CHIBA Fumiya Date: Sat, 29 Apr 2017 02:15:47 +0900 Subject: [PATCH 12/22] Specify void as arguments (#5172) --- system/include/emscripten/html5.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/include/emscripten/html5.h b/system/include/emscripten/html5.h index 6d6869e059b58..93acf92d2566f 100644 --- a/system/include/emscripten/html5.h +++ b/system/include/emscripten/html5.h @@ -422,7 +422,7 @@ extern EMSCRIPTEN_WEBGL_CONTEXT_HANDLE emscripten_webgl_create_context(const cha extern EMSCRIPTEN_RESULT emscripten_webgl_make_context_current(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context); -extern EMSCRIPTEN_WEBGL_CONTEXT_HANDLE emscripten_webgl_get_current_context(); +extern EMSCRIPTEN_WEBGL_CONTEXT_HANDLE emscripten_webgl_get_current_context(void); extern EMSCRIPTEN_RESULT emscripten_webgl_destroy_context(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context); From 47b7a21860731e4fe047d3aaf6a0b24aa8acfab8 Mon Sep 17 00:00:00 2001 From: jgravelle-google Date: Fri, 28 Apr 2017 11:31:14 -0700 Subject: [PATCH 13/22] Refactor emscripten py pt3 - emscript_wasm_backend (#5160) * Extract create_backend_args_wasm * Extract create_s2wasm_args * Extract build_wasm * Hoist asmjs_mangle to top level * Extract and split wasm metadata functions * Extract create_module_wasm * Extract create_receiving_wasm * Extract invoke wrapper creation * Simplify file reading in read_wast_invoke_imports * Extract create_sending_wasm * Extract asm_const creation for wasm * Move the_global to be local to create_module_wasm * Extract create_exported_implemented_functions_wasm * Merge common settings glue update * Re-use compile_settings in emscript_wasm_backend, consolidate repeated assert/split * Move shutil import to top of emscripten.py * Merge update_settings_common into update_settings_glue, wasm_backend may set settings it doesn't use --- emscripten.py | 462 ++++++++++++++++++++++++++++---------------------- 1 file changed, 259 insertions(+), 203 deletions(-) diff --git a/emscripten.py b/emscripten.py index b48f0ec445ca4..6cc22c3a171d9 100755 --- a/emscripten.py +++ b/emscripten.py @@ -15,6 +15,7 @@ import difflib import os, sys, json, optparse, subprocess, re, time, logging +import shutil from tools import shared from tools import jsrun, cache as cache_module, tempfiles @@ -221,9 +222,7 @@ def compiler_glue(metadata, settings, libraries, compiler_engine, temp_files, DE update_settings_glue(settings, metadata) assert not (metadata['simd'] and settings['SPLIT_MEMORY']), 'SIMD is used, but not supported in SPLIT_MEMORY' - out = compile_settings(compiler_engine, settings, libraries, temp_files) - assert '//FORWARDED_DATA:' in out, 'Did not receive forwarded data in pre output - process failed?' - glue, forwarded_data = out.split('//FORWARDED_DATA:') + glue, forwarded_data = compile_settings(compiler_engine, settings, libraries, temp_files) if DEBUG: logging.debug(' emscript: glue took %s seconds' % (time.time() - t)) @@ -489,19 +488,21 @@ def update_settings_glue(settings, metadata): # Integrate info from backend if settings['SIDE_MODULE']: settings['DEFAULT_LIBRARY_FUNCS_TO_INCLUDE'] = [] # we don't need any JS library contents in side modules + + if metadata.get('cantValidate') and settings['ASM_JS'] != 2: + logging.warning('disabling asm.js validation due to use of non-supported features: ' + metadata['cantValidate']) + settings['ASM_JS'] = 2 + settings['DEFAULT_LIBRARY_FUNCS_TO_INCLUDE'] = list( set(settings['DEFAULT_LIBRARY_FUNCS_TO_INCLUDE'] + map(shared.JS.to_nice_ident, metadata['declares'])).difference( map(lambda x: x[1:], metadata['implementedFunctions']) ) ) + map(lambda x: x[1:], metadata['externs']) + if metadata['simd']: settings['SIMD'] = 1 - if metadata['cantValidate'] and settings['ASM_JS'] != 2: - logging.warning('disabling asm.js validation due to use of non-supported features: ' + metadata['cantValidate']) - settings['ASM_JS'] = 2 settings['MAX_GLOBAL_ALIGN'] = metadata['maxGlobalAlign'] - settings['IMPLEMENTED_FUNCTIONS'] = metadata['implementedFunctions'] @@ -517,9 +518,12 @@ def save_settings(): save_settings() # Call js compiler - return jsrun.run_js(path_from_root('src', 'compiler.js'), compiler_engine, - [settings_file] + libraries, stdout=subprocess.PIPE, stderr=STDERR_FILE, - cwd=path_from_root('src'), error_limit=300) + out = jsrun.run_js(path_from_root('src', 'compiler.js'), compiler_engine, + [settings_file] + libraries, stdout=subprocess.PIPE, stderr=STDERR_FILE, + cwd=path_from_root('src'), error_limit=300) + assert '//FORWARDED_DATA:' in out, 'Did not receive forwarded data in pre output - process failed?' + glue, forwarded_data = out.split('//FORWARDED_DATA:') + return glue, forwarded_data def memory_and_global_initializers(pre, metadata, mem_init, settings): @@ -1644,62 +1648,7 @@ def emscript_wasm_backend(infile, settings, outfile, libraries=None, compiler_en if libraries is None: libraries = [] - with temp_files.get_file('.wb.s') as temp_s: - backend_compiler = os.path.join(shared.LLVM_ROOT, 'llc') - backend_args = [backend_compiler, infile, '-march=wasm32', '-filetype=asm', - '-asm-verbose=false', - '-o', temp_s] - backend_args += ['-thread-model=single'] # no threads support in backend, tell llc to not emit atomics - # disable slow and relatively unimportant optimization passes - backend_args += ['-combiner-global-alias-analysis=false'] - - # asm.js-style exception handling - if settings['DISABLE_EXCEPTION_CATCHING'] != 1: - backend_args += ['-enable-emscripten-cxx-exceptions'] - if settings['DISABLE_EXCEPTION_CATCHING'] == 2: - whitelist = ','.join(settings['EXCEPTION_CATCHING_WHITELIST'] or ['__fake']) - backend_args += ['-emscripten-cxx-exceptions-whitelist=' + whitelist] - - # asm.js-style setjmp/longjmp handling - backend_args += ['-enable-emscripten-sjlj'] - - if DEBUG: - logging.debug('emscript: llvm wasm backend: ' + ' '.join(backend_args)) - t = time.time() - shared.check_call(backend_args) - if DEBUG: - logging.debug(' emscript: llvm wasm backend took %s seconds' % (time.time() - t)) - t = time.time() - import shutil - shutil.copyfile(temp_s, os.path.join(shared.CANONICAL_TEMP_DIR, 'emcc-llvm-backend-output.s')) - - assert shared.Settings.BINARYEN_ROOT, 'need BINARYEN_ROOT config set so we can use Binaryen s2wasm on the backend output' - basename = outfile.name[:-3] - wast = basename + '.wast' - s2wasm_args = [os.path.join(shared.Settings.BINARYEN_ROOT, 'bin', 's2wasm'), temp_s] - s2wasm_args += ['--emscripten-glue'] - s2wasm_args += ['--global-base=%d' % shared.Settings.GLOBAL_BASE] - s2wasm_args += ['--initial-memory=%d' % shared.Settings.TOTAL_MEMORY] - s2wasm_args += ['--allow-memory-growth'] if shared.Settings.ALLOW_MEMORY_GROWTH else [] - def compiler_rt_fail(): raise Exception('Expected wasm_compiler_rt.a to already be built') - compiler_rt_lib = shared.Cache.get('wasm_compiler_rt.a', lambda: compiler_rt_fail(), 'a') - s2wasm_args += ['-l', compiler_rt_lib] - if DEBUG: - logging.debug('emscript: binaryen s2wasm: ' + ' '.join(s2wasm_args)) - t = time.time() - #s2wasm_args += ['--debug'] - shared.check_call(s2wasm_args, stdout=open(wast, 'w')) - # Also convert wasm text to binary - wasm_as_args = [os.path.join(shared.Settings.BINARYEN_ROOT, 'bin', 'wasm-as'), - wast, '-o', basename + '.wasm'] - logging.debug(' emscript: binaryen wasm-as: ' + ' '.join(wasm_as_args)) - shared.check_call(wasm_as_args) - - if DEBUG: - logging.debug(' emscript: binaryen s2wasm took %s seconds' % (time.time() - t)) - t = time.time() - import shutil - shutil.copyfile(wast, os.path.join(shared.CANONICAL_TEMP_DIR, 'emcc-s2wasm-output.wast')) + wast = build_wasm(temp_files, infile, outfile, settings, DEBUG) # js compiler @@ -1714,103 +1663,13 @@ def compiler_rt_fail(): raise Exception('Expected wasm_compiler_rt.a to already parts = output = None if DEBUG: logging.debug("METAraw %s", metadata_raw) - try: - metadata_json = json.loads(metadata_raw) - except Exception, e: - logging.error('emscript: failure to parse metadata output from s2wasm. raw output is: \n' + metadata_raw) - raise e - - metadata = { - 'declares': [], - 'implementedFunctions': [], - 'externs': [], - 'simd': False, - 'maxGlobalAlign': 0, - 'initializers': [], - 'exports': [], - } - - for k, v in metadata_json.iteritems(): - metadata[k] = v - - def asmjs_mangle(name): - # Mangle a name the way asm.js/JSBackend globals are mangled (i.e. prepend - # '_' and replace non-alphanumerics with '_') - library_functions_in_module = ('setThrew', 'setTempRet0', 'getTempRet0') - if name.startswith('dynCall_'): return name - if name in library_functions_in_module: return name - return '_' + ''.join(['_' if not c.isalnum() else c for c in name]) - - # Initializers call the global var version of the export, so they get the mangled name. - metadata['initializers'] = [asmjs_mangle(i) for i in metadata['initializers']] - - # TODO: emit it from s2wasm; for now, we parse it right here - for line in open(wast).readlines(): - line = line.strip() - if line.startswith('(import '): - parts = line.split() - # Don't include Invoke wrapper names (for asm.js-style exception handling) - # in metadata[declares], the invoke wrappers will be generated in - # this script later. - import_type = parts[3][1:] - import_name = parts[2][1:-1] - if import_type == 'memory': - continue - elif import_type == 'func': - if not import_name.startswith('invoke_'): - metadata['declares'].append(import_name) - elif import_type == 'global': - metadata['externs'].append('_' + import_name) - else: - assert False, 'Unhandled import type "%s"' % import_type - elif line.startswith('(func '): - parts = line.split() - func_name = parts[1][1:] - metadata['implementedFunctions'].append('_' + func_name) - elif line.startswith('(export '): - parts = line.split() - export_name = parts[1][1:-1] - export_type = parts[2][1:] - if export_type == 'func': - assert asmjs_mangle(export_name) not in metadata['exports'] - metadata['exports'].append(export_name) - else: - assert False, 'Unhandled export type "%s"' % export_type - - metadata['declares'] = filter(lambda x: not x.startswith('emscripten_asm_const'), metadata['declares']) # we emit those ourselves - + metadata = create_metadata_wasm(metadata_raw, wast) if DEBUG: logging.debug(repr(metadata)) - settings['DEFAULT_LIBRARY_FUNCS_TO_INCLUDE'] = list( - set(settings['DEFAULT_LIBRARY_FUNCS_TO_INCLUDE'] + map(shared.JS.to_nice_ident, metadata['declares'])).difference( - map(lambda x: x[1:], metadata['implementedFunctions']) - ) - ) + map(lambda x: x[1:], metadata['externs']) - if metadata['simd']: - settings['SIMD'] = 1 - - settings['MAX_GLOBAL_ALIGN'] = metadata['maxGlobalAlign'] - - settings['IMPLEMENTED_FUNCTIONS'] = metadata['implementedFunctions'] - - # Save settings to a file to work around v8 issue 1579 - with temp_files.get_file('.txt') as settings_file: - def save_settings(): - global settings_text - settings_text = json.dumps(settings, sort_keys=True) - s = open(settings_file, 'w') - s.write(settings_text) - s.close() - save_settings() - - # Call js compiler - if DEBUG: t = time.time() - out = jsrun.run_js(path_from_root('src', 'compiler.js'), compiler_engine, - [settings_file] + libraries, stdout=subprocess.PIPE, stderr=STDERR_FILE, - cwd=path_from_root('src'), error_limit=300) - assert '//FORWARDED_DATA:' in out, 'Did not receive forwarded data in pre output - process failed?' - glue, forwarded_data = out.split('//FORWARDED_DATA:') + update_settings_glue(settings, metadata) + if DEBUG: t = time.time() + glue, forwarded_data = compile_settings(compiler_engine, settings, libraries, temp_files) if DEBUG: logging.debug(' emscript: glue took %s seconds' % (time.time() - t)) t = time.time() @@ -1836,18 +1695,94 @@ def save_settings(): # merge forwarded data settings['EXPORTED_FUNCTIONS'] = forwarded_json['EXPORTED_FUNCTIONS'] - all_exported_functions = set(shared.expand_response(settings['EXPORTED_FUNCTIONS'])) # both asm.js and otherwise + exported_implemented_functions = create_exported_implemented_functions_wasm(pre, forwarded_json, metadata, settings) + + asm_consts, asm_const_funcs = create_asm_consts_wasm(forwarded_json, metadata) + pre = pre.replace('// === Body ===', '// === Body ===\n' + '\nvar ASM_CONSTS = [' + ',\n '.join(asm_consts) + '];\n' + '\n'.join(asm_const_funcs) + '\n') + + outfile.write(pre) + pre = None + + invoke_funcs = read_wast_invoke_imports(wast) + + try: + del forwarded_json['Variables']['globals']['_llvm_global_ctors'] # not a true variable + except: + pass + + # sent data + sending = create_sending_wasm(invoke_funcs, forwarded_json, metadata, settings) + receiving = create_receiving_wasm(exported_implemented_functions, settings) + + # finalize + module = create_module_wasm(sending, receiving, invoke_funcs, settings) + + for i in range(len(module)): # do this loop carefully to save memory + if WINDOWS: module[i] = module[i].replace('\r\n', '\n') # Normalize to UNIX line endings, otherwise writing to text file will duplicate \r\n to \r\r\n! + outfile.write(module[i]) + module = None + + if WINDOWS: post = post.replace('\r\n', '\n') # Normalize to UNIX line endings, otherwise writing to text file will duplicate \r\n to \r\r\n! + outfile.write(post) + + outfile.close() + + +def build_wasm(temp_files, infile, outfile, settings, DEBUG): + with temp_files.get_file('.wb.s') as temp_s: + backend_args = create_backend_args_wasm(infile, temp_s, settings) + if DEBUG: + logging.debug('emscript: llvm wasm backend: ' + ' '.join(backend_args)) + t = time.time() + shared.check_call(backend_args) + if DEBUG: + logging.debug(' emscript: llvm wasm backend took %s seconds' % (time.time() - t)) + t = time.time() + shutil.copyfile(temp_s, os.path.join(shared.CANONICAL_TEMP_DIR, 'emcc-llvm-backend-output.s')) + + assert shared.Settings.BINARYEN_ROOT, 'need BINARYEN_ROOT config set so we can use Binaryen s2wasm on the backend output' + basename = outfile.name[:-3] + wast = basename + '.wast' + s2wasm_args = create_s2wasm_args(temp_s) + if DEBUG: + logging.debug('emscript: binaryen s2wasm: ' + ' '.join(s2wasm_args)) + t = time.time() + #s2wasm_args += ['--debug'] + shared.check_call(s2wasm_args, stdout=open(wast, 'w')) + # Also convert wasm text to binary + wasm_as_args = [os.path.join(shared.Settings.BINARYEN_ROOT, 'bin', 'wasm-as'), + wast, '-o', basename + '.wasm'] + logging.debug(' emscript: binaryen wasm-as: ' + ' '.join(wasm_as_args)) + shared.check_call(wasm_as_args) + + if DEBUG: + logging.debug(' emscript: binaryen s2wasm took %s seconds' % (time.time() - t)) + t = time.time() + shutil.copyfile(wast, os.path.join(shared.CANONICAL_TEMP_DIR, 'emcc-s2wasm-output.wast')) + return wast + + +def create_metadata_wasm(metadata_raw, wast): + metadata = load_metadata(metadata_raw) + add_metadata_from_wast(metadata, wast) + return metadata + + +def create_exported_implemented_functions_wasm(pre, forwarded_json, metadata, settings): + exported_implemented_functions = set(metadata['exports']) + + all_exported_functions = set(shared.expand_response(settings['EXPORTED_FUNCTIONS'])) # both asm.js and otherwise for additional_export in settings['DEFAULT_LIBRARY_FUNCS_TO_INCLUDE']: # additional functions to export from asm, if they are implemented all_exported_functions.add('_' + additional_export) - exported_implemented_functions = set(metadata['exports']) + all_implemented = metadata['implementedFunctions'] + forwarded_json['Functions']['implementedFunctions'].keys() # XXX perf? + export_bindings = settings['EXPORT_BINDINGS'] export_all = settings['EXPORT_ALL'] - all_implemented = metadata['implementedFunctions'] + forwarded_json['Functions']['implementedFunctions'].keys() # XXX perf? for key in all_implemented: if key in all_exported_functions or export_all or (export_bindings and key.startswith('_emscripten_bind')): exported_implemented_functions.add(key) - implemented_functions = set(metadata['implementedFunctions']) + if settings['ASSERTIONS'] and settings.get('ORIGINAL_EXPORTED_FUNCTIONS'): original_exports = settings['ORIGINAL_EXPORTED_FUNCTIONS'] if original_exports[0] == '@': original_exports = json.loads(open(original_exports[1:]).read()) @@ -1859,6 +1794,9 @@ def save_settings(): (('function ' + requested.encode('utf-8')) not in pre): # could be a js library func logging.warning('function requested to be exported, but not implemented: "%s"', requested) + return exported_implemented_functions + +def create_asm_consts_wasm(forwarded_json, metadata): asm_consts = [0]*len(metadata['asmConsts']) all_sigs = [] for k, v in metadata['asmConsts'].iteritems(): @@ -1885,47 +1823,42 @@ def save_settings(): return ASM_CONSTS[code](%s); }''' % (sig.encode('utf-8'), ', '.join(all_args), ', '.join(args))) - pre = pre.replace('// === Body ===', '// === Body ===\n' + '\nvar ASM_CONSTS = [' + ',\n '.join(asm_consts) + '];\n' + '\n'.join(asm_const_funcs) + '\n') + return asm_consts, asm_const_funcs + + +def read_wast_invoke_imports(wast): + invoke_funcs = [] + for line in open(wast).readlines(): + if line.strip().startswith('(import '): + parts = line.split() + func_name = parts[2][1:-1] + if func_name.startswith('invoke_'): + invoke_funcs.append(func_name) + return invoke_funcs - outfile.write(pre) - pre = None +def create_sending_wasm(invoke_funcs, forwarded_json, metadata, settings): basic_funcs = ['abort', 'assert', 'enlargeMemory', 'getTotalMemory'] - if settings['ABORTING_MALLOC']: basic_funcs += ['abortOnCannotGrowMemory'] + if settings['ABORTING_MALLOC']: + basic_funcs += ['abortOnCannotGrowMemory'] - access_quote = access_quoter(settings) + basic_vars = ['STACKTOP', 'STACK_MAX', 'DYNAMICTOP_PTR', 'ABORT'] - # calculate globals - try: - del forwarded_json['Variables']['globals']['_llvm_global_ctors'] # not a true variable - except: - pass if not settings['RELOCATABLE']: global_vars = metadata['externs'] else: global_vars = [] # linkable code accesses globals through function calls + + implemented_functions = set(metadata['implementedFunctions']) global_funcs = list(set([key for key, value in forwarded_json['Functions']['libraryFunctions'].iteritems() if value != 2]).difference(set(global_vars)).difference(implemented_functions)) + + send_items = basic_funcs + invoke_funcs + global_funcs + basic_vars + global_vars def math_fix(g): return g if not g.startswith('Math_') else g.split('_')[1] + return '{ ' + ', '.join(['"' + math_fix(s) + '": ' + s for s in send_items]) + ' }' - basic_vars = ['STACKTOP', 'STACK_MAX', 'DYNAMICTOP_PTR', 'ABORT'] - - # Asm.js-style exception handling: invoke wrapper generation - invoke_wrappers = '' - with open(wast) as f: - for line in f: - if line.strip().startswith('(import '): - parts = line.split() - func_name = parts[2][1:-1] - if func_name.startswith('invoke_'): - sig = func_name[len('invoke_'):] - invoke_wrappers += '\n' + shared.JS.make_invoke(sig) + '\n' - basic_funcs.append(func_name) - # sent data - the_global = '{}' - sending = '{ ' + ', '.join(['"' + math_fix(s) + '": ' + s for s in basic_funcs + global_funcs + basic_vars + global_vars]) + ' }' - # received +def create_receiving_wasm(exported_implemented_functions, settings): receiving = '' if settings['ASSERTIONS']: # assert on the runtime being in a valid state when calling into compiled code. The only exceptions are @@ -1942,15 +1875,21 @@ def math_fix(g): else: receiving += 'Module["asm"] = asm;\n' + ';\n'.join(['var ' + asmjs_mangle(s) + ' = Module["' + asmjs_mangle(s) + '"] = function() { return Module["asm"]["' + s + '"].apply(null, arguments) }' for s in exported_implemented_functions]) receiving += ';\n' + return receiving - # finalize + +def create_module_wasm(sending, receiving, invoke_funcs, settings): + access_quote = access_quoter(settings) + invoke_wrappers = create_invoke_wrappers(invoke_funcs) + + the_global = '{}' if settings['USE_PTHREADS']: shared_array_buffer = "if (typeof SharedArrayBuffer !== 'undefined') Module.asmGlobalArg['Atomics'] = Atomics;" else: shared_array_buffer = '' - funcs_js = [''' + module = [''' Module%s = %s; %s Module%s = %s; @@ -1964,7 +1903,7 @@ def math_fix(g): receiving)] # wasm backend stack goes down, and is stored in the first global var location - funcs_js.append(''' + module.append(''' STACKTOP = STACK_BASE + TOTAL_STACK; STACK_MAX = STACK_BASE; HEAP32[%d >> 2] = STACKTOP; @@ -1974,27 +1913,143 @@ def math_fix(g): Runtime.establishStackSpace = Module['establishStackSpace']; ''' % shared.Settings.GLOBAL_BASE) - funcs_js.append(''' + module.append(''' Runtime.setTempRet0 = Module['setTempRet0']; Runtime.getTempRet0 = Module['getTempRet0']; ''') - funcs_js.append(invoke_wrappers) + module.append(invoke_wrappers) + return module - for i in range(len(funcs_js)): # do this loop carefully to save memory - if WINDOWS: funcs_js[i] = funcs_js[i].replace('\r\n', '\n') # Normalize to UNIX line endings, otherwise writing to text file will duplicate \r\n to \r\r\n! - outfile.write(funcs_js[i]) - funcs_js = None +def create_backend_args_wasm(infile, temp_s, settings): + backend_compiler = os.path.join(shared.LLVM_ROOT, 'llc') + args = [backend_compiler, infile, '-march=wasm32', '-filetype=asm', + '-asm-verbose=false', + '-o', temp_s] + args += ['-thread-model=single'] # no threads support in backend, tell llc to not emit atomics + # disable slow and relatively unimportant optimization passes + args += ['-combiner-global-alias-analysis=false'] + + # asm.js-style exception handling + if settings['DISABLE_EXCEPTION_CATCHING'] != 1: + args += ['-enable-emscripten-cxx-exceptions'] + if settings['DISABLE_EXCEPTION_CATCHING'] == 2: + whitelist = ','.join(settings['EXCEPTION_CATCHING_WHITELIST'] or ['__fake']) + args += ['-emscripten-cxx-exceptions-whitelist=' + whitelist] - if WINDOWS: post = post.replace('\r\n', '\n') # Normalize to UNIX line endings, otherwise writing to text file will duplicate \r\n to \r\r\n! - outfile.write(post) + # asm.js-style setjmp/longjmp handling + args += ['-enable-emscripten-sjlj'] + return args + + +def create_s2wasm_args(temp_s): + def compiler_rt_fail(): + raise Exception('Expected wasm_compiler_rt.a to already be built') + compiler_rt_lib = shared.Cache.get('wasm_compiler_rt.a', compiler_rt_fail, 'a') + + s2wasm_path = os.path.join(shared.Settings.BINARYEN_ROOT, 'bin', 's2wasm') + + args = [s2wasm_path, temp_s, '--emscripten-glue'] + args += ['--global-base=%d' % shared.Settings.GLOBAL_BASE] + args += ['--initial-memory=%d' % shared.Settings.TOTAL_MEMORY] + args += ['--allow-memory-growth'] if shared.Settings.ALLOW_MEMORY_GROWTH else [] + args += ['-l', compiler_rt_lib] + return args + + +def load_metadata(metadata_raw): + try: + metadata_json = json.loads(metadata_raw) + except Exception, e: + logging.error('emscript: failure to parse metadata output from s2wasm. raw output is: \n' + metadata_raw) + raise e + + metadata = { + 'declares': [], + 'implementedFunctions': [], + 'externs': [], + 'simd': False, + 'maxGlobalAlign': 0, + 'initializers': [], + 'exports': [], + } + + for k, v in metadata_json.iteritems(): + metadata[k] = v + + # Initializers call the global var version of the export, so they get the mangled name. + metadata['initializers'] = map(asmjs_mangle, metadata['initializers']) + + return metadata + + +def add_metadata_from_wast(metadata, wast): + """Reads .wast file and adds metadata we can read from the code. + + TODO: emit this metadata directly from s2wasm. + """ + for line in open(wast).readlines(): + line = line.strip() + if line.startswith('(import '): + parts = line.split() + # Don't include Invoke wrapper names (for asm.js-style exception handling) + # in metadata[declares], the invoke wrappers will be generated in + # this script later. + import_type = parts[3][1:] + import_name = parts[2][1:-1] + if import_type == 'memory': + continue + elif import_type == 'func': + if not import_name.startswith('invoke_'): + metadata['declares'].append(import_name) + elif import_type == 'global': + metadata['externs'].append('_' + import_name) + else: + assert False, 'Unhandled import type "%s"' % import_type + elif line.startswith('(func '): + parts = line.split() + func_name = parts[1][1:] + metadata['implementedFunctions'].append('_' + func_name) + elif line.startswith('(export '): + parts = line.split() + export_name = parts[1][1:-1] + export_type = parts[2][1:] + if export_type == 'func': + assert asmjs_mangle(export_name) not in metadata['exports'] + metadata['exports'].append(export_name) + else: + assert False, 'Unhandled export type "%s"' % export_type + + # we emit those ourselves + metadata['declares'] = filter(lambda x: not x.startswith('emscripten_asm_const'), metadata['declares']) + + +def create_invoke_wrappers(invoke_funcs): + """Asm.js-style exception handling: invoke wrapper generation.""" + invoke_wrappers = '' + for invoke in invoke_funcs: + sig = invoke[len('invoke_'):] + invoke_wrappers += '\n' + shared.JS.make_invoke(sig) + '\n' + return invoke_wrappers + + +def asmjs_mangle(name): + """Mangle a name the way asm.js/JSBackend globals are mangled. + + Prepends '_' and replaces non-alphanumerics with '_'. + Used by wasm backend for JS library consistency with asm.js. + """ + library_functions_in_module = ('setThrew', 'setTempRet0', 'getTempRet0') + if name.startswith('dynCall_'): return name + if name in library_functions_in_module: return name + return '_' + ''.join(['_' if not c.isalnum() else c for c in name]) - outfile.close() if os.environ.get('EMCC_FAST_COMPILER') == '0': logging.critical('Non-fastcomp compiler is no longer available, please use fastcomp or an older version of emscripten') sys.exit(1) + def main(args, compiler_engine, cache, temp_files, DEBUG): # Prepare settings for serialization to JSON. settings = {} @@ -2018,6 +2073,7 @@ def main(args, compiler_engine, cache, temp_files, DEBUG): emscripter(args.infile, settings, args.outfile, libraries, compiler_engine=compiler_engine, temp_files=temp_files, DEBUG=DEBUG) + def _main(args=None): if args is None: args = sys.argv[1:] From efc8a89a53c682a94158d60c4d4888119de5f58a Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Fri, 28 Apr 2017 14:14:29 -0700 Subject: [PATCH 14/22] in EMCC_DEBUG=1, save the asm.js to the temp dir alongside all the other temp files --- emcc.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/emcc.py b/emcc.py index 06b1f0c0e7bcb..1dee3023bbde3 100755 --- a/emcc.py +++ b/emcc.py @@ -2110,6 +2110,9 @@ def do_minify(): # minifies the code. this is also when we do certain optimizati wrote_wasm_text = False # finish compiling to WebAssembly, using asm2wasm, if we didn't already emit WebAssembly directly using the wasm backend. if not shared.Settings.WASM_BACKEND: + if DEBUG: + # save the asm.js input + shutil.copyfile(asm_target, os.path.join(emscripten_temp_dir, os.path.basename(asm_target))) cmd = [os.path.join(binaryen_bin, 'asm2wasm'), asm_target, '--total-memory=' + str(shared.Settings.TOTAL_MEMORY)] if shared.Settings.BINARYEN_TRAP_MODE == 'js': cmd += ['--emit-jsified-potential-traps'] From 6772b1ace7d1e9f51dc03d8ec3ca78a05e27f141 Mon Sep 17 00:00:00 2001 From: satoshinm Date: Sat, 29 Apr 2017 13:05:08 -0700 Subject: [PATCH 15/22] Fix glfw character callback typing keyboard shortcuts. Closes GH-5121 (#5158) * Fix glfwSetCharCallback typing with hotkeys. Closes GH-5121 * Add tests for glfwSetCharacterCallback in glfw_events * Ctrl keystroke tests: glfw key callback fires, not char * Fix glfw_events synthetic key events on Google Chrome --- src/library_glfw.js | 1 + tests/glfw_events.c | 61 +++++++++++++++++++++++++++++++++++++++------ 2 files changed, 54 insertions(+), 8 deletions(-) diff --git a/src/library_glfw.js b/src/library_glfw.js index 028dc5329fd87..2b85647017e84 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -343,6 +343,7 @@ var LibraryGLFW = { onKeyPress: function(event) { if (!GLFW.active || !GLFW.active.charFunc) return; + if (event.ctrlKey || event.metaKey) return; // correct unicode charCode is only available with onKeyPress event var charCode = event.charCode; diff --git a/tests/glfw_events.c b/tests/glfw_events.c index 3bb359773d4f9..20a176c8c0046 100644 --- a/tests/glfw_events.c +++ b/tests/glfw_events.c @@ -18,6 +18,7 @@ int button; int action; int modify; + int character; } test_args_t; typedef struct { @@ -54,9 +55,25 @@ #if USE_GLFW == 2 { "Module.injectKeyEvent('keydown', 27)", { 0, 0.0, 0.0, GLFW_KEY_ESC, GLFW_PRESS, -1 } }, { "Module.injectKeyEvent('keyup', 27)", { 0, 0.0, 0.0, GLFW_KEY_ESC, GLFW_RELEASE, -1 } }, + + { "Module.injectKeyEvent('keydown', 65)", { 0, 0.0, 0.0, 'A', GLFW_PRESS, -1, 'A' } }, + { "Module.injectKeyEvent('keypress', 65, {charCode: 65})", { 0, 0.0, 0.0, -1, -1, -1, 'A' } }, + { "Module.injectKeyEvent('keyup', 65)", { 0, 0.0, 0.0, 'A', GLFW_RELEASE, -1, 'A' } }, + + { "Module.injectKeyEvent('keydown', 65, {ctrlKey: true})", { 0, 0.0, 0.0, 'A', GLFW_PRESS, -1, 'A' } }, + { "Module.injectKeyEvent('keypress', 65, {ctrlKey: true, charCode: 65})", { 0, 0.0, 0.0, -1, -1, -1, -1 } }, + { "Module.injectKeyEvent('keyup', 65, {ctrlKey: true})", { 0, 0.0, 0.0, 'A', GLFW_RELEASE, -1, 'A' } }, #else { "Module.injectKeyEvent('keydown', 27)", { 0, 0.0, 0.0, GLFW_KEY_ESCAPE, GLFW_PRESS, -1 } }, { "Module.injectKeyEvent('keyup', 27)", { 0, 0.0, 0.0, GLFW_KEY_ESCAPE, GLFW_RELEASE, -1 } }, + + { "Module.injectKeyEvent('keydown', 65)", { 0, 0.0, 0.0, GLFW_KEY_A, GLFW_PRESS, -1 } }, + { "Module.injectKeyEvent('keypress', 65, {charCode: 65})", { 0, 0.0, 0.0, -1, -1, -1, 'A' } }, + { "Module.injectKeyEvent('keyup', 65)", { 0, 0.0, 0.0, GLFW_KEY_A, GLFW_RELEASE, -1 } }, + + { "Module.injectKeyEvent('keydown', 65, {ctrlKey: true})", { 0, 0.0, 0.0, GLFW_KEY_A, GLFW_PRESS, -1, 'A' } }, + { "Module.injectKeyEvent('keypress', 65, {ctrlKey: true, charCode: 65})", { 0, 0.0, 0.0, -1, -1, -1, -1 } }, + { "Module.injectKeyEvent('keyup', 65, {ctrlKey: true})", { 0, 0.0, 0.0, GLFW_KEY_A, GLFW_RELEASE, -1, 'A' } }, #endif }; @@ -115,6 +132,24 @@ } } + #if USE_GLFW == 2 + static void on_char_callback(int character, int action) + #else + static void on_char_callback(GLFWwindow* window, unsigned int character) + #endif + { + test_args_t args = g_tests[g_test_actual].args; + if (args.character != -1 && args.character == character) + { + g_state |= 1 << g_test_actual; + } + else + { + printf("Test %d: FAIL\n", g_test_actual); + } + + } + #if USE_GLFW == 3 static void on_mouse_wheel(GLFWwindow* window, double x, double y) { @@ -161,10 +196,15 @@ //canvas.dispatchEvent(event); }; - Module.injectKeyEvent = function(type, keyCode) { - var keyboardEvent = document.createEvent("KeyboardEvent"); - var initMethod = typeof keyboardEvent.initKeyboardEvent !== 'undefined' ? "initKeyboardEvent" : "initKeyEvent"; - keyboardEvent[initMethod](type, true, true, window, false, false, false, false, keyCode, 0); + Module.injectKeyEvent = function(type, keyCode, options) { + // KeyboardEvent constructor always returns 0 keyCode on Chrome, so use generic events + //var keyboardEvent = new KeyboardEvent(type, Object.assign({ keyCode: keyCode}, options)); + var keyboardEvent = document.createEventObject ? + document.createEventObject() : document.createEvent('Events'); + keyboardEvent.initEvent(type, true, true); + keyboardEvent.keyCode = keyCode; + keyboardEvent = Object.assign(keyboardEvent, options); + canvas.dispatchEvent(keyboardEvent); }; )); @@ -175,7 +215,7 @@ glfwOpenWindow(WIDTH, HEIGHT, 5, 6, 5, 0, 0, 0, GLFW_WINDOW); // != GL_TRUE) glfwSetMousePosCallback(on_mouse_move); - //glfwSetCharCallback(...); + glfwSetCharCallback(on_char_callback); #else glfwSetErrorCallback(on_error); printf("%s\n", glfwGetVersionString()); @@ -187,7 +227,7 @@ glfwSetCursorPosCallback(_mainWindow, on_mouse_move); glfwSetScrollCallback(_mainWindow, on_mouse_wheel); - //glfwSetCharCallback(_mainWindow, ...); + glfwSetCharCallback(_mainWindow, on_char_callback); #endif for (int p = 0; p < 2 && result; ++p) // 2 passes, with and without callbacks. @@ -207,6 +247,11 @@ { g_test_actual = i; test_t test = g_tests[g_test_actual]; + + if (test.args.character == -1) { + g_state |= 1 << g_test_actual; + } + emscripten_run_script(test.cmd); if (test.args.mouse) { @@ -222,9 +267,9 @@ } else { // Keyboard. #if USE_GLFW == 2 - if (glfwGetKey(test.args.button) != test.args.action) + if (test.args.action != -1 && glfwGetKey(test.args.button) != test.args.action) #else - if (glfwGetKey(_mainWindow, test.args.button) != test.args.action) + if (test.args.action != -1 && glfwGetKey(_mainWindow, test.args.button) != test.args.action) #endif { printf("Test %d: FAIL\n", g_test_actual); From 2f4731d72172f73b4e5c6f7ac435127e66c17802 Mon Sep 17 00:00:00 2001 From: satoshinm Date: Sat, 29 Apr 2017 13:05:25 -0700 Subject: [PATCH 16/22] Fix glfw keys sticking, release on blur. Closes GH-5122 (#5159) * Fix glfw keys sticking, release on blur. Closes GH-5122 * Add interactive test for GH-5122 --- src/library_glfw.js | 24 +++++-- tests/test_glfw_get_key_stuck.c | 116 ++++++++++++++++++++++++++++++++ tests/test_interactive.py | 3 + 3 files changed, 138 insertions(+), 5 deletions(-) create mode 100644 tests/test_glfw_get_key_stuck.c diff --git a/src/library_glfw.js b/src/library_glfw.js index 2b85647017e84..fa6415c06721f 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -57,6 +57,7 @@ var LibraryGLFW = { }; this.buttons = 0; this.keys = new Array(); + this.domKeys = new Array(); this.shouldClose = 0; this.title = null; this.windowPosFunc = null; // GLFWwindowposfun @@ -358,16 +359,17 @@ var LibraryGLFW = { #endif }, - onKeyChanged: function(event, status) { + onKeyChanged: function(keyCode, status) { if (!GLFW.active) return; - var key = GLFW.DOMToGLFWKeyCode(event.keyCode); + var key = GLFW.DOMToGLFWKeyCode(keyCode); if (key == -1) return; #if USE_GLFW == 3 var repeat = status && GLFW.active.keys[key]; #endif GLFW.active.keys[key] = status; + GLFW.active.domKeys[keyCode] = status; if (!GLFW.active.keyFunc) return; #if USE_GLFW == 2 @@ -376,12 +378,12 @@ var LibraryGLFW = { #if USE_GLFW == 3 if (repeat) status = 2; // GLFW_REPEAT - Module['dynCall_viiiii'](GLFW.active.keyFunc, GLFW.active.id, key, event.keyCode, status, GLFW.getModBits(GLFW.active)); + Module['dynCall_viiiii'](GLFW.active.keyFunc, GLFW.active.id, key, keyCode, status, GLFW.getModBits(GLFW.active)); #endif }, onKeydown: function(event) { - GLFW.onKeyChanged(event, 1); // GLFW_PRESS or GLFW_REPEAT + GLFW.onKeyChanged(event.keyCode, 1); // GLFW_PRESS or GLFW_REPEAT // This logic comes directly from the sdl implementation. We cannot // call preventDefault on all keydown events otherwise onKeyPress will @@ -392,7 +394,17 @@ var LibraryGLFW = { }, onKeyup: function(event) { - GLFW.onKeyChanged(event, 0); // GLFW_RELEASE + GLFW.onKeyChanged(event.keyCode, 0); // GLFW_RELEASE + }, + + onBlur: function(event) { + if (!GLFW.active) return; + + for (var i = 0; i < GLFW.active.domKeys.length; ++i) { + if (GLFW.active.domKeys[i]) { + GLFW.onKeyChanged(i, 0); // GLFW_RELEASE + } + } }, onMousemove: function(event) { @@ -945,6 +957,7 @@ var LibraryGLFW = { window.addEventListener("keydown", GLFW.onKeydown, true); window.addEventListener("keypress", GLFW.onKeyPress, true); window.addEventListener("keyup", GLFW.onKeyup, true); + window.addEventListener("blur", GLFW.onBlur, true); Module["canvas"].addEventListener("mousemove", GLFW.onMousemove, true); Module["canvas"].addEventListener("mousedown", GLFW.onMouseButtonDown, true); Module["canvas"].addEventListener("mouseup", GLFW.onMouseButtonUp, true); @@ -963,6 +976,7 @@ var LibraryGLFW = { window.removeEventListener("keydown", GLFW.onKeydown, true); window.removeEventListener("keypress", GLFW.onKeyPress, true); window.removeEventListener("keyup", GLFW.onKeyup, true); + window.removeEventListener("blur", GLFW.onBlur, true); Module["canvas"].removeEventListener("mousemove", GLFW.onMousemove, true); Module["canvas"].removeEventListener("mousedown", GLFW.onMouseButtonDown, true); Module["canvas"].removeEventListener("mouseup", GLFW.onMouseButtonUp, true); diff --git a/tests/test_glfw_get_key_stuck.c b/tests/test_glfw_get_key_stuck.c new file mode 100644 index 0000000000000..a81ccbcade7f9 --- /dev/null +++ b/tests/test_glfw_get_key_stuck.c @@ -0,0 +1,116 @@ +#include +#include +#ifdef __EMSCRIPTEN__ +#include +#include +#endif + +GLFWwindow *window; + +static int step = 1; +static int last_state = -1; +void render() { + // http://www.glfw.org/docs/latest/input_guide.html#input_key + int state = glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS; + + if (last_state != state) { // to not spam console + last_state = state; + printf("glfwGetKey says space pressed? %d\n", state); + if (state && step == 1) { + printf("%d. Switch out of your browser to another window (while holding space)\n", step++); + } + if (!state && step == 2) { + printf("You let go, please press and hold spacebar\n"); + step = 1; + } + } + + // Red while space is pressed, green while not + if (state) { + glClearColor(1.0f, 0.0f, 0.0f, 1.0f); + } else { + glClearColor(0.0f, 1.0f, 0.0f, 1.0f); + } + + glClear(GL_COLOR_BUFFER_BIT); +} + +#ifdef __EMSCRIPTEN__ +int result = 0; +EM_BOOL on_focuspocus(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData) { + switch(eventType) { + case EMSCRIPTEN_EVENT_BLUR: + printf("blur\n"); + if (step == 2) { + printf("%d. Switch back to the browser now\n", step++); + } + if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) { + printf("FAIL: glfwGetKey() is stuck after blur\n"); +#ifdef REPORT_RESULT + REPORT_RESULT(); +#endif + } + break; + case EMSCRIPTEN_EVENT_FOCUS: + printf("focus\n"); + if (step == 3) { + int result; + if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) { + printf("FAIL: glfwGetKey() is stuck after blur and focus\n"); + } else { + printf("Pass\n"); + result = 1; + } +#ifdef REPORT_RESULT + REPORT_RESULT(); +#endif + glfwTerminate(); + } + break; + case EMSCRIPTEN_EVENT_FOCUSIN: + printf("focusin\n"); + break; + case EMSCRIPTEN_EVENT_FOCUSOUT: + printf("focusout\n"); + break; + default: + printf("focus event %d\n", eventType); + break; + } + return EM_FALSE; +} + +#endif + +int main() { + if (!glfwInit()) { + return -1; + } + + window = glfwCreateWindow(640, 480, "test_glfw_get_key_stuck", NULL, NULL); + if (!window) { + glfwTerminate(); + return -1; + } + + glfwMakeContextCurrent(window); + printf("%d. Press and hold spacebar\n", step); + +#ifdef __EMSCRIPTEN__ + emscripten_set_blur_callback(NULL, NULL, EM_TRUE, on_focuspocus); + emscripten_set_focus_callback(NULL, NULL, EM_TRUE, on_focuspocus); + emscripten_set_focusin_callback(NULL, NULL, EM_TRUE, on_focuspocus); + emscripten_set_focusout_callback(NULL, NULL, EM_TRUE, on_focuspocus); + + emscripten_set_main_loop(render, 0, 1); +#else + while (!glfwWindowShouldClose(window)) { + render(); + glfwSwapBuffers(window); + glfwPollEvents(); + } +#endif + + glfwTerminate(); + return 0; +} diff --git a/tests/test_interactive.py b/tests/test_interactive.py index b565bc8d7fb0d..a08e6be1c5e4c 100644 --- a/tests/test_interactive.py +++ b/tests/test_interactive.py @@ -137,6 +137,9 @@ def test_glfw_cursor_disabled(self): def test_glfw_fullscreen(self): self.btest('test_glfw_fullscreen.c', expected='1', args=['-s', 'NO_EXIT_RUNTIME=1', '-s', 'USE_GLFW=3']) + def test_glfw_get_key_stuck(self): + self.btest('test_glfw_get_key_stuck.c', expected='1', args=['-s', 'NO_EXIT_RUNTIME=1', '-s', 'USE_GLFW=3']) + def test_glfw_pointerlock(self): self.btest('test_glfw_pointerlock.c', expected='1', args=['-s', 'NO_EXIT_RUNTIME=1', '-s', 'USE_GLFW=3']) From e2b673227c4e651701b52199d61e783a42e2528b Mon Sep 17 00:00:00 2001 From: satoshinm Date: Sat, 29 Apr 2017 13:08:03 -0700 Subject: [PATCH 17/22] Update glfw3 library to version 3.2.1 (#5162) * Update glfw3.h header to version 3.2.1 * Add stubs for new functions in glfw 3.2 * Update glfw version string to 3.2.1 * Update glfwGetVersion() to 3.2.1 * Fix glfwGetVersion() test for 3.2.1 --- src/library_glfw.js | 56 +- system/include/GLFW/glfw3.h | 3095 ++++++++++++++++++++++++++++------- tests/glfw3.c | 6 +- 3 files changed, 2587 insertions(+), 570 deletions(-) diff --git a/src/library_glfw.js b/src/library_glfw.js index fa6415c06721f..b71bab38e491a 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -998,8 +998,8 @@ var LibraryGLFW = { #if USE_GLFW == 3 setValue(major, 3, 'i32'); - setValue(minor, 0, 'i32'); - setValue(rev, 0, 'i32'); + setValue(minor, 2, 'i32'); + setValue(rev, 1, 'i32'); #endif }, @@ -1042,7 +1042,7 @@ var LibraryGLFW = { #if USE_GLFW == 3 glfwGetVersionString: function() { if (!GLFW.versionString) { - GLFW.versionString = allocate(intArrayFromString("3.0.0 JS WebGL Emscripten"), 'i8', ALLOC_NORMAL); + GLFW.versionString = allocate(intArrayFromString("3.2.1 JS WebGL Emscripten"), 'i8', ALLOC_NORMAL); } return GLFW.versionString; }, @@ -1051,6 +1051,10 @@ var LibraryGLFW = { GLFW.errorFunc = cbfun; }, + glfwWaitEventsTimeout: function(timeout) {}, + + glfwPostEmptyEvent: function() {}, + glfwGetMonitors: function(count) { setValue(count, 1, 'i32'); if (!GLFW.monitors) { @@ -1236,6 +1240,28 @@ var LibraryGLFW = { win.windowIconifyFunc = cbfun; }, + glfwSetWindowIcon: function(winid, count, images) {}, + + glfwSetWindowSizeLimits: function(winid, minwidth, minheight, maxwidth, maxheight) {}, + + glfwSetWindowAspectRatio: function(winid, numer, denom) {}, + + glfwGetWindowFrameSize: function(winid, left, top, right, bottom) { throw "glfwGetWindowFrameSize not implemented."; }, + + glfwMaximizeWindow: function(winid) {}, + + glfwFocusWindow: function(winid) {}, + + glfwSetWindowMonitor: function(winid, monitor, xpos, ypos, width, height, refreshRate) { throw "glfwSetWindowMonitor not implemented."; }, + + glfwCreateCursor: function(image, xhot, yhot) {}, + + glfwCreateStandardCursor: function(shape) {}, + + glfwDestroyCursor: function(cursor) {}, + + glfwSetCursor: function(winid, cursor) {}, + glfwSetFramebufferSizeCallback: function(winid, cbfun) { var win = GLFW.WindowFromId(winid); if (!win) return; @@ -1267,6 +1293,8 @@ var LibraryGLFW = { return GLFW.getKey(winid, key); }, + glfwGetKeyName: function(key, scancode) { throw "glfwGetKeyName not implemented."; }, + glfwGetMouseButton: function(winid, button) { return GLFW.getMouseButton(winid, button); }, @@ -1288,6 +1316,8 @@ var LibraryGLFW = { GLFW.setCharCallback(winid, cbfun); }, + glfwSetCharModsCallback: function(winid, cbfun) { throw "glfwSetCharModsCallback not implemented."; }, + glfwSetMouseButtonCallback: function(winid, cbfun) { GLFW.setMouseButtonCallback(winid, cbfun); }, @@ -1306,6 +1336,26 @@ var LibraryGLFW = { GLFW.setScrollCallback(winid, cbfun); }, + glfwVulkanSupported: function() { + return 0; + }, + + glfwSetDropCallback: function(winid, cbfun) { throw "glfwSetDropCallback is not implemented."; }, + + glfwGetTimerValue: function() { throw "glfwGetTimerValue is not implemented."; }, + + glfwGetTimerFrequency: function() { throw "glfwGetTimerFrequency is not implemented."; }, + + glfwGetRequiredInstanceExtensions: function(count) { throw "glfwGetRequiredInstanceExtensions is not implemented."; }, + + glfwGetInstanceProcAddress: function(instance, procname) { throw "glfwGetInstanceProcAddress is not implemented."; }, + + glfwGetPhysicalDevicePresentationSupport: function(instance, device, queuefamily) { throw "glfwGetPhysicalDevicePresentationSupport is not implemented"; }, + + glfwCreateWindowSurface: function(instance, winid, allocator, surface) { throw "glfwCreateWindowSurface is not implemented."; }, + + glfwSetJoystickCallback: function(cbfun) { throw "glfwSetJoystickCallback is not implemented."; }, + glfwJoystickPresent: function(joy) { throw "glfwJoystickPresent is not implemented."; }, glfwGetJoystickAxes: function(joy, count) { throw "glfwGetJoystickAxes is not implemented."; }, diff --git a/system/include/GLFW/glfw3.h b/system/include/GLFW/glfw3.h index 8b11c2fc04358..95caa9558ecb8 100644 --- a/system/include/GLFW/glfw3.h +++ b/system/include/GLFW/glfw3.h @@ -1,9 +1,9 @@ /************************************************************************* - * GLFW 3.0 - www.glfw.org + * GLFW 3.2 - www.glfw.org * A library for OpenGL, window and input *------------------------------------------------------------------------ * Copyright (c) 2002-2006 Marcus Geelnard - * Copyright (c) 2006-2010 Camilla Berglund + * Copyright (c) 2006-2016 Camilla Berglund * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -38,54 +38,60 @@ extern "C" { * Doxygen documentation *************************************************************************/ -/*! @defgroup clipboard Clipboard support +/*! @file glfw3.h + * @brief The header of the GLFW 3 API. + * + * This is the header file of the GLFW 3 API. It defines all its types and + * declares all its functions. + * + * For more information about how to use this file, see @ref build_include. */ -/*! @defgroup context Context handling +/*! @defgroup context Context reference + * + * This is the reference documentation for OpenGL and OpenGL ES context related + * functions. For more task-oriented information, see the @ref context_guide. */ -/*! @defgroup error Error handling +/*! @defgroup vulkan Vulkan reference + * + * This is the reference documentation for Vulkan related functions and types. + * For more task-oriented information, see the @ref vulkan_guide. */ -/*! @defgroup init Initialization and version information +/*! @defgroup init Initialization, version and error reference + * + * This is the reference documentation for initialization and termination of + * the library, version management and error handling. For more task-oriented + * information, see the @ref intro_guide. */ -/*! @defgroup input Input handling +/*! @defgroup input Input reference + * + * This is the reference documentation for input related functions and types. + * For more task-oriented information, see the @ref input_guide. */ -/*! @defgroup monitor Monitor handling +/*! @defgroup monitor Monitor reference * * This is the reference documentation for monitor related functions and types. - * For more information, see the @ref monitor. + * For more task-oriented information, see the @ref monitor_guide. */ -/*! @defgroup time Time input - */ -/*! @defgroup window Window handling +/*! @defgroup window Window reference * * This is the reference documentation for window related functions and types, - * including creation, deletion and event polling. For more information, see - * the @ref window. + * including creation, deletion and event polling. For more task-oriented + * information, see the @ref window_guide. */ /************************************************************************* - * Global definitions + * Compiler- and platform-specific preprocessor work *************************************************************************/ -/* ------------------- BEGIN SYSTEM/COMPILER SPECIFIC -------------------- */ - -/* Please report any problems that you find with your compiler, which may - * be solved in this section! There are several compilers that I have not - * been able to test this file with yet. - * - * First: If we are we on Windows, we want a single define for it (_WIN32) - * (Note: For Cygwin the compiler flag -mwin32 should be used, but to - * make sure that things run smoothly for Cygwin users, we add __CYGWIN__ - * to the list of "valid Win32 identifiers", which removes the need for - * -mwin32) +/* If we are we on Windows, we want a single define for it. */ -#if !defined(_WIN32) && (defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__)) +#if !defined(_WIN32) && (defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__)) #define _WIN32 #endif /* _WIN32 */ -/* In order for extension support to be portable, we need to define an - * OpenGL function call method. We use the keyword APIENTRY, which is - * defined for Win32. (Note: Windows also needs this for ) +/* It is customary to use APIENTRY for OpenGL function pointer declarations on + * all platforms. Additionally, the Windows OpenGL header needs APIENTRY. */ #ifndef APIENTRY #ifdef _WIN32 @@ -95,112 +101,108 @@ extern "C" { #endif #endif /* APIENTRY */ -/* The following three defines are here solely to make some Windows-based - * files happy. Theoretically we could include , but - * it has the major drawback of severely polluting our namespace. +/* Some Windows OpenGL headers need this. */ - -/* Under Windows, we need WINGDIAPI defined */ #if !defined(WINGDIAPI) && defined(_WIN32) - #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__POCC__) - /* Microsoft Visual C++, Borland C++ Builder and Pelles C */ - #define WINGDIAPI __declspec(dllimport) - #elif defined(__LCC__) - /* LCC-Win32 */ - #define WINGDIAPI __stdcall - #else - /* Others (e.g. MinGW, Cygwin) */ - #define WINGDIAPI extern - #endif + #define WINGDIAPI __declspec(dllimport) #define GLFW_WINGDIAPI_DEFINED #endif /* WINGDIAPI */ -/* Some files also need CALLBACK defined */ +/* Some Windows GLU headers need this. + */ #if !defined(CALLBACK) && defined(_WIN32) - #if defined(_MSC_VER) - /* Microsoft Visual C++ */ - #if (defined(_M_MRX000) || defined(_M_IX86) || defined(_M_ALPHA) || defined(_M_PPC)) && !defined(MIDL_PASS) - #define CALLBACK __stdcall - #else - #define CALLBACK - #endif - #else - /* Other Windows compilers */ - #define CALLBACK __stdcall - #endif + #define CALLBACK __stdcall #define GLFW_CALLBACK_DEFINED #endif /* CALLBACK */ -/* Most GL/glu.h variants on Windows need wchar_t - * OpenGL/gl.h blocks the definition of ptrdiff_t by glext.h on OS X */ -#if !defined(GLFW_INCLUDE_NONE) - #include -#endif +/* Include because most Windows GLU headers need wchar_t and + * the OS X OpenGL header blocks the definition of ptrdiff_t by glext.h. + * Include it unconditionally to avoid surprising side-effects. + */ +#include + +/* Include because it is needed by Vulkan and related functions. + */ +#include /* Include the chosen client API headers. */ -#if defined(__APPLE_CC__) - #if defined(GLFW_INCLUDE_GLCOREARB) - #include - #elif !defined(GLFW_INCLUDE_NONE) - #define GL_GLEXT_LEGACY - #include +#if defined(__APPLE__) + #if defined(GLFW_INCLUDE_GLCOREARB) + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include #endif - #if defined(GLFW_INCLUDE_GLU) - #include + #elif !defined(GLFW_INCLUDE_NONE) + #if !defined(GLFW_INCLUDE_GLEXT) + #define GL_GLEXT_LEGACY #endif + #include + #endif + #if defined(GLFW_INCLUDE_GLU) + #include + #endif #else - #if defined(GLFW_INCLUDE_GLCOREARB) - #include - #elif defined(GLFW_INCLUDE_ES1) - #include - #elif defined(GLFW_INCLUDE_ES2) - #include - #elif defined(GLFW_INCLUDE_ES3) - #include - #elif !defined(GLFW_INCLUDE_NONE) - #include + #if defined(GLFW_INCLUDE_GLCOREARB) + #include + #elif defined(GLFW_INCLUDE_ES1) + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif + #elif defined(GLFW_INCLUDE_ES2) + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include #endif - #if defined(GLFW_INCLUDE_GLU) - #include + #elif defined(GLFW_INCLUDE_ES3) + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include #endif + #elif defined(GLFW_INCLUDE_ES31) + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif + #elif defined(GLFW_INCLUDE_VULKAN) + #include + #elif !defined(GLFW_INCLUDE_NONE) + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif + #endif + #if defined(GLFW_INCLUDE_GLU) + #include + #endif #endif #if defined(GLFW_DLL) && defined(_GLFW_BUILD_DLL) - /* GLFW_DLL is defined by users of GLFW when compiling programs that will link - * to the DLL version of the GLFW library. _GLFW_BUILD_DLL is defined by the - * GLFW configuration header when compiling the DLL version of the library. + /* GLFW_DLL must be defined by applications that are linking against the DLL + * version of the GLFW library. _GLFW_BUILD_DLL is defined by the GLFW + * configuration header when compiling the DLL version of the library. */ #error "You must not have both GLFW_DLL and _GLFW_BUILD_DLL defined" #endif +/* GLFWAPI is used to declare public API functions for export + * from the DLL / shared library / dynamic library. + */ #if defined(_WIN32) && defined(_GLFW_BUILD_DLL) - - /* We are building a Win32 DLL */ + /* We are building GLFW as a Win32 DLL */ #define GLFWAPI __declspec(dllexport) - #elif defined(_WIN32) && defined(GLFW_DLL) - - /* We are calling a Win32 DLL */ - #if defined(__LCC__) - #define GLFWAPI extern - #else - #define GLFWAPI __declspec(dllimport) - #endif - + /* We are calling GLFW as a Win32 DLL */ + #define GLFWAPI __declspec(dllimport) #elif defined(__GNUC__) && defined(_GLFW_BUILD_DLL) - + /* We are building GLFW as a shared / dynamic library */ #define GLFWAPI __attribute__((visibility("default"))) - #else - - /* We are either building/calling a static lib or we are non-win32 */ + /* We are building or calling GLFW as a static library */ #define GLFWAPI - #endif -/* -------------------- END SYSTEM/COMPILER SPECIFIC --------------------- */ - /************************************************************************* * GLFW API tokens @@ -220,27 +222,54 @@ extern "C" { * backward-compatible. * @ingroup init */ -#define GLFW_VERSION_MINOR 0 +#define GLFW_VERSION_MINOR 2 /*! @brief The revision number of the GLFW library. * * This is incremented when a bug fix release is made that does not contain any * API changes. * @ingroup init */ -#define GLFW_VERSION_REVISION 3 +#define GLFW_VERSION_REVISION 1 +/*! @} */ + +/*! @name Boolean values + * @{ */ +/*! @brief One. + * + * One. Seriously. You don't _need_ to use this symbol in your code. It's + * just semantic sugar for the number 1. You can use `1` or `true` or `_True` + * or `GL_TRUE` or whatever you want. + */ +#define GLFW_TRUE 1 +/*! @brief Zero. + * + * Zero. Seriously. You don't _need_ to use this symbol in your code. It's + * just just semantic sugar for the number 0. You can use `0` or `false` or + * `_False` or `GL_FALSE` or whatever you want. + */ +#define GLFW_FALSE 0 /*! @} */ /*! @name Key and button actions * @{ */ -/*! @brief The key or button was released. +/*! @brief The key or mouse button was released. + * + * The key or mouse button was released. + * * @ingroup input */ #define GLFW_RELEASE 0 -/*! @brief The key or button was pressed. +/*! @brief The key or mouse button was pressed. + * + * The key or mouse button was pressed. + * * @ingroup input */ #define GLFW_PRESS 1 /*! @brief The key was held down until it repeated. + * + * The key was held down until it repeated. + * * @ingroup input */ #define GLFW_REPEAT 2 @@ -248,20 +277,22 @@ extern "C" { /*! @defgroup keys Keyboard keys * - * These key codes are inspired by the *USB HID Usage Tables v1.12* (p. 53-60), - * but re-arranged to map to 7-bit ASCII for printable keys (function keys are - * put in the 256+ range). - * - * The naming of the key codes follow these rules: - * - The US keyboard layout is used - * - Names of printable alpha-numeric characters are used (e.g. "A", "R", - * "3", etc.) - * - For non-alphanumeric characters, Unicode:ish names are used (e.g. - * "COMMA", "LEFT_SQUARE_BRACKET", etc.). Note that some names do not - * correspond to the Unicode standard (usually for brevity) - * - Keys that lack a clear US mapping are named "WORLD_x" - * - For non-printable keys, custom names are used (e.g. "F4", - * "BACKSPACE", etc.) + * See [key input](@ref input_key) for how these are used. + * + * These key codes are inspired by the _USB HID Usage Tables v1.12_ (p. 53-60), + * but re-arranged to map to 7-bit ASCII for printable keys (function keys are + * put in the 256+ range). + * + * The naming of the key codes follow these rules: + * - The US keyboard layout is used + * - Names of printable alpha-numeric characters are used (e.g. "A", "R", + * "3", etc.) + * - For non-alphanumeric characters, Unicode:ish names are used (e.g. + * "COMMA", "LEFT_SQUARE_BRACKET", etc.). Note that some names do not + * correspond to the Unicode standard (usually for brevity) + * - Keys that lack a clear US mapping are named "WORLD_x" + * - For non-printable keys, custom names are used (e.g. "F4", + * "BACKSPACE", etc.) * * @ingroup input * @{ @@ -393,11 +424,15 @@ extern "C" { #define GLFW_KEY_RIGHT_ALT 346 #define GLFW_KEY_RIGHT_SUPER 347 #define GLFW_KEY_MENU 348 + #define GLFW_KEY_LAST GLFW_KEY_MENU /*! @} */ /*! @defgroup mods Modifier key flags + * + * See [key input](@ref input_key) for how these are used. + * * @ingroup input * @{ */ @@ -417,6 +452,9 @@ extern "C" { /*! @} */ /*! @defgroup buttons Mouse buttons + * + * See [mouse button input](@ref input_mouse_button) for how these are used. + * * @ingroup input * @{ */ #define GLFW_MOUSE_BUTTON_1 0 @@ -434,6 +472,9 @@ extern "C" { /*! @} */ /*! @defgroup joysticks Joysticks + * + * See [joystick input](@ref joystick) for how these are used. + * * @ingroup input * @{ */ #define GLFW_JOYSTICK_1 0 @@ -456,38 +497,129 @@ extern "C" { /*! @} */ /*! @defgroup errors Error codes - * @ingroup error + * + * See [error handling](@ref error_handling) for how these are used. + * + * @ingroup init * @{ */ /*! @brief GLFW has not been initialized. + * + * This occurs if a GLFW function was called that must not be called unless the + * library is [initialized](@ref intro_init). + * + * @analysis Application programmer error. Initialize GLFW before calling any + * function that requires initialization. */ #define GLFW_NOT_INITIALIZED 0x00010001 /*! @brief No context is current for this thread. + * + * This occurs if a GLFW function was called that needs and operates on the + * current OpenGL or OpenGL ES context but no context is current on the calling + * thread. One such function is @ref glfwSwapInterval. + * + * @analysis Application programmer error. Ensure a context is current before + * calling functions that require a current context. */ #define GLFW_NO_CURRENT_CONTEXT 0x00010002 -/*! @brief One of the enum parameters for the function was given an invalid - * enum. +/*! @brief One of the arguments to the function was an invalid enum value. + * + * One of the arguments to the function was an invalid enum value, for example + * requesting [GLFW_RED_BITS](@ref window_hints_fb) with @ref + * glfwGetWindowAttrib. + * + * @analysis Application programmer error. Fix the offending call. */ #define GLFW_INVALID_ENUM 0x00010003 -/*! @brief One of the parameters for the function was given an invalid value. +/*! @brief One of the arguments to the function was an invalid value. + * + * One of the arguments to the function was an invalid value, for example + * requesting a non-existent OpenGL or OpenGL ES version like 2.7. + * + * Requesting a valid but unavailable OpenGL or OpenGL ES version will instead + * result in a @ref GLFW_VERSION_UNAVAILABLE error. + * + * @analysis Application programmer error. Fix the offending call. */ #define GLFW_INVALID_VALUE 0x00010004 /*! @brief A memory allocation failed. + * + * A memory allocation failed. + * + * @analysis A bug in GLFW or the underlying operating system. Report the bug + * to our [issue tracker](https://github.com/glfw/glfw/issues). */ #define GLFW_OUT_OF_MEMORY 0x00010005 -/*! @brief GLFW could not find support for the requested client API on the - * system. +/*! @brief GLFW could not find support for the requested API on the system. + * + * GLFW could not find support for the requested API on the system. + * + * @analysis The installed graphics driver does not support the requested + * API, or does not support it via the chosen context creation backend. + * Below are a few examples. + * + * @par + * Some pre-installed Windows graphics drivers do not support OpenGL. AMD only + * supports OpenGL ES via EGL, while Nvidia and Intel only support it via + * a WGL or GLX extension. OS X does not provide OpenGL ES at all. The Mesa + * EGL, OpenGL and OpenGL ES libraries do not interface with the Nvidia binary + * driver. Older graphics drivers do not support Vulkan. */ #define GLFW_API_UNAVAILABLE 0x00010006 -/*! @brief The requested client API version is not available. +/*! @brief The requested OpenGL or OpenGL ES version is not available. + * + * The requested OpenGL or OpenGL ES version (including any requested context + * or framebuffer hints) is not available on this machine. + * + * @analysis The machine does not support your requirements. If your + * application is sufficiently flexible, downgrade your requirements and try + * again. Otherwise, inform the user that their machine does not match your + * requirements. + * + * @par + * Future invalid OpenGL and OpenGL ES versions, for example OpenGL 4.8 if 5.0 + * comes out before the 4.x series gets that far, also fail with this error and + * not @ref GLFW_INVALID_VALUE, because GLFW cannot know what future versions + * will exist. */ #define GLFW_VERSION_UNAVAILABLE 0x00010007 /*! @brief A platform-specific error occurred that does not match any of the * more specific categories. + * + * A platform-specific error occurred that does not match any of the more + * specific categories. + * + * @analysis A bug or configuration error in GLFW, the underlying operating + * system or its drivers, or a lack of required resources. Report the issue to + * our [issue tracker](https://github.com/glfw/glfw/issues). */ #define GLFW_PLATFORM_ERROR 0x00010008 -/*! @brief The clipboard did not contain data in the requested format. +/*! @brief The requested format is not supported or available. + * + * If emitted during window creation, the requested pixel format is not + * supported. + * + * If emitted when querying the clipboard, the contents of the clipboard could + * not be converted to the requested format. + * + * @analysis If emitted during window creation, one or more + * [hard constraints](@ref window_hints_hard) did not match any of the + * available pixel formats. If your application is sufficiently flexible, + * downgrade your requirements and try again. Otherwise, inform the user that + * their machine does not match your requirements. + * + * @par + * If emitted when querying the clipboard, ignore the error or report it to + * the user, as appropriate. */ #define GLFW_FORMAT_UNAVAILABLE 0x00010009 +/*! @brief The specified window does not have an OpenGL or OpenGL ES context. + * + * A window that does not have an OpenGL or OpenGL ES context was passed to + * a function that requires it to have one. + * + * @analysis Application programmer error. Fix the offending call. + */ +#define GLFW_NO_WINDOW_CONTEXT 0x0001000A /*! @} */ #define GLFW_FOCUSED 0x00020001 @@ -495,6 +627,9 @@ extern "C" { #define GLFW_RESIZABLE 0x00020003 #define GLFW_VISIBLE 0x00020004 #define GLFW_DECORATED 0x00020005 +#define GLFW_AUTO_ICONIFY 0x00020006 +#define GLFW_FLOATING 0x00020007 +#define GLFW_MAXIMIZED 0x00020008 #define GLFW_RED_BITS 0x00021001 #define GLFW_GREEN_BITS 0x00021002 @@ -511,6 +646,7 @@ extern "C" { #define GLFW_SAMPLES 0x0002100D #define GLFW_SRGB_CAPABLE 0x0002100E #define GLFW_REFRESH_RATE 0x0002100F +#define GLFW_DOUBLEBUFFER 0x00021010 #define GLFW_CLIENT_API 0x00022001 #define GLFW_CONTEXT_VERSION_MAJOR 0x00022002 @@ -520,7 +656,11 @@ extern "C" { #define GLFW_OPENGL_FORWARD_COMPAT 0x00022006 #define GLFW_OPENGL_DEBUG_CONTEXT 0x00022007 #define GLFW_OPENGL_PROFILE 0x00022008 +#define GLFW_CONTEXT_RELEASE_BEHAVIOR 0x00022009 +#define GLFW_CONTEXT_NO_ERROR 0x0002200A +#define GLFW_CONTEXT_CREATION_API 0x0002200B +#define GLFW_NO_API 0 #define GLFW_OPENGL_API 0x00030001 #define GLFW_OPENGL_ES_API 0x00030002 @@ -540,9 +680,57 @@ extern "C" { #define GLFW_CURSOR_HIDDEN 0x00034002 #define GLFW_CURSOR_DISABLED 0x00034003 +#define GLFW_ANY_RELEASE_BEHAVIOR 0 +#define GLFW_RELEASE_BEHAVIOR_FLUSH 0x00035001 +#define GLFW_RELEASE_BEHAVIOR_NONE 0x00035002 + +#define GLFW_NATIVE_CONTEXT_API 0x00036001 +#define GLFW_EGL_CONTEXT_API 0x00036002 + +/*! @defgroup shapes Standard cursor shapes + * + * See [standard cursor creation](@ref cursor_standard) for how these are used. + * + * @ingroup input + * @{ */ + +/*! @brief The regular arrow cursor shape. + * + * The regular arrow cursor. + */ +#define GLFW_ARROW_CURSOR 0x00036001 +/*! @brief The text input I-beam cursor shape. + * + * The text input I-beam cursor shape. + */ +#define GLFW_IBEAM_CURSOR 0x00036002 +/*! @brief The crosshair shape. + * + * The crosshair shape. + */ +#define GLFW_CROSSHAIR_CURSOR 0x00036003 +/*! @brief The hand shape. + * + * The hand shape. + */ +#define GLFW_HAND_CURSOR 0x00036004 +/*! @brief The horizontal resize arrow shape. + * + * The horizontal resize arrow shape. + */ +#define GLFW_HRESIZE_CURSOR 0x00036005 +/*! @brief The vertical resize arrow shape. + * + * The vertical resize arrow shape. + */ +#define GLFW_VRESIZE_CURSOR 0x00036006 +/*! @} */ + #define GLFW_CONNECTED 0x00040001 #define GLFW_DISCONNECTED 0x00040002 +#define GLFW_DONT_CARE -1 + /************************************************************************* * GLFW API types @@ -553,14 +741,37 @@ extern "C" { * Generic function pointer used for returning client API function pointers * without forcing a cast from a regular pointer. * + * @sa @ref context_glext + * @sa glfwGetProcAddress + * + * @since Added in version 3.0. + * @ingroup context */ typedef void (*GLFWglproc)(void); +/*! @brief Vulkan API function pointer type. + * + * Generic function pointer used for returning Vulkan API function pointers + * without forcing a cast from a regular pointer. + * + * @sa @ref vulkan_proc + * @sa glfwGetInstanceProcAddress + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +typedef void (*GLFWvkproc)(void); + /*! @brief Opaque monitor object. * * Opaque monitor object. * + * @see @ref monitor_object + * + * @since Added in version 3.0. + * * @ingroup monitor */ typedef struct GLFWmonitor GLFWmonitor; @@ -569,10 +780,26 @@ typedef struct GLFWmonitor GLFWmonitor; * * Opaque window object. * + * @see @ref window_object + * + * @since Added in version 3.0. + * * @ingroup window */ typedef struct GLFWwindow GLFWwindow; +/*! @brief Opaque cursor object. + * + * Opaque cursor object. + * + * @see @ref cursor_object + * + * @since Added in version 3.1. + * + * @ingroup cursor + */ +typedef struct GLFWcursor GLFWcursor; + /*! @brief The function signature for error callbacks. * * This is the function signature for error callback functions. @@ -580,9 +807,12 @@ typedef struct GLFWwindow GLFWwindow; * @param[in] error An [error code](@ref errors). * @param[in] description A UTF-8 encoded string describing the error. * + * @sa @ref error_handling * @sa glfwSetErrorCallback * - * @ingroup error + * @since Added in version 3.0. + * + * @ingroup init */ typedef void (* GLFWerrorfun)(int,const char*); @@ -590,14 +820,17 @@ typedef void (* GLFWerrorfun)(int,const char*); * * This is the function signature for window position callback functions. * - * @param[in] window The window that the user moved. + * @param[in] window The window that was moved. * @param[in] xpos The new x-coordinate, in screen coordinates, of the * upper-left corner of the client area of the window. * @param[in] ypos The new y-coordinate, in screen coordinates, of the * upper-left corner of the client area of the window. * + * @sa @ref window_pos * @sa glfwSetWindowPosCallback * + * @since Added in version 3.0. + * * @ingroup window */ typedef void (* GLFWwindowposfun)(GLFWwindow*,int,int); @@ -606,12 +839,16 @@ typedef void (* GLFWwindowposfun)(GLFWwindow*,int,int); * * This is the function signature for window size callback functions. * - * @param[in] window The window that the user resized. + * @param[in] window The window that was resized. * @param[in] width The new width, in screen coordinates, of the window. * @param[in] height The new height, in screen coordinates, of the window. * + * @sa @ref window_size * @sa glfwSetWindowSizeCallback * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * * @ingroup window */ typedef void (* GLFWwindowsizefun)(GLFWwindow*,int,int); @@ -622,8 +859,12 @@ typedef void (* GLFWwindowsizefun)(GLFWwindow*,int,int); * * @param[in] window The window that the user attempted to close. * + * @sa @ref window_close * @sa glfwSetWindowCloseCallback * + * @since Added in version 2.5. + * @glfw3 Added window handle parameter. + * * @ingroup window */ typedef void (* GLFWwindowclosefun)(GLFWwindow*); @@ -634,8 +875,12 @@ typedef void (* GLFWwindowclosefun)(GLFWwindow*); * * @param[in] window The window whose content needs to be refreshed. * + * @sa @ref window_refresh * @sa glfwSetWindowRefreshCallback * + * @since Added in version 2.5. + * @glfw3 Added window handle parameter. + * * @ingroup window */ typedef void (* GLFWwindowrefreshfun)(GLFWwindow*); @@ -644,12 +889,15 @@ typedef void (* GLFWwindowrefreshfun)(GLFWwindow*); * * This is the function signature for window focus callback functions. * - * @param[in] window The window that was focused or defocused. - * @param[in] focused `GL_TRUE` if the window was focused, or `GL_FALSE` if - * it was defocused. + * @param[in] window The window that gained or lost input focus. + * @param[in] focused `GLFW_TRUE` if the window was given input focus, or + * `GLFW_FALSE` if it lost it. * + * @sa @ref window_focus * @sa glfwSetWindowFocusCallback * + * @since Added in version 3.0. + * * @ingroup window */ typedef void (* GLFWwindowfocusfun)(GLFWwindow*,int); @@ -660,11 +908,14 @@ typedef void (* GLFWwindowfocusfun)(GLFWwindow*,int); * functions. * * @param[in] window The window that was iconified or restored. - * @param[in] iconified `GL_TRUE` if the window was iconified, or `GL_FALSE` - * if it was restored. + * @param[in] iconified `GLFW_TRUE` if the window was iconified, or + * `GLFW_FALSE` if it was restored. * + * @sa @ref window_iconify * @sa glfwSetWindowIconifyCallback * + * @since Added in version 3.0. + * * @ingroup window */ typedef void (* GLFWwindowiconifyfun)(GLFWwindow*,int); @@ -678,8 +929,11 @@ typedef void (* GLFWwindowiconifyfun)(GLFWwindow*,int); * @param[in] width The new width, in pixels, of the framebuffer. * @param[in] height The new height, in pixels, of the framebuffer. * + * @sa @ref window_fbsize * @sa glfwSetFramebufferSizeCallback * + * @since Added in version 3.0. + * * @ingroup window */ typedef void (* GLFWframebuffersizefun)(GLFWwindow*,int,int); @@ -695,8 +949,12 @@ typedef void (* GLFWframebuffersizefun)(GLFWwindow*,int,int); * @param[in] mods Bit field describing which [modifier keys](@ref mods) were * held down. * + * @sa @ref input_mouse_button * @sa glfwSetMouseButtonCallback * + * @since Added in version 1.0. + * @glfw3 Added window handle and modifier mask parameters. + * * @ingroup input */ typedef void (* GLFWmousebuttonfun)(GLFWwindow*,int,int,int); @@ -706,11 +964,16 @@ typedef void (* GLFWmousebuttonfun)(GLFWwindow*,int,int,int); * This is the function signature for cursor position callback functions. * * @param[in] window The window that received the event. - * @param[in] xpos The new x-coordinate of the cursor. - * @param[in] ypos The new y-coordinate of the cursor. + * @param[in] xpos The new cursor x-coordinate, relative to the left edge of + * the client area. + * @param[in] ypos The new cursor y-coordinate, relative to the top edge of the + * client area. * + * @sa @ref cursor_pos * @sa glfwSetCursorPosCallback * + * @since Added in version 3.0. Replaces `GLFWmouseposfun`. + * * @ingroup input */ typedef void (* GLFWcursorposfun)(GLFWwindow*,double,double); @@ -720,11 +983,14 @@ typedef void (* GLFWcursorposfun)(GLFWwindow*,double,double); * This is the function signature for cursor enter/leave callback functions. * * @param[in] window The window that received the event. - * @param[in] entered `GL_TRUE` if the cursor entered the window's client - * area, or `GL_FALSE` if it left it. + * @param[in] entered `GLFW_TRUE` if the cursor entered the window's client + * area, or `GLFW_FALSE` if it left it. * + * @sa @ref cursor_enter * @sa glfwSetCursorEnterCallback * + * @since Added in version 3.0. + * * @ingroup input */ typedef void (* GLFWcursorenterfun)(GLFWwindow*,int); @@ -737,8 +1003,11 @@ typedef void (* GLFWcursorenterfun)(GLFWwindow*,int); * @param[in] xoffset The scroll offset along the x-axis. * @param[in] yoffset The scroll offset along the y-axis. * + * @sa @ref scrolling * @sa glfwSetScrollCallback * + * @since Added in version 3.0. Replaces `GLFWmousewheelfun`. + * * @ingroup input */ typedef void (* GLFWscrollfun)(GLFWwindow*,double,double); @@ -750,12 +1019,16 @@ typedef void (* GLFWscrollfun)(GLFWwindow*,double,double); * @param[in] window The window that received the event. * @param[in] key The [keyboard key](@ref keys) that was pressed or released. * @param[in] scancode The system-specific scancode of the key. - * @param[in] action @ref GLFW_PRESS, @ref GLFW_RELEASE or @ref GLFW_REPEAT. + * @param[in] action `GLFW_PRESS`, `GLFW_RELEASE` or `GLFW_REPEAT`. * @param[in] mods Bit field describing which [modifier keys](@ref mods) were * held down. * + * @sa @ref input_key * @sa glfwSetKeyCallback * + * @since Added in version 1.0. + * @glfw3 Added window handle, scancode and modifier mask parameters. + * * @ingroup input */ typedef void (* GLFWkeyfun)(GLFWwindow*,int,int,int,int); @@ -765,14 +1038,56 @@ typedef void (* GLFWkeyfun)(GLFWwindow*,int,int,int,int); * This is the function signature for Unicode character callback functions. * * @param[in] window The window that received the event. - * @param[in] character The Unicode code point of the character. + * @param[in] codepoint The Unicode code point of the character. * + * @sa @ref input_char * @sa glfwSetCharCallback * + * @since Added in version 2.4. + * @glfw3 Added window handle parameter. + * * @ingroup input */ typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int); +/*! @brief The function signature for Unicode character with modifiers + * callbacks. + * + * This is the function signature for Unicode character with modifiers callback + * functions. It is called for each input character, regardless of what + * modifier keys are held down. + * + * @param[in] window The window that received the event. + * @param[in] codepoint The Unicode code point of the character. + * @param[in] mods Bit field describing which [modifier keys](@ref mods) were + * held down. + * + * @sa @ref input_char + * @sa glfwSetCharModsCallback + * + * @since Added in version 3.1. + * + * @ingroup input + */ +typedef void (* GLFWcharmodsfun)(GLFWwindow*,unsigned int,int); + +/*! @brief The function signature for file drop callbacks. + * + * This is the function signature for file drop callbacks. + * + * @param[in] window The window that received the event. + * @param[in] count The number of dropped files. + * @param[in] paths The UTF-8 encoded file and/or directory path names. + * + * @sa @ref path_drop + * @sa glfwSetDropCallback + * + * @since Added in version 3.1. + * + * @ingroup input + */ +typedef void (* GLFWdropfun)(GLFWwindow*,int,const char**); + /*! @brief The function signature for monitor configuration callbacks. * * This is the function signature for monitor configuration callback functions. @@ -780,16 +1095,42 @@ typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int); * @param[in] monitor The monitor that was connected or disconnected. * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. * + * @sa @ref monitor_event * @sa glfwSetMonitorCallback * + * @since Added in version 3.0. + * * @ingroup monitor */ typedef void (* GLFWmonitorfun)(GLFWmonitor*,int); +/*! @brief The function signature for joystick configuration callbacks. + * + * This is the function signature for joystick configuration callback + * functions. + * + * @param[in] joy The joystick that was connected or disconnected. + * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. + * + * @sa @ref joystick_event + * @sa glfwSetJoystickCallback + * + * @since Added in version 3.2. + * + * @ingroup input + */ +typedef void (* GLFWjoystickfun)(int,int); + /*! @brief Video mode type. * * This describes a single video mode. * + * @sa @ref monitor_modes + * @sa glfwGetVideoMode glfwGetVideoModes + * + * @since Added in version 1.0. + * @glfw3 Added refresh rate member. + * * @ingroup monitor */ typedef struct GLFWvidmode @@ -818,8 +1159,11 @@ typedef struct GLFWvidmode * * This describes the gamma ramp for a monitor. * + * @sa @ref monitor_gamma * @sa glfwGetGammaRamp glfwSetGammaRamp * + * @since Added in version 3.0. + * * @ingroup monitor */ typedef struct GLFWgammaramp @@ -838,6 +1182,27 @@ typedef struct GLFWgammaramp unsigned int size; } GLFWgammaramp; +/*! @brief Image data. + * + * @sa @ref cursor_custom + * @sa @ref window_icon + * + * @since Added in version 2.1. + * @glfw3 Removed format and bytes-per-pixel members. + */ +typedef struct GLFWimage +{ + /*! The width, in pixels, of this image. + */ + int width; + /*! The height, in pixels, of this image. + */ + int height; + /*! The pixel data of this image, arranged left-to-right, top-to-bottom. + */ + unsigned char* pixels; +} GLFWimage; + /************************************************************************* * GLFW API functions @@ -846,56 +1211,65 @@ typedef struct GLFWgammaramp /*! @brief Initializes the GLFW library. * * This function initializes the GLFW library. Before most GLFW functions can - * be used, GLFW must be initialized, and before a program terminates GLFW + * be used, GLFW must be initialized, and before an application terminates GLFW * should be terminated in order to free any resources allocated during or * after initialization. * * If this function fails, it calls @ref glfwTerminate before returning. If it - * succeeds, you should call @ref glfwTerminate before the program exits. + * succeeds, you should call @ref glfwTerminate before the application exits. * * Additional calls to this function after successful initialization but before - * termination will succeed but will do nothing. - * - * @return `GL_TRUE` if successful, or `GL_FALSE` if an error occurred. + * termination will return `GLFW_TRUE` immediately. * - * @par New in GLFW 3 - * This function no longer registers @ref glfwTerminate with `atexit`. + * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an + * [error](@ref error_handling) occurred. * - * @note This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_PLATFORM_ERROR. * - * @note This function may take several seconds to complete on some systems, - * while on other systems it may take only a fraction of a second to complete. - * - * @note **Mac OS X:** This function will change the current directory of the + * @remark @osx This function will change the current directory of the * application to the `Contents/Resources` subdirectory of the application's - * bundle, if present. + * bundle, if present. This can be disabled with a + * [compile-time option](@ref compile_options_osx). + * + * @thread_safety This function must only be called from the main thread. * + * @sa @ref intro_init * @sa glfwTerminate * + * @since Added in version 1.0. + * * @ingroup init */ GLFWAPI int glfwInit(void); /*! @brief Terminates the GLFW library. * - * This function destroys all remaining windows, frees any allocated resources - * and sets the library to an uninitialized state. Once this is called, you - * must again call @ref glfwInit successfully before you will be able to use - * most GLFW functions. + * This function destroys all remaining windows and cursors, restores any + * modified gamma ramps and frees any other allocated resources. Once this + * function is called, you must again call @ref glfwInit successfully before + * you will be able to use most GLFW functions. * * If GLFW has been successfully initialized, this function should be called - * before the program exits. If initialization fails, there is no need to call - * this function, as it is called by @ref glfwInit before it returns failure. + * before the application exits. If initialization fails, there is no need to + * call this function, as it is called by @ref glfwInit before it returns + * failure. + * + * @errors Possible errors include @ref GLFW_PLATFORM_ERROR. * - * @remarks This function may be called before @ref glfwInit. + * @remark This function may be called before @ref glfwInit. * - * @note This function may only be called from the main thread. + * @warning The contexts of any remaining windows must not be current on any + * other thread when this function is called. * - * @warning No window's context may be current on another thread when this - * function is called. + * @reentrancy This function must not be called from a callback. * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref intro_init * @sa glfwInit * + * @since Added in version 1.0. + * * @ingroup init */ GLFWAPI void glfwTerminate(void); @@ -906,46 +1280,54 @@ GLFWAPI void glfwTerminate(void); * library. It is intended for when you are using GLFW as a shared library and * want to ensure that you are using the minimum required version. * + * Any or all of the version arguments may be `NULL`. + * * @param[out] major Where to store the major version number, or `NULL`. * @param[out] minor Where to store the minor version number, or `NULL`. * @param[out] rev Where to store the revision number, or `NULL`. * - * @remarks This function may be called before @ref glfwInit. + * @errors None. + * + * @remark This function may be called before @ref glfwInit. * - * @remarks This function may be called from any thread. + * @thread_safety This function may be called from any thread. * + * @sa @ref intro_version * @sa glfwGetVersionString * + * @since Added in version 1.0. + * * @ingroup init */ GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev); /*! @brief Returns a string describing the compile-time configuration. * - * This function returns a static string generated at compile-time according to - * which configuration macros were defined. This is intended for use when - * submitting bug reports, to allow developers to see which code paths are - * enabled in a binary. + * This function returns the compile-time generated + * [version string](@ref intro_version_string) of the GLFW library binary. It + * describes the version, platform, compiler and any platform-specific + * compile-time options. It should not be confused with the OpenGL or OpenGL + * ES version string, queried with `glGetString`. * - * The format of the string is as follows: - * - The version of GLFW - * - The name of the window system API - * - The name of the context creation API - * - Any additional options or APIs + * __Do not use the version string__ to parse the GLFW library version. The + * @ref glfwGetVersion function provides the version of the running library + * binary in numerical format. * - * For example, when compiling GLFW 3.0 with MinGW using the Win32 and WGL - * back ends, the version string may look something like this: + * @return The ASCII encoded GLFW version string. * - * 3.0.0 Win32 WGL MinGW + * @errors None. * - * @return The GLFW version string. + * @remark This function may be called before @ref glfwInit. * - * @remarks This function may be called before @ref glfwInit. + * @pointer_lifetime The returned string is static and compile-time generated. * - * @remarks This function may be called from any thread. + * @thread_safety This function may be called from any thread. * + * @sa @ref intro_version * @sa glfwGetVersion * + * @since Added in version 3.0. + * * @ingroup init */ GLFWAPI const char* glfwGetVersionString(void); @@ -955,44 +1337,60 @@ GLFWAPI const char* glfwGetVersionString(void); * This function sets the error callback, which is called with an error code * and a human-readable description each time a GLFW error occurs. * + * The error callback is called on the thread where the error occurred. If you + * are using GLFW from multiple threads, your error callback needs to be + * written accordingly. + * + * Because the description string may have been generated specifically for that + * error, it is not guaranteed to be valid after the callback has returned. If + * you wish to use it after the callback returns, you need to make a copy. + * + * Once set, the error callback remains set even after the library has been + * terminated. + * * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set. * - * @remarks This function may be called before @ref glfwInit. + * @errors None. * - * @note The error callback is called by the thread where the error was - * generated. If you are using GLFW from multiple threads, your error callback - * needs to be written accordingly. + * @remark This function may be called before @ref glfwInit. * - * @note Because the description string provided to the callback may have been - * generated specifically for that error, it is not guaranteed to be valid - * after the callback has returned. If you wish to use it after that, you need - * to make your own copy of it before returning. + * @thread_safety This function must only be called from the main thread. * - * @ingroup error + * @sa @ref error_handling + * + * @since Added in version 3.0. + * + * @ingroup init */ GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun); /*! @brief Returns the currently connected monitors. * * This function returns an array of handles for all currently connected - * monitors. + * monitors. The primary monitor is always first in the returned array. If no + * monitors were found, this function returns `NULL`. + * + * @param[out] count Where to store the number of monitors in the returned + * array. This is set to zero if an error occurred. + * @return An array of monitor handles, or `NULL` if no monitors were found or + * if an [error](@ref error_handling) occurred. * - * @param[out] count Where to store the size of the returned array. This is - * set to zero if an error occurred. - * @return An array of monitor handles, or `NULL` if an error occurred. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * - * @note The returned array is allocated and freed by GLFW. You should not - * free it yourself. + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is guaranteed to be valid only until the + * monitor configuration changes or the library is terminated. * - * @note The returned array is valid only until the monitor configuration - * changes. See @ref glfwSetMonitorCallback to receive notifications of - * configuration changes. + * @thread_safety This function must only be called from the main thread. * + * @sa @ref monitor_monitors + * @sa @ref monitor_event * @sa glfwGetPrimaryMonitor * + * @since Added in version 3.0. + * * @ingroup monitor */ GLFWAPI GLFWmonitor** glfwGetMonitors(int* count); @@ -1000,12 +1398,23 @@ GLFWAPI GLFWmonitor** glfwGetMonitors(int* count); /*! @brief Returns the primary monitor. * * This function returns the primary monitor. This is usually the monitor - * where elements like the Windows task bar or the OS X menu bar is located. + * where elements like the task bar or global menu bar are located. + * + * @return The primary monitor, or `NULL` if no monitors were found or if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * - * @return The primary monitor, or `NULL` if an error occurred. + * @thread_safety This function must only be called from the main thread. * + * @remark The primary monitor is always first in the array returned by @ref + * glfwGetMonitors. + * + * @sa @ref monitor_monitors * @sa glfwGetMonitors * + * @since Added in version 3.0. + * * @ingroup monitor */ GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void); @@ -1015,10 +1424,22 @@ GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void); * This function returns the position, in screen coordinates, of the upper-left * corner of the specified monitor. * + * Any or all of the position arguments may be `NULL`. If an error occurs, all + * non-`NULL` position arguments will be set to zero. + * * @param[in] monitor The monitor to query. * @param[out] xpos Where to store the monitor x-coordinate, or `NULL`. * @param[out] ypos Where to store the monitor y-coordinate, or `NULL`. * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_properties + * + * @since Added in version 3.0. + * * @ingroup monitor */ GLFWAPI void glfwGetMonitorPos(GLFWmonitor* monitor, int* xpos, int* ypos); @@ -1028,31 +1449,56 @@ GLFWAPI void glfwGetMonitorPos(GLFWmonitor* monitor, int* xpos, int* ypos); * This function returns the size, in millimetres, of the display area of the * specified monitor. * + * Some systems do not provide accurate monitor size information, either + * because the monitor + * [EDID](https://en.wikipedia.org/wiki/Extended_display_identification_data) + * data is incorrect or because the driver does not report it accurately. + * + * Any or all of the size arguments may be `NULL`. If an error occurs, all + * non-`NULL` size arguments will be set to zero. + * * @param[in] monitor The monitor to query. - * @param[out] width Where to store the width, in mm, of the monitor's display - * area, or `NULL`. - * @param[out] height Where to store the height, in mm, of the monitor's - * display area, or `NULL`. + * @param[out] widthMM Where to store the width, in millimetres, of the + * monitor's display area, or `NULL`. + * @param[out] heightMM Where to store the height, in millimetres, of the + * monitor's display area, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @remark @win32 calculates the returned physical size from the + * current resolution and system DPI instead of querying the monitor EDID data. + * + * @thread_safety This function must only be called from the main thread. * - * @note Some operating systems do not provide accurate information, either - * because the monitor's EDID data is incorrect, or because the driver does not - * report it accurately. + * @sa @ref monitor_properties + * + * @since Added in version 3.0. * * @ingroup monitor */ -GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* monitor, int* width, int* height); +GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* monitor, int* widthMM, int* heightMM); /*! @brief Returns the name of the specified monitor. * * This function returns a human-readable name, encoded as UTF-8, of the - * specified monitor. + * specified monitor. The name typically reflects the make and model of the + * monitor and is not guaranteed to be unique among the connected monitors. * * @param[in] monitor The monitor to query. - * @return The UTF-8 encoded name of the monitor, or `NULL` if an error - * occurred. + * @return The UTF-8 encoded name of the monitor, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * - * @note The returned string is allocated and freed by GLFW. You should not - * free it yourself. + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified monitor is + * disconnected or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_properties + * + * @since Added in version 3.0. * * @ingroup monitor */ @@ -1066,11 +1512,16 @@ GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* monitor); * * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). * - * @bug **X11:** This callback is not yet called on monitor configuration - * changes. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_event + * + * @since Added in version 3.0. * * @ingroup monitor */ @@ -1086,16 +1537,25 @@ GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun); * @param[in] monitor The monitor to query. * @param[out] count Where to store the number of video modes in the returned * array. This is set to zero if an error occurred. - * @return An array of video modes, or `NULL` if an error occurred. + * @return An array of video modes, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @note The returned array is allocated and freed by GLFW. You should not - * free it yourself. + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified monitor is + * disconnected, this function is called again for that monitor or the library + * is terminated. * - * @note The returned array is valid only until this function is called again - * for the specified monitor. + * @thread_safety This function must only be called from the main thread. * + * @sa @ref monitor_modes * @sa glfwGetVideoMode * + * @since Added in version 1.0. + * @glfw3 Changed to return an array of modes for a specific monitor. + * * @ingroup monitor */ GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* monitor, int* count); @@ -1103,17 +1563,27 @@ GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* monitor, int* count); /*! @brief Returns the current mode of the specified monitor. * * This function returns the current video mode of the specified monitor. If - * you are using a full screen window, the return value will therefore depend - * on whether it is focused. + * you have created a full screen window for that monitor, the return value + * will depend on whether that window is iconified. * * @param[in] monitor The monitor to query. - * @return The current mode of the monitor, or `NULL` if an error occurred. + * @return The current mode of the monitor, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @note The returned struct is allocated and freed by GLFW. You should not - * free it yourself. + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified monitor is + * disconnected or the library is terminated. * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_modes * @sa glfwGetVideoModes * + * @since Added in version 3.0. Replaces `glfwGetDesktopMode`. + * * @ingroup monitor */ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor); @@ -1121,24 +1591,46 @@ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor); /*! @brief Generates a gamma ramp and sets it for the specified monitor. * * This function generates a 256-element gamma ramp from the specified exponent - * and then calls @ref glfwSetGammaRamp with it. + * and then calls @ref glfwSetGammaRamp with it. The value must be a finite + * number greater than zero. * * @param[in] monitor The monitor whose gamma ramp to set. * @param[in] gamma The desired exponent. * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_gamma + * + * @since Added in version 3.0. + * * @ingroup monitor */ GLFWAPI void glfwSetGamma(GLFWmonitor* monitor, float gamma); -/*! @brief Retrieves the current gamma ramp for the specified monitor. +/*! @brief Returns the current gamma ramp for the specified monitor. * - * This function retrieves the current gamma ramp of the specified monitor. + * This function returns the current gamma ramp of the specified monitor. * * @param[in] monitor The monitor to query. - * @return The current gamma ramp, or `NULL` if an error occurred. + * @return The current gamma ramp, or `NULL` if an + * [error](@ref error_handling) occurred. * - * @note The value arrays of the returned ramp are allocated and freed by GLFW. - * You should not free them yourself. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned structure and its arrays are allocated and + * freed by GLFW. You should not free them yourself. They are valid until the + * specified monitor is disconnected, this function is called again for that + * monitor or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_gamma + * + * @since Added in version 3.0. * * @ingroup monitor */ @@ -1146,26 +1638,48 @@ GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor); /*! @brief Sets the current gamma ramp for the specified monitor. * - * This function sets the current gamma ramp for the specified monitor. + * This function sets the current gamma ramp for the specified monitor. The + * original gamma ramp for that monitor is saved by GLFW the first time this + * function is called and is restored by @ref glfwTerminate. * * @param[in] monitor The monitor whose gamma ramp to set. * @param[in] ramp The gamma ramp to use. * - * @note Gamma ramp sizes other than 256 are not supported by all hardware. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @ingroup monitor - */ -GLFWAPI void glfwSetGammaRamp(GLFWmonitor* monitor, const GLFWgammaramp* ramp); - + * @remark Gamma ramp sizes other than 256 are not supported by all platforms + * or graphics hardware. + * + * @remark @win32 The gamma ramp size must be 256. + * + * @pointer_lifetime The specified gamma ramp is copied before this function + * returns. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_gamma + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI void glfwSetGammaRamp(GLFWmonitor* monitor, const GLFWgammaramp* ramp); + /*! @brief Resets all window hints to their default values. * * This function resets all window hints to their * [default values](@ref window_hints_values). * - * @note This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_hints * @sa glfwWindowHint * + * @since Added in version 3.0. + * * @ingroup window */ GLFWAPI void glfwDefaultWindowHints(void); @@ -1175,78 +1689,146 @@ GLFWAPI void glfwDefaultWindowHints(void); * This function sets hints for the next call to @ref glfwCreateWindow. The * hints, once set, retain their values until changed by a call to @ref * glfwWindowHint or @ref glfwDefaultWindowHints, or until the library is - * terminated with @ref glfwTerminate. + * terminated. * - * @param[in] target The [window hint](@ref window_hints) to set. - * @param[in] hint The new value of the window hint. + * This function does not check whether the specified hint values are valid. + * If you set hints to invalid values this will instead be reported by the next + * call to @ref glfwCreateWindow. * - * @par New in GLFW 3 - * Hints are no longer reset to their default values on window creation. To - * set default hint values, use @ref glfwDefaultWindowHints. + * @param[in] hint The [window hint](@ref window_hints) to set. + * @param[in] value The new value of the window hint. * - * @note This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_hints * @sa glfwDefaultWindowHints * + * @since Added in version 3.0. Replaces `glfwOpenWindowHint`. + * * @ingroup window */ -GLFWAPI void glfwWindowHint(int target, int hint); +GLFWAPI void glfwWindowHint(int hint, int value); /*! @brief Creates a window and its associated context. * - * This function creates a window and its associated context. Most of the - * options controlling how the window and its context should be created are - * specified through @ref glfwWindowHint. + * This function creates a window and its associated OpenGL or OpenGL ES + * context. Most of the options controlling how the window and its context + * should be created are specified with [window hints](@ref window_hints). * * Successful creation does not change which context is current. Before you - * can use the newly created context, you need to make it current using @ref - * glfwMakeContextCurrent. + * can use the newly created context, you need to + * [make it current](@ref context_current). For information about the `share` + * parameter, see @ref context_sharing. * - * Note that the created window and context may differ from what you requested, - * as not all parameters and hints are + * The created window, framebuffer and context may differ from what you + * requested, as not all parameters and hints are * [hard constraints](@ref window_hints_hard). This includes the size of the - * window, especially for full screen windows. To retrieve the actual - * attributes of the created window and context, use queries like @ref - * glfwGetWindowAttrib and @ref glfwGetWindowSize. - * - * To create a full screen window, you need to specify the monitor to use. If - * no monitor is specified, windowed mode will be used. Unless you have a way - * for the user to choose a specific monitor, it is recommended that you pick - * the primary monitor. For more information on how to retrieve monitors, see - * @ref monitor_monitors. - * - * To create the window at a specific position, make it initially invisible - * using the `GLFW_VISIBLE` window hint, set its position and then show it. - * - * If a full screen window is active, the screensaver is prohibited from - * starting. + * window, especially for full screen windows. To query the actual attributes + * of the created window, framebuffer and context, see @ref + * glfwGetWindowAttrib, @ref glfwGetWindowSize and @ref glfwGetFramebufferSize. + * + * To create a full screen window, you need to specify the monitor the window + * will cover. If no monitor is specified, the window will be windowed mode. + * Unless you have a way for the user to choose a specific monitor, it is + * recommended that you pick the primary monitor. For more information on how + * to query connected monitors, see @ref monitor_monitors. + * + * For full screen windows, the specified size becomes the resolution of the + * window's _desired video mode_. As long as a full screen window is not + * iconified, the supported video mode most closely matching the desired video + * mode is set for the specified monitor. For more information about full + * screen windows, including the creation of so called _windowed full screen_ + * or _borderless full screen_ windows, see @ref window_windowed_full_screen. + * + * Once you have created the window, you can switch it between windowed and + * full screen mode with @ref glfwSetWindowMonitor. If the window has an + * OpenGL or OpenGL ES context, it will be unaffected. + * + * By default, newly created windows use the placement recommended by the + * window system. To create the window at a specific position, make it + * initially invisible using the [GLFW_VISIBLE](@ref window_hints_wnd) window + * hint, set its [position](@ref window_pos) and then [show](@ref window_hide) + * it. + * + * As long as at least one full screen window is not iconified, the screensaver + * is prohibited from starting. + * + * Window systems put limits on window sizes. Very large or very small window + * dimensions may be overridden by the window system on creation. Check the + * actual [size](@ref window_size) after creation. + * + * The [swap interval](@ref buffer_swap) is not set during window creation and + * the initial value may vary depending on driver settings and defaults. * * @param[in] width The desired width, in screen coordinates, of the window. * This must be greater than zero. * @param[in] height The desired height, in screen coordinates, of the window. * This must be greater than zero. * @param[in] title The initial, UTF-8 encoded window title. - * @param[in] monitor The monitor to use for full screen mode, or `NULL` to use + * @param[in] monitor The monitor to use for full screen mode, or `NULL` for * windowed mode. * @param[in] share The window whose context to share resources with, or `NULL` * to not share resources. - * @return The handle of the created window, or `NULL` if an error occurred. + * @return The handle of the created window, or `NULL` if an + * [error](@ref error_handling) occurred. * - * @remarks **Windows:** If the executable has an icon resource named - * `GLFW_ICON,` it will be set as the icon for the window. If no such icon is - * present, the `IDI_WINLOGO` icon will be used instead. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM, @ref GLFW_INVALID_VALUE, @ref GLFW_API_UNAVAILABLE, @ref + * GLFW_VERSION_UNAVAILABLE, @ref GLFW_FORMAT_UNAVAILABLE and @ref + * GLFW_PLATFORM_ERROR. * - * @remarks **Mac OS X:** The GLFW window has no icon, as it is not a document - * window, but the dock icon will be the same as the application bundle's icon. - * Also, the first time a window is opened the menu bar is populated with - * common commands like Hide, Quit and About. The (minimal) about dialog uses - * information from the application's bundle. For more information on bundles, - * see the Bundle Programming Guide provided by Apple. + * @remark @win32 Window creation will fail if the Microsoft GDI software + * OpenGL implementation is the only one available. * - * @note This function may only be called from the main thread. + * @remark @win32 If the executable has an icon resource named `GLFW_ICON,` it + * will be set as the initial icon for the window. If no such icon is present, + * the `IDI_WINLOGO` icon will be used instead. To set a different icon, see + * @ref glfwSetWindowIcon. * + * @remark @win32 The context to share resources with must not be current on + * any other thread. + * + * @remark @osx The GLFW window has no icon, as it is not a document + * window, but the dock icon will be the same as the application bundle's icon. + * For more information on bundles, see the + * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) + * in the Mac Developer Library. + * + * @remark @osx The first time a window is created the menu bar is populated + * with common commands like Hide, Quit and About. The About entry opens + * a minimal about dialog with information from the application's bundle. The + * menu bar can be disabled with a + * [compile-time option](@ref compile_options_osx). + * + * @remark @osx On OS X 10.10 and later the window frame will not be rendered + * at full resolution on Retina displays unless the `NSHighResolutionCapable` + * key is enabled in the application bundle's `Info.plist`. For more + * information, see + * [High Resolution Guidelines for OS X](https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html) + * in the Mac Developer Library. The GLFW test and example programs use + * a custom `Info.plist` template for this, which can be found as + * `CMake/MacOSXBundleInfo.plist.in` in the source tree. + * + * @remark @x11 Some window managers will not respect the placement of + * initially hidden windows. + * + * @remark @x11 Due to the asynchronous nature of X11, it may take a moment for + * a window to reach its requested state. This means you may not be able to + * query the final size, position or other attributes directly after window + * creation. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_creation * @sa glfwDestroyWindow * + * @since Added in version 3.0. Replaces `glfwOpenWindow`. + * * @ingroup window */ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, GLFWmonitor* monitor, GLFWwindow* share); @@ -1256,19 +1838,26 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, G * This function destroys the specified window and its context. On calling * this function, no further callbacks will be called for that window. * + * If the context of the specified window is current on the main thread, it is + * detached before being destroyed. + * * @param[in] window The window to destroy. * - * @note This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @note This function may not be called from a callback. + * @note The context of the specified window must not be current on any other + * thread when this function is called. * - * @note If the window's context is current on the main thread, it is - * detached before being destroyed. + * @reentrancy This function must not be called from a callback. * - * @warning The window's context must not be current on any other thread. + * @thread_safety This function must only be called from the main thread. * + * @sa @ref window_creation * @sa glfwCreateWindow * + * @since Added in version 3.0. Replaces `glfwCloseWindow`. + * * @ingroup window */ GLFWAPI void glfwDestroyWindow(GLFWwindow* window); @@ -1280,7 +1869,14 @@ GLFWAPI void glfwDestroyWindow(GLFWwindow* window); * @param[in] window The window to query. * @return The value of the close flag. * - * @remarks This function may be called from secondary threads. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref window_close + * + * @since Added in version 3.0. * * @ingroup window */ @@ -1295,7 +1891,14 @@ GLFWAPI int glfwWindowShouldClose(GLFWwindow* window); * @param[in] window The window whose flag to change. * @param[in] value The new value. * - * @remarks This function may be called from secondary threads. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref window_close + * + * @since Added in version 3.0. * * @ingroup window */ @@ -1309,25 +1912,86 @@ GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* window, int value); * @param[in] window The window whose title to change. * @param[in] title The UTF-8 encoded window title. * - * @note This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @osx The window title will not be updated until the next time you + * process events. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_title + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. * * @ingroup window */ GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title); +/*! @brief Sets the icon for the specified window. + * + * This function sets the icon of the specified window. If passed an array of + * candidate images, those of or closest to the sizes desired by the system are + * selected. If no images are specified, the window reverts to its default + * icon. + * + * The desired image sizes varies depending on platform and system settings. + * The selected images will be rescaled as needed. Good sizes include 16x16, + * 32x32 and 48x48. + * + * @param[in] window The window whose icon to set. + * @param[in] count The number of images in the specified array, or zero to + * revert to the default window icon. + * @param[in] images The images to create the icon from. This is ignored if + * count is zero. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The specified image data is copied before this function + * returns. + * + * @remark @osx The GLFW window has no icon, as it is not a document + * window, so this function does nothing. The dock icon will be the same as + * the application bundle's icon. For more information on bundles, see the + * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) + * in the Mac Developer Library. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_icon + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowIcon(GLFWwindow* window, int count, const GLFWimage* images); + /*! @brief Retrieves the position of the client area of the specified window. * * This function retrieves the position, in screen coordinates, of the * upper-left corner of the client area of the specified window. * + * Any or all of the position arguments may be `NULL`. If an error occurs, all + * non-`NULL` position arguments will be set to zero. + * * @param[in] window The window to query. * @param[out] xpos Where to store the x-coordinate of the upper-left corner of * the client area, or `NULL`. * @param[out] ypos Where to store the y-coordinate of the upper-left corner of * the client area, or `NULL`. * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_pos * @sa glfwSetWindowPos * + * @since Added in version 3.0. + * * @ingroup window */ GLFWAPI void glfwGetWindowPos(GLFWwindow* window, int* xpos, int* ypos); @@ -1335,31 +1999,30 @@ GLFWAPI void glfwGetWindowPos(GLFWwindow* window, int* xpos, int* ypos); /*! @brief Sets the position of the client area of the specified window. * * This function sets the position, in screen coordinates, of the upper-left - * corner of the client area of the window. + * corner of the client area of the specified windowed mode window. If the + * window is a full screen window, this function does nothing. * - * If the specified window is a full screen window, this function does nothing. + * __Do not use this function__ to move an already visible window unless you + * have very good reasons for doing so, as it will confuse and annoy the user. * - * If you wish to set an initial window position you should create a hidden - * window (using @ref glfwWindowHint and `GLFW_VISIBLE`), set its position and - * then show it. + * The window manager may put limits on what positions are allowed. GLFW + * cannot and should not override these limits. * * @param[in] window The window to query. * @param[in] xpos The x-coordinate of the upper-left corner of the client area. * @param[in] ypos The y-coordinate of the upper-left corner of the client area. * - * @note It is very rarely a good idea to move an already visible window, as it - * will confuse and annoy the user. - * - * @note This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @note The window manager may put limits on what positions are allowed. - * - * @bug **X11:** Some window managers ignore the set position of hidden (i.e. - * unmapped) windows, instead placing them where it thinks is appropriate once - * they are shown. + * @thread_safety This function must only be called from the main thread. * + * @sa @ref window_pos * @sa glfwGetWindowPos * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * * @ingroup window */ GLFWAPI void glfwSetWindowPos(GLFWwindow* window, int xpos, int ypos); @@ -1367,7 +2030,11 @@ GLFWAPI void glfwSetWindowPos(GLFWwindow* window, int xpos, int ypos); /*! @brief Retrieves the size of the client area of the specified window. * * This function retrieves the size, in screen coordinates, of the client area - * of the specified window. + * of the specified window. If you wish to retrieve the size of the + * framebuffer of the window in pixels, see @ref glfwGetFramebufferSize. + * + * Any or all of the size arguments may be `NULL`. If an error occurs, all + * non-`NULL` size arguments will be set to zero. * * @param[in] window The window whose size to retrieve. * @param[out] width Where to store the width, in screen coordinates, of the @@ -1375,31 +2042,134 @@ GLFWAPI void glfwSetWindowPos(GLFWwindow* window, int xpos, int ypos); * @param[out] height Where to store the height, in screen coordinates, of the * client area, or `NULL`. * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_size * @sa glfwSetWindowSize * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * * @ingroup window */ GLFWAPI void glfwGetWindowSize(GLFWwindow* window, int* width, int* height); +/*! @brief Sets the size limits of the specified window. + * + * This function sets the size limits of the client area of the specified + * window. If the window is full screen, the size limits only take effect + * once it is made windowed. If the window is not resizable, this function + * does nothing. + * + * The size limits are applied immediately to a windowed mode window and may + * cause it to be resized. + * + * The maximum dimensions must be greater than or equal to the minimum + * dimensions and all must be greater than or equal to zero. + * + * @param[in] window The window to set limits for. + * @param[in] minwidth The minimum width, in screen coordinates, of the client + * area, or `GLFW_DONT_CARE`. + * @param[in] minheight The minimum height, in screen coordinates, of the + * client area, or `GLFW_DONT_CARE`. + * @param[in] maxwidth The maximum width, in screen coordinates, of the client + * area, or `GLFW_DONT_CARE`. + * @param[in] maxheight The maximum height, in screen coordinates, of the + * client area, or `GLFW_DONT_CARE`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. + * + * @remark If you set size limits and an aspect ratio that conflict, the + * results are undefined. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_sizelimits + * @sa glfwSetWindowAspectRatio + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight); + +/*! @brief Sets the aspect ratio of the specified window. + * + * This function sets the required aspect ratio of the client area of the + * specified window. If the window is full screen, the aspect ratio only takes + * effect once it is made windowed. If the window is not resizable, this + * function does nothing. + * + * The aspect ratio is specified as a numerator and a denominator and both + * values must be greater than zero. For example, the common 16:9 aspect ratio + * is specified as 16 and 9, respectively. + * + * If the numerator and denominator is set to `GLFW_DONT_CARE` then the aspect + * ratio limit is disabled. + * + * The aspect ratio is applied immediately to a windowed mode window and may + * cause it to be resized. + * + * @param[in] window The window to set limits for. + * @param[in] numer The numerator of the desired aspect ratio, or + * `GLFW_DONT_CARE`. + * @param[in] denom The denominator of the desired aspect ratio, or + * `GLFW_DONT_CARE`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. + * + * @remark If you set size limits and an aspect ratio that conflict, the + * results are undefined. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_sizelimits + * @sa glfwSetWindowSizeLimits + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* window, int numer, int denom); + /*! @brief Sets the size of the client area of the specified window. * * This function sets the size, in screen coordinates, of the client area of * the specified window. * - * For full screen windows, this function selects and switches to the resolution - * closest to the specified size, without affecting the window's context. As - * the context is unaffected, the bit depths of the framebuffer remain - * unchanged. + * For full screen windows, this function updates the resolution of its desired + * video mode and switches to the video mode closest to it, without affecting + * the window's context. As the context is unaffected, the bit depths of the + * framebuffer remain unchanged. + * + * If you wish to update the refresh rate of the desired video mode in addition + * to its resolution, see @ref glfwSetWindowMonitor. + * + * The window manager may put limits on what sizes are allowed. GLFW cannot + * and should not override these limits. * * @param[in] window The window to resize. - * @param[in] width The desired width of the specified window. - * @param[in] height The desired height of the specified window. + * @param[in] width The desired width, in screen coordinates, of the window + * client area. + * @param[in] height The desired height, in screen coordinates, of the window + * client area. * - * @note This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @note The window manager may put limits on what window sizes are allowed. + * @thread_safety This function must only be called from the main thread. * + * @sa @ref window_size * @sa glfwGetWindowSize + * @sa glfwSetWindowMonitor + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. * * @ingroup window */ @@ -1408,7 +2178,11 @@ GLFWAPI void glfwSetWindowSize(GLFWwindow* window, int width, int height); /*! @brief Retrieves the size of the framebuffer of the specified window. * * This function retrieves the size, in pixels, of the framebuffer of the - * specified window. + * specified window. If you wish to retrieve the size of the window in screen + * coordinates, see @ref glfwGetWindowSize. + * + * Any or all of the size arguments may be `NULL`. If an error occurs, all + * non-`NULL` size arguments will be set to zero. * * @param[in] window The window whose framebuffer to query. * @param[out] width Where to store the width, in pixels, of the framebuffer, @@ -1416,24 +2190,79 @@ GLFWAPI void glfwSetWindowSize(GLFWwindow* window, int width, int height); * @param[out] height Where to store the height, in pixels, of the framebuffer, * or `NULL`. * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_fbsize * @sa glfwSetFramebufferSizeCallback * + * @since Added in version 3.0. + * * @ingroup window */ GLFWAPI void glfwGetFramebufferSize(GLFWwindow* window, int* width, int* height); +/*! @brief Retrieves the size of the frame of the window. + * + * This function retrieves the size, in screen coordinates, of each edge of the + * frame of the specified window. This size includes the title bar, if the + * window has one. The size of the frame may vary depending on the + * [window-related hints](@ref window_hints_wnd) used to create it. + * + * Because this function retrieves the size of each window frame edge and not + * the offset along a particular coordinate axis, the retrieved values will + * always be zero or positive. + * + * Any or all of the size arguments may be `NULL`. If an error occurs, all + * non-`NULL` size arguments will be set to zero. + * + * @param[in] window The window whose frame size to query. + * @param[out] left Where to store the size, in screen coordinates, of the left + * edge of the window frame, or `NULL`. + * @param[out] top Where to store the size, in screen coordinates, of the top + * edge of the window frame, or `NULL`. + * @param[out] right Where to store the size, in screen coordinates, of the + * right edge of the window frame, or `NULL`. + * @param[out] bottom Where to store the size, in screen coordinates, of the + * bottom edge of the window frame, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_size + * + * @since Added in version 3.1. + * + * @ingroup window + */ +GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* window, int* left, int* top, int* right, int* bottom); + /*! @brief Iconifies the specified window. * - * This function iconifies/minimizes the specified window, if it was previously - * restored. If it is a full screen window, the original monitor resolution is - * restored until the window is restored. If the window is already iconified, - * this function does nothing. + * This function iconifies (minimizes) the specified window if it was + * previously restored. If the window is already iconified, this function does + * nothing. + * + * If the specified window is a full screen window, the original monitor + * resolution is restored until the window is restored. * * @param[in] window The window to iconify. * - * @note This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * + * @sa @ref window_iconify * @sa glfwRestoreWindow + * @sa glfwMaximizeWindow + * + * @since Added in version 2.1. + * @glfw3 Added window handle parameter. * * @ingroup window */ @@ -1441,74 +2270,227 @@ GLFWAPI void glfwIconifyWindow(GLFWwindow* window); /*! @brief Restores the specified window. * - * This function restores the specified window, if it was previously - * iconified/minimized. If it is a full screen window, the resolution chosen - * for the window is restored on the selected monitor. If the window is - * already restored, this function does nothing. + * This function restores the specified window if it was previously iconified + * (minimized) or maximized. If the window is already restored, this function + * does nothing. + * + * If the specified window is a full screen window, the resolution chosen for + * the window is restored on the selected monitor. * * @param[in] window The window to restore. * - * @note This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_iconify * @sa glfwIconifyWindow + * @sa glfwMaximizeWindow + * + * @since Added in version 2.1. + * @glfw3 Added window handle parameter. * * @ingroup window */ GLFWAPI void glfwRestoreWindow(GLFWwindow* window); +/*! @brief Maximizes the specified window. + * + * This function maximizes the specified window if it was previously not + * maximized. If the window is already maximized, this function does nothing. + * + * If the specified window is a full screen window, this function does nothing. + * + * @param[in] window The window to maximize. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_iconify + * @sa glfwIconifyWindow + * @sa glfwRestoreWindow + * + * @since Added in GLFW 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwMaximizeWindow(GLFWwindow* window); + /*! @brief Makes the specified window visible. * - * This function makes the specified window visible, if it was previously + * This function makes the specified window visible if it was previously * hidden. If the window is already visible or is in full screen mode, this * function does nothing. * * @param[in] window The window to make visible. * - * @note This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_hide * @sa glfwHideWindow * + * @since Added in version 3.0. + * * @ingroup window */ GLFWAPI void glfwShowWindow(GLFWwindow* window); /*! @brief Hides the specified window. * - * This function hides the specified window, if it was previously visible. If + * This function hides the specified window if it was previously visible. If * the window is already hidden or is in full screen mode, this function does * nothing. * * @param[in] window The window to hide. * - * @note This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_hide * @sa glfwShowWindow * + * @since Added in version 3.0. + * * @ingroup window */ GLFWAPI void glfwHideWindow(GLFWwindow* window); +/*! @brief Brings the specified window to front and sets input focus. + * + * This function brings the specified window to front and sets input focus. + * The window should already be visible and not iconified. + * + * By default, both windowed and full screen mode windows are focused when + * initially created. Set the [GLFW_FOCUSED](@ref window_hints_wnd) to disable + * this behavior. + * + * __Do not use this function__ to steal focus from other applications unless + * you are certain that is what the user wants. Focus stealing can be + * extremely disruptive. + * + * @param[in] window The window to give input focus. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_focus + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwFocusWindow(GLFWwindow* window); + /*! @brief Returns the monitor that the window uses for full screen mode. * * This function returns the handle of the monitor that the specified window is * in full screen on. * * @param[in] window The window to query. - * @return The monitor, or `NULL` if the window is in windowed mode. + * @return The monitor, or `NULL` if the window is in windowed mode or an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_monitor + * @sa glfwSetWindowMonitor + * + * @since Added in version 3.0. * * @ingroup window */ GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window); +/*! @brief Sets the mode, monitor, video mode and placement of a window. + * + * This function sets the monitor that the window uses for full screen mode or, + * if the monitor is `NULL`, makes it windowed mode. + * + * When setting a monitor, this function updates the width, height and refresh + * rate of the desired video mode and switches to the video mode closest to it. + * The window position is ignored when setting a monitor. + * + * When the monitor is `NULL`, the position, width and height are used to + * place the window client area. The refresh rate is ignored when no monitor + * is specified. + * + * If you only wish to update the resolution of a full screen window or the + * size of a windowed mode window, see @ref glfwSetWindowSize. + * + * When a window transitions from full screen to windowed mode, this function + * restores any previous window settings such as whether it is decorated, + * floating, resizable, has size or aspect ratio limits, etc.. + * + * @param[in] window The window whose monitor, size or video mode to set. + * @param[in] monitor The desired monitor, or `NULL` to set windowed mode. + * @param[in] xpos The desired x-coordinate of the upper-left corner of the + * client area. + * @param[in] ypos The desired y-coordinate of the upper-left corner of the + * client area. + * @param[in] width The desired with, in screen coordinates, of the client area + * or video mode. + * @param[in] height The desired height, in screen coordinates, of the client + * area or video mode. + * @param[in] refreshRate The desired refresh rate, in Hz, of the video mode, + * or `GLFW_DONT_CARE`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_monitor + * @sa @ref window_full_screen + * @sa glfwGetWindowMonitor + * @sa glfwSetWindowSize + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowMonitor(GLFWwindow* window, GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); + /*! @brief Returns an attribute of the specified window. * - * This function returns an attribute of the specified window. There are many - * attributes, some related to the window and others to its context. + * This function returns the value of an attribute of the specified window or + * its OpenGL or OpenGL ES context. * * @param[in] window The window to query. * @param[in] attrib The [window attribute](@ref window_attribs) whose value to * return. - * @return The value of the attribute, or zero if an error occurred. + * @return The value of the attribute, or zero if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @remark Framebuffer related hints are not window attributes. See @ref + * window_attribs_fb for more information. + * + * @remark Zero is a valid value for many window and context related + * attributes so you cannot use a return value of zero as an indication of + * errors. However, this function should not fail as long as it is passed + * valid arguments and the library has been [initialized](@ref intro_init). + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_attribs + * + * @since Added in version 3.0. Replaces `glfwGetWindowParam` and + * `glfwGetGLVersion`. * * @ingroup window */ @@ -1523,8 +2505,16 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* window, int attrib); * @param[in] window The window whose pointer to set. * @param[in] pointer The new value. * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref window_userptr * @sa glfwGetWindowUserPointer * + * @since Added in version 3.0. + * * @ingroup window */ GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* window, void* pointer); @@ -1536,8 +2526,16 @@ GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* window, void* pointer); * * @param[in] window The window whose pointer to return. * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref window_userptr * @sa glfwSetWindowUserPointer * + * @since Added in version 3.0. + * * @ingroup window */ GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* window); @@ -1551,8 +2549,16 @@ GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* window); * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_pos + * + * @since Added in version 3.0. * * @ingroup window */ @@ -1567,8 +2573,17 @@ GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* window, GLFWwindow * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_size + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter and return value. * * @ingroup window */ @@ -1588,11 +2603,20 @@ GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* window, GLFWwind * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @remark @osx Selecting Quit from the application menu will trigger the close + * callback for all windows. * - * @remarks **Mac OS X:** Selecting Quit from the application menu will - * trigger the close callback for all windows. + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_close + * + * @since Added in version 2.5. + * @glfw3 Added window handle parameter and return value. * * @ingroup window */ @@ -1611,12 +2635,17 @@ GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwi * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). * - * @note On compositing window systems such as Aero, Compiz or Aqua, where the - * window contents are saved off-screen, this callback may be called only very - * infrequently or never at all. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_refresh + * + * @since Added in version 2.5. + * @glfw3 Added window handle parameter and return value. * * @ingroup window */ @@ -1625,18 +2654,26 @@ GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* window, GL /*! @brief Sets the focus callback for the specified window. * * This function sets the focus callback of the specified window, which is - * called when the window gains or loses focus. + * called when the window gains or loses input focus. * - * After the focus callback is called for a window that lost focus, synthetic - * key and mouse button release events will be generated for all such that had - * been pressed. For more information, see @ref glfwSetKeyCallback and @ref - * glfwSetMouseButtonCallback. + * After the focus callback is called for a window that lost input focus, + * synthetic key and mouse button release events will be generated for all such + * that had been pressed. For more information, see @ref glfwSetKeyCallback + * and @ref glfwSetMouseButtonCallback. * * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_focus + * + * @since Added in version 3.0. * * @ingroup window */ @@ -1650,8 +2687,16 @@ GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* window, GLFWwi * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_iconify + * + * @since Added in version 3.0. * * @ingroup window */ @@ -1665,8 +2710,16 @@ GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* window, GL * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_fbsize + * + * @since Added in version 3.0. * * @ingroup window */ @@ -1674,124 +2727,317 @@ GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* window /*! @brief Processes all pending events. * - * This function processes only those events that have already been received - * and then returns immediately. Processing events will cause the window and - * input callbacks associated with those events to be called. + * This function processes only those events that are already in the event + * queue and then returns immediately. Processing events will cause the window + * and input callbacks associated with those events to be called. + * + * On some platforms, a window move, resize or menu operation will cause event + * processing to block. This is due to how event processing is designed on + * those platforms. You can use the + * [window refresh callback](@ref window_refresh) to redraw the contents of + * your window when necessary during such operations. * - * This function is not required for joystick input to work. + * On some platforms, certain events are sent directly to the application + * without going through the event queue, causing callbacks to be called + * outside of a call to one of the event processing functions. * - * @par New in GLFW 3 - * This function is no longer called by @ref glfwSwapBuffers. You need to call - * it or @ref glfwWaitEvents yourself. + * Event processing is not required for joystick input to work. * - * @note This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @note This function may not be called from a callback. + * @reentrancy This function must not be called from a callback. * - * @note On some platforms, certain callbacks may be called outside of a call - * to one of the event processing functions. + * @thread_safety This function must only be called from the main thread. * + * @sa @ref events * @sa glfwWaitEvents + * @sa glfwWaitEventsTimeout + * + * @since Added in version 1.0. * * @ingroup window */ GLFWAPI void glfwPollEvents(void); -/*! @brief Waits until events are pending and processes them. +/*! @brief Waits until events are queued and processes them. * - * This function puts the calling thread to sleep until at least one event has - * been received. Once one or more events have been received, it behaves as if - * @ref glfwPollEvents was called, i.e. the events are processed and the - * function then returns immediately. Processing events will cause the window - * and input callbacks associated with those events to be called. + * This function puts the calling thread to sleep until at least one event is + * available in the event queue. Once one or more events are available, + * it behaves exactly like @ref glfwPollEvents, i.e. the events in the queue + * are processed and the function then returns immediately. Processing events + * will cause the window and input callbacks associated with those events to be + * called. * * Since not all events are associated with callbacks, this function may return * without a callback having been called even if you are monitoring all * callbacks. * - * This function is not required for joystick input to work. + * On some platforms, a window move, resize or menu operation will cause event + * processing to block. This is due to how event processing is designed on + * those platforms. You can use the + * [window refresh callback](@ref window_refresh) to redraw the contents of + * your window when necessary during such operations. + * + * On some platforms, certain callbacks may be called outside of a call to one + * of the event processing functions. + * + * If no windows exist, this function returns immediately. For synchronization + * of threads in applications that do not create windows, use your threading + * library of choice. * - * @note This function may only be called from the main thread. + * Event processing is not required for joystick input to work. * - * @note This function may not be called from a callback. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @note On some platforms, certain callbacks may be called outside of a call - * to one of the event processing functions. + * @reentrancy This function must not be called from a callback. * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref events * @sa glfwPollEvents + * @sa glfwWaitEventsTimeout + * + * @since Added in version 2.5. * * @ingroup window */ GLFWAPI void glfwWaitEvents(void); -/*! @brief Returns the value of an input option for the specified window. +/*! @brief Waits with timeout until events are queued and processes them. * - * @param[in] window The window to query. - * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or - * `GLFW_STICKY_MOUSE_BUTTONS`. + * This function puts the calling thread to sleep until at least one event is + * available in the event queue, or until the specified timeout is reached. If + * one or more events are available, it behaves exactly like @ref + * glfwPollEvents, i.e. the events in the queue are processed and the function + * then returns immediately. Processing events will cause the window and input + * callbacks associated with those events to be called. * - * @sa glfwSetInputMode + * The timeout value must be a positive finite number. * - * @ingroup input - */ -GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); - -/*! @brief Sets an input option for the specified window. - * @param[in] window The window whose input mode to set. - * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or - * `GLFW_STICKY_MOUSE_BUTTONS`. - * @param[in] value The new value of the specified input mode. + * Since not all events are associated with callbacks, this function may return + * without a callback having been called even if you are monitoring all + * callbacks. * - * If `mode` is `GLFW_CURSOR`, the value must be one of the supported input - * modes: - * - `GLFW_CURSOR_NORMAL` makes the cursor visible and behaving normally. - * - `GLFW_CURSOR_HIDDEN` makes the cursor invisible when it is over the client - * area of the window. - * - `GLFW_CURSOR_DISABLED` disables the cursor and removes any limitations on - * cursor movement. - * - * If `mode` is `GLFW_STICKY_KEYS`, the value must be either `GL_TRUE` to - * enable sticky keys, or `GL_FALSE` to disable it. If sticky keys are - * enabled, a key press will ensure that @ref glfwGetKey returns @ref - * GLFW_PRESS the next time it is called even if the key had been released - * before the call. This is useful when you are only interested in whether - * keys have been pressed but not when or in which order. - * - * If `mode` is `GLFW_STICKY_MOUSE_BUTTONS`, the value must be either `GL_TRUE` - * to enable sticky mouse buttons, or `GL_FALSE` to disable it. If sticky - * mouse buttons are enabled, a mouse button press will ensure that @ref - * glfwGetMouseButton returns @ref GLFW_PRESS the next time it is called even - * if the mouse button had been released before the call. This is useful when - * you are only interested in whether mouse buttons have been pressed but not - * when or in which order. + * On some platforms, a window move, resize or menu operation will cause event + * processing to block. This is due to how event processing is designed on + * those platforms. You can use the + * [window refresh callback](@ref window_refresh) to redraw the contents of + * your window when necessary during such operations. * - * @sa glfwGetInputMode + * On some platforms, certain callbacks may be called outside of a call to one + * of the event processing functions. * - * @ingroup input - */ -GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value); - -/*! @brief Returns the last reported state of a keyboard key for the specified - * window. + * If no windows exist, this function returns immediately. For synchronization + * of threads in applications that do not create windows, use your threading + * library of choice. * - * This function returns the last state reported for the specified key to the - * specified window. The returned state is one of `GLFW_PRESS` or - * `GLFW_RELEASE`. The higher-level state `GLFW_REPEAT` is only reported to - * the key callback. + * Event processing is not required for joystick input to work. * - * If the `GLFW_STICKY_KEYS` input mode is enabled, this function returns - * `GLFW_PRESS` the first time you call this function after a key has been - * pressed, even if the key has already been released. + * @param[in] timeout The maximum amount of time, in seconds, to wait. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref events + * @sa glfwPollEvents + * @sa glfwWaitEvents + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwWaitEventsTimeout(double timeout); + +/*! @brief Posts an empty event to the event queue. + * + * This function posts an empty event from the current thread to the event + * queue, causing @ref glfwWaitEvents or @ref glfwWaitEventsTimeout to return. + * + * If no windows exist, this function returns immediately. For synchronization + * of threads in applications that do not create windows, use your threading + * library of choice. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref events + * @sa glfwWaitEvents + * @sa glfwWaitEventsTimeout + * + * @since Added in version 3.1. + * + * @ingroup window + */ +GLFWAPI void glfwPostEmptyEvent(void); + +/*! @brief Returns the value of an input option for the specified window. + * + * This function returns the value of an input option for the specified window. + * The mode must be one of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or + * `GLFW_STICKY_MOUSE_BUTTONS`. + * + * @param[in] window The window to query. + * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or + * `GLFW_STICKY_MOUSE_BUTTONS`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa glfwSetInputMode + * + * @since Added in version 3.0. + * + * @ingroup input + */ +GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); + +/*! @brief Sets an input option for the specified window. + * + * This function sets an input mode option for the specified window. The mode + * must be one of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or + * `GLFW_STICKY_MOUSE_BUTTONS`. + * + * If the mode is `GLFW_CURSOR`, the value must be one of the following cursor + * modes: + * - `GLFW_CURSOR_NORMAL` makes the cursor visible and behaving normally. + * - `GLFW_CURSOR_HIDDEN` makes the cursor invisible when it is over the client + * area of the window but does not restrict the cursor from leaving. + * - `GLFW_CURSOR_DISABLED` hides and grabs the cursor, providing virtual + * and unlimited cursor movement. This is useful for implementing for + * example 3D camera controls. + * + * If the mode is `GLFW_STICKY_KEYS`, the value must be either `GLFW_TRUE` to + * enable sticky keys, or `GLFW_FALSE` to disable it. If sticky keys are + * enabled, a key press will ensure that @ref glfwGetKey returns `GLFW_PRESS` + * the next time it is called even if the key had been released before the + * call. This is useful when you are only interested in whether keys have been + * pressed but not when or in which order. + * + * If the mode is `GLFW_STICKY_MOUSE_BUTTONS`, the value must be either + * `GLFW_TRUE` to enable sticky mouse buttons, or `GLFW_FALSE` to disable it. + * If sticky mouse buttons are enabled, a mouse button press will ensure that + * @ref glfwGetMouseButton returns `GLFW_PRESS` the next time it is called even + * if the mouse button had been released before the call. This is useful when + * you are only interested in whether mouse buttons have been pressed but not + * when or in which order. + * + * @param[in] window The window whose input mode to set. + * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or + * `GLFW_STICKY_MOUSE_BUTTONS`. + * @param[in] value The new value of the specified input mode. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa glfwGetInputMode + * + * @since Added in version 3.0. Replaces `glfwEnable` and `glfwDisable`. + * + * @ingroup input + */ +GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value); + +/*! @brief Returns the localized name of the specified printable key. + * + * This function returns the localized name of the specified printable key. + * This is intended for displaying key bindings to the user. + * + * If the key is `GLFW_KEY_UNKNOWN`, the scancode is used instead, otherwise + * the scancode is ignored. If a non-printable key or (if the key is + * `GLFW_KEY_UNKNOWN`) a scancode that maps to a non-printable key is + * specified, this function returns `NULL`. + * + * This behavior allows you to pass in the arguments passed to the + * [key callback](@ref input_key) without modification. + * + * The printable keys are: + * - `GLFW_KEY_APOSTROPHE` + * - `GLFW_KEY_COMMA` + * - `GLFW_KEY_MINUS` + * - `GLFW_KEY_PERIOD` + * - `GLFW_KEY_SLASH` + * - `GLFW_KEY_SEMICOLON` + * - `GLFW_KEY_EQUAL` + * - `GLFW_KEY_LEFT_BRACKET` + * - `GLFW_KEY_RIGHT_BRACKET` + * - `GLFW_KEY_BACKSLASH` + * - `GLFW_KEY_WORLD_1` + * - `GLFW_KEY_WORLD_2` + * - `GLFW_KEY_0` to `GLFW_KEY_9` + * - `GLFW_KEY_A` to `GLFW_KEY_Z` + * - `GLFW_KEY_KP_0` to `GLFW_KEY_KP_9` + * - `GLFW_KEY_KP_DECIMAL` + * - `GLFW_KEY_KP_DIVIDE` + * - `GLFW_KEY_KP_MULTIPLY` + * - `GLFW_KEY_KP_SUBTRACT` + * - `GLFW_KEY_KP_ADD` + * - `GLFW_KEY_KP_EQUAL` + * + * @param[in] key The key to query, or `GLFW_KEY_UNKNOWN`. + * @param[in] scancode The scancode of the key to query. + * @return The localized name of the key, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the next call to @ref + * glfwGetKeyName, or until the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_key_name + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI const char* glfwGetKeyName(int key, int scancode); + +/*! @brief Returns the last reported state of a keyboard key for the specified + * window. + * + * This function returns the last state reported for the specified key to the + * specified window. The returned state is one of `GLFW_PRESS` or + * `GLFW_RELEASE`. The higher-level action `GLFW_REPEAT` is only reported to + * the key callback. + * + * If the `GLFW_STICKY_KEYS` input mode is enabled, this function returns + * `GLFW_PRESS` the first time you call it for a key that was pressed, even if + * that key has already been released. * * The key functions deal with physical keys, with [key tokens](@ref keys) * named after their use on the standard US keyboard layout. If you want to * input text, use the Unicode character callback instead. * + * The [modifier key bit masks](@ref mods) are not key tokens and cannot be + * used with this function. + * + * __Do not use this function__ to implement [text input](@ref input_char). + * * @param[in] window The desired window. - * @param[in] key The desired [keyboard key](@ref keys). + * @param[in] key The desired [keyboard key](@ref keys). `GLFW_KEY_UNKNOWN` is + * not a valid key for this function. * @return One of `GLFW_PRESS` or `GLFW_RELEASE`. * - * @note `GLFW_KEY_UNKNOWN` is not a valid key for this function. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_key + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. * * @ingroup input */ @@ -1801,25 +3047,37 @@ GLFWAPI int glfwGetKey(GLFWwindow* window, int key); * window. * * This function returns the last state reported for the specified mouse button - * to the specified window. + * to the specified window. The returned state is one of `GLFW_PRESS` or + * `GLFW_RELEASE`. * * If the `GLFW_STICKY_MOUSE_BUTTONS` input mode is enabled, this function - * returns `GLFW_PRESS` the first time you call this function after a mouse - * button has been pressed, even if the mouse button has already been released. + * `GLFW_PRESS` the first time you call it for a mouse button that was pressed, + * even if that mouse button has already been released. * * @param[in] window The desired window. * @param[in] button The desired [mouse button](@ref buttons). * @return One of `GLFW_PRESS` or `GLFW_RELEASE`. * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_mouse_button + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * * @ingroup input */ GLFWAPI int glfwGetMouseButton(GLFWwindow* window, int button); -/*! @brief Retrieves the last reported cursor position, relative to the client - * area of the window. +/*! @brief Retrieves the position of the cursor relative to the client area of + * the window. * - * This function returns the last reported position of the cursor to the - * specified window. + * This function returns the position of the cursor, in screen coordinates, + * relative to the upper-left corner of the client area of the specified + * window. * * If the cursor is disabled (with `GLFW_CURSOR_DISABLED`) then the cursor * position is unbounded and limited only by the minimum and maximum values of @@ -1829,26 +3087,44 @@ GLFWAPI int glfwGetMouseButton(GLFWwindow* window, int button); * `floor` function. Casting directly to an integer type works for positive * coordinates, but fails for negative ones. * + * Any or all of the position arguments may be `NULL`. If an error occurs, all + * non-`NULL` position arguments will be set to zero. + * * @param[in] window The desired window. * @param[out] xpos Where to store the cursor x-coordinate, relative to the * left edge of the client area, or `NULL`. * @param[out] ypos Where to store the cursor y-coordinate, relative to the to * top edge of the client area, or `NULL`. * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_pos * @sa glfwSetCursorPos * + * @since Added in version 3.0. Replaces `glfwGetMousePos`. + * * @ingroup input */ GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos); -/*! @brief Sets the position of the cursor, relative to the client area of the window. +/*! @brief Sets the position of the cursor, relative to the client area of the + * window. * - * This function sets the position of the cursor. The specified window must be - * focused. If the window does not have focus when this function is called, it - * fails silently. + * This function sets the position, in screen coordinates, of the cursor + * relative to the upper-left corner of the client area of the specified + * window. The window must have input focus. If the window does not have + * input focus when this function is called, it fails silently. * - * If the cursor is disabled (with `GLFW_CURSOR_DISABLED`) then the cursor - * position is unbounded and limited only by the minimum and maximum values of + * __Do not use this function__ to implement things like camera controls. GLFW + * already provides the `GLFW_CURSOR_DISABLED` cursor mode that hides the + * cursor, transparently re-centers it and provides unconstrained cursor + * motion. See @ref glfwSetInputMode for more information. + * + * If the cursor mode is `GLFW_CURSOR_DISABLED` then the cursor position is + * unconstrained and limited only by the minimum and maximum values of * a `double`. * * @param[in] window The desired window. @@ -1857,15 +3133,139 @@ GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos); * @param[in] ypos The desired y-coordinate, relative to the top edge of the * client area. * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_pos * @sa glfwGetCursorPos * + * @since Added in version 3.0. Replaces `glfwSetMousePos`. + * * @ingroup input */ GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); +/*! @brief Creates a custom cursor. + * + * Creates a new custom cursor image that can be set for a window with @ref + * glfwSetCursor. The cursor can be destroyed with @ref glfwDestroyCursor. + * Any remaining cursors are destroyed by @ref glfwTerminate. + * + * The pixels are 32-bit, little-endian, non-premultiplied RGBA, i.e. eight + * bits per channel. They are arranged canonically as packed sequential rows, + * starting from the top-left corner. + * + * The cursor hotspot is specified in pixels, relative to the upper-left corner + * of the cursor image. Like all other coordinate systems in GLFW, the X-axis + * points to the right and the Y-axis points down. + * + * @param[in] image The desired cursor image. + * @param[in] xhot The desired x-coordinate, in pixels, of the cursor hotspot. + * @param[in] yhot The desired y-coordinate, in pixels, of the cursor hotspot. + * @return The handle of the created cursor, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The specified image data is copied before this function + * returns. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_object + * @sa glfwDestroyCursor + * @sa glfwCreateStandardCursor + * + * @since Added in version 3.1. + * + * @ingroup input + */ +GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot); + +/*! @brief Creates a cursor with a standard shape. + * + * Returns a cursor with a [standard shape](@ref shapes), that can be set for + * a window with @ref glfwSetCursor. + * + * @param[in] shape One of the [standard shapes](@ref shapes). + * @return A new cursor ready to use or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_object + * @sa glfwCreateCursor + * + * @since Added in version 3.1. + * + * @ingroup input + */ +GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape); + +/*! @brief Destroys a cursor. + * + * This function destroys a cursor previously created with @ref + * glfwCreateCursor. Any remaining cursors will be destroyed by @ref + * glfwTerminate. + * + * @param[in] cursor The cursor object to destroy. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_object + * @sa glfwCreateCursor + * + * @since Added in version 3.1. + * + * @ingroup input + */ +GLFWAPI void glfwDestroyCursor(GLFWcursor* cursor); + +/*! @brief Sets the cursor for the window. + * + * This function sets the cursor image to be used when the cursor is over the + * client area of the specified window. The set cursor will only be visible + * when the [cursor mode](@ref cursor_mode) of the window is + * `GLFW_CURSOR_NORMAL`. + * + * On some platforms, the set cursor may not be visible unless the window also + * has input focus. + * + * @param[in] window The window to set the cursor for. + * @param[in] cursor The cursor to set, or `NULL` to switch back to the default + * arrow cursor. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_object + * + * @since Added in version 3.1. + * + * @ingroup input + */ +GLFWAPI void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor); + /*! @brief Sets the key callback. * - * This function sets the key callback of the specific window, which is called + * This function sets the key callback of the specified window, which is called * when a key is pressed, repeated or released. * * The key functions deal with physical keys, with layout independent @@ -1873,16 +3273,16 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); * layout. If you want to input text, use the * [character callback](@ref glfwSetCharCallback) instead. * - * When a window loses focus, it will generate synthetic key release events - * for all pressed keys. You can tell these events from user-generated events - * by the fact that the synthetic ones are generated after the window has lost - * focus, i.e. `GLFW_FOCUSED` will be false and the focus callback will have - * already been called. + * When a window loses input focus, it will generate synthetic key release + * events for all pressed keys. You can tell these events from user-generated + * events by the fact that the synthetic ones are generated after the focus + * loss event has been processed, i.e. after the + * [window focus callback](@ref glfwSetWindowFocusCallback) has been called. * * The scancode of a key is specific to that platform or sometimes even to that * machine. Scancodes are intended to allow users to bind keys that don't have * a GLFW key token. Such keys have `key` set to `GLFW_KEY_UNKNOWN`, their - * state is not saved and so it cannot be retrieved with @ref glfwGetKey. + * state is not saved and so it cannot be queried with @ref glfwGetKey. * * Sometimes GLFW needs to generate synthetic key events, in which case the * scancode may be zero. @@ -1890,8 +3290,17 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); * @param[in] window The window whose callback to set. * @param[in] cbfun The new key callback, or `NULL` to remove the currently * set callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_key + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter and return value. * * @ingroup input */ @@ -1899,39 +3308,100 @@ GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun cbfun); /*! @brief Sets the Unicode character callback. * - * This function sets the character callback of the specific window, which is + * This function sets the character callback of the specified window, which is * called when a Unicode character is input. * - * The character callback is intended for text input. If you want to know - * whether a specific key was pressed or released, use the + * The character callback is intended for Unicode text input. As it deals with + * characters, it is keyboard layout dependent, whereas the + * [key callback](@ref glfwSetKeyCallback) is not. Characters do not map 1:1 + * to physical keys, as a key may produce zero, one or more characters. If you + * want to know whether a specific physical key was pressed or released, see + * the key callback instead. + * + * The character callback behaves as system text input normally does and will + * not be called if modifier keys are held down that would prevent normal text + * input on that platform, for example a Super (Command) key on OS X or Alt key + * on Windows. There is a + * [character with modifiers callback](@ref glfwSetCharModsCallback) that + * receives these events. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_char + * + * @since Added in version 2.4. + * @glfw3 Added window handle parameter and return value. + * + * @ingroup input + */ +GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun cbfun); + +/*! @brief Sets the Unicode character with modifiers callback. + * + * This function sets the character with modifiers callback of the specified + * window, which is called when a Unicode character is input regardless of what + * modifier keys are used. + * + * The character with modifiers callback is intended for implementing custom + * Unicode character input. For regular Unicode text input, see the + * [character callback](@ref glfwSetCharCallback). Like the character + * callback, the character with modifiers callback deals with characters and is + * keyboard layout dependent. Characters do not map 1:1 to physical keys, as + * a key may produce zero, one or more characters. If you want to know whether + * a specific physical key was pressed or released, see the * [key callback](@ref glfwSetKeyCallback) instead. * * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_char + * + * @since Added in version 3.1. * * @ingroup input */ -GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun cbfun); +GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmodsfun cbfun); /*! @brief Sets the mouse button callback. * * This function sets the mouse button callback of the specified window, which * is called when a mouse button is pressed or released. * - * When a window loses focus, it will generate synthetic mouse button release - * events for all pressed mouse buttons. You can tell these events from - * user-generated events by the fact that the synthetic ones are generated - * after the window has lost focus, i.e. `GLFW_FOCUSED` will be false and the - * focus callback will have already been called. + * When a window loses input focus, it will generate synthetic mouse button + * release events for all pressed mouse buttons. You can tell these events + * from user-generated events by the fact that the synthetic ones are generated + * after the focus loss event has been processed, i.e. after the + * [window focus callback](@ref glfwSetWindowFocusCallback) has been called. * * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_mouse_button + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter and return value. * * @ingroup input */ @@ -1941,13 +3411,22 @@ GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* window, GLFWmo * * This function sets the cursor position callback of the specified window, * which is called when the cursor is moved. The callback is provided with the - * position relative to the upper-left corner of the client area of the window. + * position, in screen coordinates, relative to the upper-left corner of the + * client area of the window. * * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_pos + * + * @since Added in version 3.0. Replaces `glfwSetMousePosCallback`. * * @ingroup input */ @@ -1962,8 +3441,16 @@ GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* window, GLFWcursor * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_enter + * + * @since Added in version 3.0. * * @ingroup input */ @@ -1981,19 +3468,64 @@ GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* window, GLFWcu * @param[in] window The window whose callback to set. * @param[in] cbfun The new scroll callback, or `NULL` to remove the currently * set callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref scrolling + * + * @since Added in version 3.0. Replaces `glfwSetMouseWheelCallback`. * * @ingroup input */ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun cbfun); +/*! @brief Sets the file drop callback. + * + * This function sets the file drop callback of the specified window, which is + * called when one or more dragged files are dropped on the window. + * + * Because the path array and its strings may have been generated specifically + * for that event, they are not guaranteed to be valid after the callback has + * returned. If you wish to use them after the callback returns, you need to + * make a deep copy. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new file drop callback, or `NULL` to remove the + * currently set callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref path_drop + * + * @since Added in version 3.1. + * + * @ingroup input + */ +GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun cbfun); + /*! @brief Returns whether the specified joystick is present. * * This function returns whether the specified joystick is present. * - * @param[in] joy The joystick to query. - * @return `GL_TRUE` if the joystick is present, or `GL_FALSE` otherwise. + * @param[in] joy The [joystick](@ref joysticks) to query. + * @return `GLFW_TRUE` if the joystick is present, or `GLFW_FALSE` otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref joystick + * + * @since Added in version 3.0. Replaces `glfwGetJoystickParam`. * * @ingroup input */ @@ -2002,17 +3534,32 @@ GLFWAPI int glfwJoystickPresent(int joy); /*! @brief Returns the values of all axes of the specified joystick. * * This function returns the values of all axes of the specified joystick. + * Each element in the array is a value between -1.0 and 1.0. * - * @param[in] joy The joystick to query. - * @param[out] count Where to store the size of the returned array. This is - * set to zero if an error occurred. - * @return An array of axis values, or `NULL` if the joystick is not present. + * Querying a joystick slot with no device present is not an error, but will + * cause this function to return `NULL`. Call @ref glfwJoystickPresent to + * check device presence. * - * @note The returned array is allocated and freed by GLFW. You should not - * free it yourself. + * @param[in] joy The [joystick](@ref joysticks) to query. + * @param[out] count Where to store the number of axis values in the returned + * array. This is set to zero if the joystick is not present or an error + * occurred. + * @return An array of axis values, or `NULL` if the joystick is not present or + * an [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected, this function is called again for that joystick or the library + * is terminated. * - * @note The returned array is valid only until the next call to @ref - * glfwGetJoystickAxes for that joystick. + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref joystick_axis + * + * @since Added in version 3.0. Replaces `glfwGetJoystickPos`. * * @ingroup input */ @@ -2021,17 +3568,33 @@ GLFWAPI const float* glfwGetJoystickAxes(int joy, int* count); /*! @brief Returns the state of all buttons of the specified joystick. * * This function returns the state of all buttons of the specified joystick. + * Each element in the array is either `GLFW_PRESS` or `GLFW_RELEASE`. + * + * Querying a joystick slot with no device present is not an error, but will + * cause this function to return `NULL`. Call @ref glfwJoystickPresent to + * check device presence. * - * @param[in] joy The joystick to query. - * @param[out] count Where to store the size of the returned array. This is - * set to zero if an error occurred. - * @return An array of button states, or `NULL` if the joystick is not present. + * @param[in] joy The [joystick](@ref joysticks) to query. + * @param[out] count Where to store the number of button states in the returned + * array. This is set to zero if the joystick is not present or an error + * occurred. + * @return An array of button states, or `NULL` if the joystick is not present + * or an [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected, this function is called again for that joystick or the library + * is terminated. * - * @note The returned array is allocated and freed by GLFW. You should not - * free it yourself. + * @thread_safety This function must only be called from the main thread. * - * @note The returned array is valid only until the next call to @ref - * glfwGetJoystickButtons for that joystick. + * @sa @ref joystick_button + * + * @since Added in version 2.2. + * @glfw3 Changed to return a dynamic array. * * @ingroup input */ @@ -2040,58 +3603,110 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int joy, int* count); /*! @brief Returns the name of the specified joystick. * * This function returns the name, encoded as UTF-8, of the specified joystick. + * The returned string is allocated and freed by GLFW. You should not free it + * yourself. + * + * Querying a joystick slot with no device present is not an error, but will + * cause this function to return `NULL`. Call @ref glfwJoystickPresent to + * check device presence. * - * @param[in] joy The joystick to query. + * @param[in] joy The [joystick](@ref joysticks) to query. * @return The UTF-8 encoded name of the joystick, or `NULL` if the joystick - * is not present. + * is not present or an [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. * - * @note The returned string is allocated and freed by GLFW. You should not - * free it yourself. + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected, this function is called again for that joystick or the library + * is terminated. * - * @note The returned string is valid only until the next call to @ref - * glfwGetJoystickName for that joystick. + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref joystick_name + * + * @since Added in version 3.0. * * @ingroup input */ GLFWAPI const char* glfwGetJoystickName(int joy); +/*! @brief Sets the joystick configuration callback. + * + * This function sets the joystick configuration callback, or removes the + * currently set callback. This is called when a joystick is connected to or + * disconnected from the system. + * + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref joystick_event + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun); + /*! @brief Sets the clipboard to the specified string. * * This function sets the system clipboard to the specified, UTF-8 encoded - * string. The string is copied before returning, so you don't have to retain - * it afterwards. + * string. * * @param[in] window The window that will own the clipboard contents. * @param[in] string A UTF-8 encoded string. * - * @note This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The specified string is copied before this function + * returns. + * + * @thread_safety This function must only be called from the main thread. * + * @sa @ref clipboard * @sa glfwGetClipboardString * - * @ingroup clipboard + * @since Added in version 3.0. + * + * @ingroup input */ GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string); -/*! @brief Retrieves the contents of the clipboard as a string. +/*! @brief Returns the contents of the clipboard as a string. * * This function returns the contents of the system clipboard, if it contains - * or is convertible to a UTF-8 encoded string. + * or is convertible to a UTF-8 encoded string. If the clipboard is empty or + * if its contents cannot be converted, `NULL` is returned and a @ref + * GLFW_FORMAT_UNAVAILABLE error is generated. * * @param[in] window The window that will request the clipboard contents. * @return The contents of the clipboard as a UTF-8 encoded string, or `NULL` - * if an error occurred. + * if an [error](@ref error_handling) occurred. * - * @note This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @note The returned string is allocated and freed by GLFW. You should not - * free it yourself. + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the next call to @ref + * glfwGetClipboardString or @ref glfwSetClipboardString, or until the library + * is terminated. * - * @note The returned string is valid only until the next call to @ref - * glfwGetClipboardString or @ref glfwSetClipboardString. + * @thread_safety This function must only be called from the main thread. * + * @sa @ref clipboard * @sa glfwSetClipboardString * - * @ingroup clipboard + * @since Added in version 3.0. + * + * @ingroup input */ GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window); @@ -2101,93 +3716,192 @@ GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window); * been set using @ref glfwSetTime, the timer measures time elapsed since GLFW * was initialized. * - * @return The current value, in seconds, or zero if an error occurred. + * The resolution of the timer is system dependent, but is usually on the order + * of a few micro- or nanoseconds. It uses the highest-resolution monotonic + * time source on each supported platform. + * + * @return The current value, in seconds, or zero if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * - * @remarks This function may be called from secondary threads. + * @thread_safety This function may be called from any thread. Reading and + * writing of the internal timer offset is not atomic, so it needs to be + * externally synchronized with calls to @ref glfwSetTime. * - * @note The resolution of the timer is system dependent, but is usually on the - * order of a few micro- or nanoseconds. It uses the highest-resolution - * monotonic time source on each supported platform. + * @sa @ref time * - * @ingroup time + * @since Added in version 1.0. + * + * @ingroup input */ GLFWAPI double glfwGetTime(void); /*! @brief Sets the GLFW timer. * * This function sets the value of the GLFW timer. It then continues to count - * up from that value. + * up from that value. The value must be a positive finite number less than + * or equal to 18446744073.0, which is approximately 584.5 years. * * @param[in] time The new value, in seconds. * - * @note The resolution of the timer is system dependent, but is usually on the - * order of a few micro- or nanoseconds. It uses the highest-resolution - * monotonic time source on each supported platform. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_VALUE. + * + * @remark The upper limit of the timer is calculated as + * floor((264 - 1) / 109) and is due to implementations + * storing nanoseconds in 64 bits. The limit may be increased in the future. + * + * @thread_safety This function may be called from any thread. Reading and + * writing of the internal timer offset is not atomic, so it needs to be + * externally synchronized with calls to @ref glfwGetTime. + * + * @sa @ref time + * + * @since Added in version 2.2. * - * @ingroup time + * @ingroup input */ GLFWAPI void glfwSetTime(double time); +/*! @brief Returns the current value of the raw timer. + * + * This function returns the current value of the raw timer, measured in + * 1 / frequency seconds. To get the frequency, call @ref + * glfwGetTimerFrequency. + * + * @return The value of the timer, or zero if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref time + * @sa glfwGetTimerFrequency + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI uint64_t glfwGetTimerValue(void); + +/*! @brief Returns the frequency, in Hz, of the raw timer. + * + * This function returns the frequency, in Hz, of the raw timer. + * + * @return The frequency of the timer, in Hz, or zero if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref time + * @sa glfwGetTimerValue + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI uint64_t glfwGetTimerFrequency(void); + /*! @brief Makes the context of the specified window current for the calling * thread. * - * This function makes the context of the specified window current on the - * calling thread. A context can only be made current on a single thread at - * a time and each thread can have only a single current context at a time. + * This function makes the OpenGL or OpenGL ES context of the specified window + * current on the calling thread. A context can only be made current on + * a single thread at a time and each thread can have only a single current + * context at a time. + * + * By default, making a context non-current implicitly forces a pipeline flush. + * On machines that support `GL_KHR_context_flush_control`, you can control + * whether a context performs this flush by setting the + * [GLFW_CONTEXT_RELEASE_BEHAVIOR](@ref window_hints_ctx) window hint. + * + * The specified window must have an OpenGL or OpenGL ES context. Specifying + * a window without a context will generate a @ref GLFW_NO_WINDOW_CONTEXT + * error. * * @param[in] window The window whose context to make current, or `NULL` to * detach the current context. * - * @remarks This function may be called from secondary threads. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function may be called from any thread. * + * @sa @ref context_current * @sa glfwGetCurrentContext * + * @since Added in version 3.0. + * * @ingroup context */ GLFWAPI void glfwMakeContextCurrent(GLFWwindow* window); /*! @brief Returns the window whose context is current on the calling thread. * - * This function returns the window whose context is current on the calling - * thread. + * This function returns the window whose OpenGL or OpenGL ES context is + * current on the calling thread. * * @return The window whose context is current, or `NULL` if no window's * context is current. * - * @remarks This function may be called from secondary threads. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. * + * @sa @ref context_current * @sa glfwMakeContextCurrent * + * @since Added in version 3.0. + * * @ingroup context */ GLFWAPI GLFWwindow* glfwGetCurrentContext(void); /*! @brief Swaps the front and back buffers of the specified window. * - * This function swaps the front and back buffers of the specified window. If - * the swap interval is greater than zero, the GPU driver waits the specified - * number of screen updates before swapping the buffers. + * This function swaps the front and back buffers of the specified window when + * rendering with OpenGL or OpenGL ES. If the swap interval is greater than + * zero, the GPU driver waits the specified number of screen updates before + * swapping the buffers. + * + * The specified window must have an OpenGL or OpenGL ES context. Specifying + * a window without a context will generate a @ref GLFW_NO_WINDOW_CONTEXT + * error. + * + * This function does not apply to Vulkan. If you are rendering with Vulkan, + * see `vkQueuePresentKHR` instead. * * @param[in] window The window whose buffers to swap. * - * @remarks This function may be called from secondary threads. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR. * - * @par New in GLFW 3 - * This function no longer calls @ref glfwPollEvents. You need to call it or - * @ref glfwWaitEvents yourself. + * @remark __EGL:__ The context of the specified window must be current on the + * calling thread. * + * @thread_safety This function may be called from any thread. + * + * @sa @ref buffer_swap * @sa glfwSwapInterval * - * @ingroup context + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * @ingroup window */ GLFWAPI void glfwSwapBuffers(GLFWwindow* window); /*! @brief Sets the swap interval for the current context. * - * This function sets the swap interval for the current context, i.e. the - * number of screen updates to wait before swapping the buffers of a window and - * returning from @ref glfwSwapBuffers. This is sometimes called 'vertical - * synchronization', 'vertical retrace synchronization' or 'vsync'. + * This function sets the swap interval for the current OpenGL or OpenGL ES + * context, i.e. the number of screen updates to wait from the time @ref + * glfwSwapBuffers was called before swapping the buffers and returning. This + * is sometimes called _vertical synchronization_, _vertical retrace + * synchronization_ or just _vsync_. * * Contexts that support either of the `WGL_EXT_swap_control_tear` and * `GLX_EXT_swap_control_tear` extensions also accept negative swap intervals, @@ -2196,17 +3910,34 @@ GLFWAPI void glfwSwapBuffers(GLFWwindow* window); * glfwExtensionSupported. For more information about swap tearing, see the * extension specifications. * + * A context must be current on the calling thread. Calling this function + * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. + * + * This function does not apply to Vulkan. If you are rendering with Vulkan, + * see the present mode of your swapchain instead. + * * @param[in] interval The minimum number of screen updates to wait for * until the buffers are swapped by @ref glfwSwapBuffers. * - * @remarks This function may be called from secondary threads. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_CURRENT_CONTEXT and @ref GLFW_PLATFORM_ERROR. * - * @note Some GPU drivers do not honor the requested swap interval, either - * because of user settings that override the request or due to bugs in the - * driver. + * @remark This function is not called during context creation, leaving the + * swap interval set to whatever is the default on that platform. This is done + * because some swap interval extensions used by GLFW do not allow the swap + * interval to be reset to zero once it has been set to a non-zero value. * + * @remark Some GPU drivers do not honor the requested swap interval, either + * because of a user setting that overrides the application's request or due to + * bugs in the driver. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref buffer_swap * @sa glfwSwapBuffers * + * @since Added in version 1.0. + * * @ingroup context */ GLFWAPI void glfwSwapInterval(int interval); @@ -2214,20 +3945,37 @@ GLFWAPI void glfwSwapInterval(int interval); /*! @brief Returns whether the specified extension is available. * * This function returns whether the specified - * [OpenGL or context creation API extension](@ref context_glext) is supported - * by the current context. For example, on Windows both the OpenGL and WGL - * extension strings are checked. + * [API extension](@ref context_glext) is supported by the current OpenGL or + * OpenGL ES context. It searches both for client API extension and context + * creation API extensions. * - * @param[in] extension The ASCII encoded name of the extension. - * @return `GL_TRUE` if the extension is available, or `GL_FALSE` otherwise. - * - * @remarks This function may be called from secondary threads. + * A context must be current on the calling thread. Calling this function + * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. * - * @note As this functions searches one or more extension strings on each call, - * it is recommended that you cache its results if it's going to be used + * As this functions retrieves and searches one or more extension strings each + * call, it is recommended that you cache its results if it is going to be used * frequently. The extension strings will not change during the lifetime of * a context, so there is no danger in doing this. * + * This function does not apply to Vulkan. If you are using Vulkan, see @ref + * glfwGetRequiredInstanceExtensions, `vkEnumerateInstanceExtensionProperties` + * and `vkEnumerateDeviceExtensionProperties` instead. + * + * @param[in] extension The ASCII encoded name of the extension. + * @return `GLFW_TRUE` if the extension is available, or `GLFW_FALSE` + * otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_CURRENT_CONTEXT, @ref GLFW_INVALID_VALUE and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref context_glext + * @sa glfwGetProcAddress + * + * @since Added in version 1.0. + * * @ingroup context */ GLFWAPI int glfwExtensionSupported(const char* extension); @@ -2235,24 +3983,243 @@ GLFWAPI int glfwExtensionSupported(const char* extension); /*! @brief Returns the address of the specified function for the current * context. * - * This function returns the address of the specified - * [client API or extension function](@ref context_glext), if it is supported + * This function returns the address of the specified OpenGL or OpenGL ES + * [core or extension function](@ref context_glext), if it is supported * by the current context. * + * A context must be current on the calling thread. Calling this function + * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. + * + * This function does not apply to Vulkan. If you are rendering with Vulkan, + * see @ref glfwGetInstanceProcAddress, `vkGetInstanceProcAddr` and + * `vkGetDeviceProcAddr` instead. + * * @param[in] procname The ASCII encoded name of the function. - * @return The address of the function, or `NULL` if the function is - * unavailable. + * @return The address of the function, or `NULL` if an + * [error](@ref error_handling) occurred. * - * @remarks This function may be called from secondary threads. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_CURRENT_CONTEXT and @ref GLFW_PLATFORM_ERROR. * - * @note The addresses of these functions are not guaranteed to be the same for - * all contexts, especially if they use different client APIs or even different - * context creation hints. + * @remark The address of a given function is not guaranteed to be the same + * between contexts. + * + * @remark This function may return a non-`NULL` address despite the + * associated version or extension not being available. Always check the + * context version or extension string first. + * + * @pointer_lifetime The returned function pointer is valid until the context + * is destroyed or the library is terminated. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref context_glext + * @sa glfwExtensionSupported + * + * @since Added in version 1.0. * * @ingroup context */ GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname); +/*! @brief Returns whether the Vulkan loader has been found. + * + * This function returns whether the Vulkan loader has been found. This check + * is performed by @ref glfwInit. + * + * The availability of a Vulkan loader does not by itself guarantee that window + * surface creation or even device creation is possible. Call @ref + * glfwGetRequiredInstanceExtensions to check whether the extensions necessary + * for Vulkan surface creation are available and @ref + * glfwGetPhysicalDevicePresentationSupport to check whether a queue family of + * a physical device supports image presentation. + * + * @return `GLFW_TRUE` if Vulkan is available, or `GLFW_FALSE` otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref vulkan_support + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI int glfwVulkanSupported(void); + +/*! @brief Returns the Vulkan instance extensions required by GLFW. + * + * This function returns an array of names of Vulkan instance extensions required + * by GLFW for creating Vulkan surfaces for GLFW windows. If successful, the + * list will always contains `VK_KHR_surface`, so if you don't require any + * additional extensions you can pass this list directly to the + * `VkInstanceCreateInfo` struct. + * + * If Vulkan is not available on the machine, this function returns `NULL` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported + * to check whether Vulkan is available. + * + * If Vulkan is available but no set of extensions allowing window surface + * creation was found, this function returns `NULL`. You may still use Vulkan + * for off-screen rendering and compute work. + * + * @param[out] count Where to store the number of extensions in the returned + * array. This is set to zero if an error occurred. + * @return An array of ASCII encoded extension names, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_API_UNAVAILABLE. + * + * @remarks Additional extensions may be required by future versions of GLFW. + * You should check if any extensions you wish to enable are already in the + * returned array, as it is an error to specify an extension more than once in + * the `VkInstanceCreateInfo` struct. + * + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is guaranteed to be valid only until the + * library is terminated. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref vulkan_ext + * @sa glfwCreateWindowSurface + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count); + +#if defined(VK_VERSION_1_0) + +/*! @brief Returns the address of the specified Vulkan instance function. + * + * This function returns the address of the specified Vulkan core or extension + * function for the specified instance. If instance is set to `NULL` it can + * return any function exported from the Vulkan loader, including at least the + * following functions: + * + * - `vkEnumerateInstanceExtensionProperties` + * - `vkEnumerateInstanceLayerProperties` + * - `vkCreateInstance` + * - `vkGetInstanceProcAddr` + * + * If Vulkan is not available on the machine, this function returns `NULL` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported + * to check whether Vulkan is available. + * + * This function is equivalent to calling `vkGetInstanceProcAddr` with + * a platform-specific query of the Vulkan loader as a fallback. + * + * @param[in] instance The Vulkan instance to query, or `NULL` to retrieve + * functions related to instance creation. + * @param[in] procname The ASCII encoded name of the function. + * @return The address of the function, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_API_UNAVAILABLE. + * + * @pointer_lifetime The returned function pointer is valid until the library + * is terminated. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref vulkan_proc + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance, const char* procname); + +/*! @brief Returns whether the specified queue family can present images. + * + * This function returns whether the specified queue family of the specified + * physical device supports presentation to the platform GLFW was built for. + * + * If Vulkan or the required window surface creation instance extensions are + * not available on the machine, or if the specified instance was not created + * with the required extensions, this function returns `GLFW_FALSE` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported + * to check whether Vulkan is available and @ref + * glfwGetRequiredInstanceExtensions to check what instance extensions are + * required. + * + * @param[in] instance The instance that the physical device belongs to. + * @param[in] device The physical device that the queue family belongs to. + * @param[in] queuefamily The index of the queue family to query. + * @return `GLFW_TRUE` if the queue family supports presentation, or + * `GLFW_FALSE` otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function may be called from any thread. For + * synchronization details of Vulkan objects, see the Vulkan specification. + * + * @sa @ref vulkan_present + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily); + +/*! @brief Creates a Vulkan surface for the specified window. + * + * This function creates a Vulkan surface for the specified window. + * + * If the Vulkan loader was not found at initialization, this function returns + * `VK_ERROR_INITIALIZATION_FAILED` and generates a @ref GLFW_API_UNAVAILABLE + * error. Call @ref glfwVulkanSupported to check whether the Vulkan loader was + * found. + * + * If the required window surface creation instance extensions are not + * available or if the specified instance was not created with these extensions + * enabled, this function returns `VK_ERROR_EXTENSION_NOT_PRESENT` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref + * glfwGetRequiredInstanceExtensions to check what instance extensions are + * required. + * + * The window surface must be destroyed before the specified Vulkan instance. + * It is the responsibility of the caller to destroy the window surface. GLFW + * does not destroy it for you. Call `vkDestroySurfaceKHR` to destroy the + * surface. + * + * @param[in] instance The Vulkan instance to create the surface in. + * @param[in] window The window to create the surface for. + * @param[in] allocator The allocator to use, or `NULL` to use the default + * allocator. + * @param[out] surface Where to store the handle of the surface. This is set + * to `VK_NULL_HANDLE` if an error occurred. + * @return `VK_SUCCESS` if successful, or a Vulkan error code if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR. + * + * @remarks If an error occurs before the creation call is made, GLFW returns + * the Vulkan error code most appropriate for the error. Appropriate use of + * @ref glfwVulkanSupported and @ref glfwGetRequiredInstanceExtensions should + * eliminate almost all occurrences of these errors. + * + * @thread_safety This function may be called from any thread. For + * synchronization details of Vulkan objects, see the Vulkan specification. + * + * @sa @ref vulkan_surface + * @sa glfwGetRequiredInstanceExtensions + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); + +#endif /*VK_VERSION_1_0*/ + /************************************************************************* * Global definition cleanup diff --git a/tests/glfw3.c b/tests/glfw3.c index 61d3dd3bed346..71a8332e135e3 100644 --- a/tests/glfw3.c +++ b/tests/glfw3.c @@ -30,14 +30,14 @@ int main() glfwSetErrorCallback(errorcb); assert(glfwInit() == GL_TRUE); - assert(!strcmp(glfwGetVersionString(), "3.0.0 JS WebGL Emscripten")); + assert(!strcmp(glfwGetVersionString(), "3.2.1 JS WebGL Emscripten")); { int major, minor, rev; glfwGetVersion(&major, &minor, &rev); assert(major == 3); - assert(minor == 0); - assert(rev == 0); + assert(minor == 2); + assert(rev == 1); } { From b019ab87ef671b5cd6b2221b7fe70dc3eac296ed Mon Sep 17 00:00:00 2001 From: Ryan Speets Date: Sat, 29 Apr 2017 19:58:07 -0400 Subject: [PATCH 18/22] Initialize numGamepadsConnected Fixes #5169 (#5170) * Initialize numGamepadsConnected Fixes #5169 Fix for Chrome issue https://bugs.chromium.org/p/chromium/issues/detail?id=502824 * Update AUTHORS * Add comment about Chrome Gamepad bug --- AUTHORS | 1 + src/library_html5.js | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/AUTHORS b/AUTHORS index 5ad95c9d114c4..b38c95a91b300 100644 --- a/AUTHORS +++ b/AUTHORS @@ -289,4 +289,5 @@ a license to everyone to use it as detailed in LICENSE.) * Jean-François Geyelin * Matthew Collins * Satoshi N. M +* Ryan Speets * Fumiya Chiba diff --git a/src/library_html5.js b/src/library_html5.js index ed16ba167b338..cf6bb6de9d500 100644 --- a/src/library_html5.js +++ b/src/library_html5.js @@ -39,6 +39,13 @@ var LibraryJSEvents = { if (typeof window !== 'undefined') { window.addEventListener("gamepadconnected", function() { ++JSEvents.numGamepadsConnected; }); window.addEventListener("gamepaddisconnected", function() { --JSEvents.numGamepadsConnected; }); + + // Chromium does not fire the gamepadconnected event on reload, so we need to get the number of gamepads here as a workaround. + // See https://bugs.chromium.org/p/chromium/issues/detail?id=502824 + var firstState = navigator.getGamepads ? navigator.getGamepads() : (navigator.webkitGetGamepads ? navigator.webkitGetGamepads() : null); + if (firstState) { + JSEvents.numGamepadsConnected = firstState.length; + } } }, From 26044dc39af4a1f4eacbf027fe598faf80fee2ff Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sun, 30 Apr 2017 19:36:37 -0400 Subject: [PATCH 19/22] Fixed an incorrect line of debug output. --- src/library_openal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library_openal.js b/src/library_openal.js index 6d71f723f5b20..32ad2a0433fa9 100644 --- a/src/library_openal.js +++ b/src/library_openal.js @@ -1374,7 +1374,7 @@ var LibraryOpenAL = { alListener3f: function(param, v1, v2, v3) { if (!AL.currentContext) { #if OPENAL_DEBUG - console.error("alListenerfv called without a valid context"); + console.error("alListener3f called without a valid context"); #endif return; } From 33fed3c647f5dc41c47e95ddd034c3df0a9d1bf8 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Mon, 1 May 2017 14:28:28 -0400 Subject: [PATCH 20/22] Added Ryan C. Gordon to AUTHORS --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 0441963dded57..9d282a91f8278 100644 --- a/AUTHORS +++ b/AUTHORS @@ -269,3 +269,4 @@ a license to everyone to use it as detailed in LICENSE.) * Vilibald Wanča * Alex Hixon * Vladimir Davidovich +* Ryan C. Gordon From c55636b9c142c2f4e7b9d68d374bd421d46676ee Mon Sep 17 00:00:00 2001 From: CHIBA Fumiya Date: Tue, 2 May 2017 06:11:29 +0900 Subject: [PATCH 21/22] Ignore "--tracing" on configure (#5184) --- emcc.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/emcc.py b/emcc.py index 1dee3023bbde3..eb6d7198f07f6 100755 --- a/emcc.py +++ b/emcc.py @@ -262,6 +262,8 @@ def filter_emscripten_options(argv): continue if not use_js and el == '-s' and is_minus_s_for_emcc(argv, idx): # skip -s X=Y if not using js for configure skip_next = True + if not use_js and el == '--tracing': + pass else: yield el idx += 1 From e75df6a4a881a1f55040d748f0fc4f9b10275d46 Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Mon, 1 May 2017 15:13:46 -0700 Subject: [PATCH 22/22] 1.37.11 --- emscripten-version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emscripten-version.txt b/emscripten-version.txt index 2a788d314baec..35fa8c09f1de7 100644 --- a/emscripten-version.txt +++ b/emscripten-version.txt @@ -1 +1 @@ -"1.37.10" +"1.37.11"