Compare commits

..

1404 Commits

Author SHA1 Message Date
Kovid Goyal
62db7639a8 version 0.8.3 2018-03-29 09:56:44 +05:30
Kovid Goyal
80f3fe6e9f ... 2018-03-29 00:05:37 +05:30
Kovid Goyal
9ba2c4b397 Update glfw from upstream 2018-03-28 19:57:01 +05:30
Kovid Goyal
bfa53d4b45 Update glfw from upstream
Includes proper fix for Wayland key repeat
2018-03-28 15:26:56 +05:30
Kovid Goyal
69f3ceb903 Merge glfw upstream changes to build on Wayland on FreeBSD 2018-03-28 09:47:16 +05:30
Kovid Goyal
d0f839bbd8 Fix audible bell not working under Wayland 2018-03-27 19:45:19 +05:30
Kovid Goyal
48538c0e25 Update bundled glfw 2018-03-27 15:07:25 +05:30
Kovid Goyal
02ab22f08c Update CHANGELOG 2018-03-27 12:15:25 +05:30
Kovid Goyal
b3b216a6dc ... 2018-03-27 12:09:18 +05:30
Kovid Goyal
431564c8bc Linux: When calculating cell widths use the actual rendered bitmap width in addition to the horizontal advance reported by FreeType.
The horizontal advance is insufficient for some fonts at some point
sizes. So although rendering the characters is slower, we do it
to ensure cell width is correct. Fixes #352
2018-03-27 12:04:38 +05:30
Kovid Goyal
57f1bbb71a Make cwd check more robust
Apparently getcwd() raises an exception on macOS when the cwd does not
exist.
2018-03-27 10:54:49 +05:30
Kovid Goyal
faac8649e4 Fix a regression that broke visual bell and invert screen colors escape code. Fixes #419 2018-03-27 10:46:26 +05:30
Kovid Goyal
1e6a41186f Move check for NULL boss into call_boss()
Negligible perf impact and makes it safe to use in different contexts
2018-03-27 09:56:29 +05:30
Kovid Goyal
eddee67130 Fix error when testing update_selection because not boss is defined 2018-03-27 09:54:14 +05:30
Kovid Goyal
9b834014e9 Merge branch 'zero-length-title' of https://github.com/jamessan/kitty 2018-03-27 09:41:33 +05:30
James McCoy
a467e79144 Stop setting title to ";" when 0-length OSC 2 is received
Various programs send a 0-length title if no title is configured (e.g.,
(n)vim with 'title' unset, or mutt without ts_enabled).  When this
happens, kitty is mis-parsing the data and setting the title to ";".
2018-03-26 21:30:45 -04:00
Kovid Goyal
90cc785b55 Allow double-click and triple-click + drag to extend selections word at a time or line at a time. Fixes #400 2018-03-26 16:48:28 +05:30
Kovid Goyal
09710425ab Move rectangle_select onto the selection object 2018-03-26 12:37:36 +05:30
Kovid Goyal
dd36727adf Show macOs version for --debug-config 2018-03-25 12:47:47 +05:30
Kovid Goyal
47b665a624 Prettyify --debug-config output 2018-03-25 12:36:27 +05:30
Kovid Goyal
7011329761 Add a --debug-config option to provide diagnostic info about the system and kitty 2018-03-25 12:30:56 +05:30
Kovid Goyal
ea24c23fde Allow specifying a system wide kitty config file
The system config is merged with any user specific config files, with
options in the user specific config files having higher priority.

Also follow the full XDG spec for finding config files, including
XDG_CONFIG_DIRS.
2018-03-25 11:47:11 +05:30
Kovid Goyal
be8f2b8106 Create a shortcut to set the tab title
No longer need to use remote control just to change tab titles.
2018-03-25 09:55:02 +05:30
Kovid Goyal
71db024a3b Add history based completion to the ask kitten 2018-03-24 11:49:34 +05:30
Kovid Goyal
3790af6897 Basic ask kitten 2018-03-23 18:03:43 +05:30
Kovid Goyal
dc6ef63ddd Merge branch 'oS' of https://github.com/jubalh/kitty 2018-03-23 15:33:40 +05:30
Michael Vetter
ef762f7a2b Add link to openSUSE package 2018-03-23 10:45:42 +01:00
Kovid Goyal
4ed646e062 Merge branch 'tic2' of https://github.com/jubalh/kitty 2018-03-21 21:17:46 +05:30
Michael Vetter
afbd843388 Mention tic as dependency 2018-03-21 16:42:44 +01:00
Kovid Goyal
18c3598ef2 Merge branch 'desktop' of https://github.com/jubalh/kitty 2018-03-21 20:43:50 +05:30
Michael Vetter
1c2623e609 Have more detailed desktop file category
Let's use the 'TerminalEmulator' category according to the spec:
https://specifications.freedesktop.org/menu-spec/menu-spec-1.0.html
2018-03-21 11:28:57 +01:00
Kovid Goyal
e232863028 Also recognize unicode aliases for macOS modifiers 2018-03-20 15:10:29 +05:30
Kovid Goyal
a89309153d Merge branch 'patch-1' of https://github.com/sle-odoo/kitty 2018-03-18 17:59:27 +05:30
Simon Lejeune
fee7c8e573 update dependencies to run make app
while imagemagick is defined as an optional dependency in the installation section, its presence is indeed mandatory to successfully run `make app` as seen at https://github.com/kovidgoyal/kitty/blob/master/logo/make.py#L27
2018-03-18 10:56:40 +01:00
Kovid Goyal
1a52127c55 version 0.8.2 2018-03-17 17:45:57 +05:30
Kovid Goyal
4920431c3a Update CHANGELOG 2018-03-17 17:40:41 +05:30
Kovid Goyal
773f26b61d Fix screen not being refreshed immediately after moving a window. Fixes #397 2018-03-16 22:00:57 +05:30
Kovid Goyal
16e77d7329 Replace use of PyObject_Str in a couple more places 2018-03-16 21:26:46 +05:30
Kovid Goyal
2cec0908a5 Fix a segfault when getting the contents of the scrollback buffer as text
Fixes #398
2018-03-16 21:10:48 +05:30
Kovid Goyal
b3ef62c188 Merge branch 'i386-fixes' of https://github.com/oleastre/kitty 2018-03-16 20:42:57 +05:30
Olivier Samyn
3385f6fe67 Avoid comparison between signed and unsigned compilation error (32bit) 2018-03-16 09:31:37 +01:00
Kovid Goyal
0170bf636b ... 2018-03-15 20:58:26 +05:30
Kovid Goyal
b2561fd61e Add a facility to specify command line arguments when running kitty from the GUI on macOS
Fixes #395
2018-03-15 20:57:08 +05:30
Kovid Goyal
64b48945d4 Add a focus-tab remote command
Fixes #394
2018-03-15 17:41:49 +05:30
Kovid Goyal
bbfd463357 Dont show a useless traceback when failing to match in a remote command
Fixes #393
2018-03-15 15:45:12 +05:30
Kovid Goyal
2179dab8ed Re-organize kitty.conf into sections
Sections are de-limited by vim folds
2018-03-15 13:07:02 +05:30
Kovid Goyal
801ead7f7f Add ntoe to readme about right click to extend selection 2018-03-15 12:20:46 +05:30
Kovid Goyal
9e4834d58b Right click should only extend selection if there is an existing selection 2018-03-15 12:19:45 +05:30
Kovid Goyal
f38e089de0 Merge branch 'extend-selection' of https://github.com/vsajko/kitty 2018-03-15 12:07:23 +05:30
Kovid Goyal
b252504306 ... 2018-03-15 11:31:37 +05:30
Kovid Goyal
81bcdaf48a Dont show [options] if there are no options in usage message 2018-03-15 11:30:31 +05:30
Kovid Goyal
44f654ff86 Cleanup remote_control.py 2018-03-15 11:26:22 +05:30
Kovid Goyal
84cfa9382f Add argspecs for the remote control command help text 2018-03-15 11:21:13 +05:30
Kovid Goyal
c6da374aa9 Add a configurable keyboard shortcut and remote command to set the font size to a specific value
Fixes #388
2018-03-15 11:15:35 +05:30
Vedran Sajko
d9fe0b2540 Extend selection with right click 2018-03-15 00:09:33 +01:00
Kovid Goyal
5a905dfe7f Add kitty.app to .gitignore
Also have make clean clean linux-package and kitty.app when running
manually.
2018-03-14 12:10:15 +05:30
Kovid Goyal
09b6d6e62b README cleanups 2018-03-14 08:01:10 +05:30
Kovid Goyal
6aa26cf75f Improve the wording for close_on_child_death option 2018-03-13 09:12:06 +05:30
Kovid Goyal
bae8915881 Add an option to have kitty close the window when the main processes running in it exits, even if there are still background processes writing to that terminal.
Merge branch 'master' of https://github.com/josswright/kitty
2018-03-13 09:08:45 +05:30
Kovid Goyal
9c46de319e MacOS: Fix restoring of window size not correct on Retina screens
Fixes #382
2018-03-13 08:19:15 +05:30
Joss Wright
994eecadb7 Adds close_on_child_death option for disowned processes. 2018-03-12 21:02:37 +00:00
Kovid Goyal
f7f9ceec34 Consolidate signal handling
Move the signal handler for SIGCHLD into child-monitor.c
Makes for cleaner code.
2018-03-12 21:53:02 +05:30
Kovid Goyal
527255e3a1 Fix compilation with gcc 8
Apparently some nitwit Linux distros have made an unreleased compiler
their default compiler. Fixes #376

Fixes various new warnings that GCC 8 issues
2018-03-12 10:38:12 +05:30
Kovid Goyal
0333da991d ... 2018-03-12 08:11:43 +05:30
Kovid Goyal
2bf8e1b1a3 Allow the name of the lib directory in linux-package to be configurable. Fixes #372 2018-03-12 08:10:53 +05:30
Kovid Goyal
ffc717717c Oops 2018-03-12 07:53:31 +05:30
Kovid Goyal
2c8414db5d Be a bit more specific 2018-03-12 07:52:08 +05:30
Kovid Goyal
32473d7dc7 make clean fallsback to manual cleaning when not in a git checkout
Fixes #379
2018-03-12 07:50:54 +05:30
Kovid Goyal
079f10eebd ... 2018-03-11 22:31:19 +05:30
Kovid Goyal
ae1f305a81 Add kittens to the LOC script 2018-03-11 12:03:23 +05:30
Kovid Goyal
0b1f5209d5 Use CFLAGS and LDFLAGS env vars when building the launcher as well
Fixes #374
2018-03-11 08:12:17 +05:30
Kovid Goyal
fc9980903d Make layout names case-insensitive for enabled_layouts in sessions as well 2018-03-10 23:42:06 +05:30
Kovid Goyal
ad87131926 A bit of documentation for goto_layout 2018-03-10 23:38:18 +05:30
Kovid Goyal
4dfe1b664f Add configurable keyboard shortcuts to switch to a specific layout
Fixes #369
2018-03-10 23:34:47 +05:30
Kovid Goyal
d7b2ac97b5 ... 2018-03-09 21:04:20 +05:30
Kovid Goyal
fd9dac4ca4 Add a small delay when opening the editor with the config file to workaround bugs in vim that cause it to ignore SIGWINCH if it happens early during startup. 2018-03-09 21:03:42 +05:30
Kovid Goyal
8ca9348b07 ... 2018-03-09 18:10:17 +05:30
Kovid Goyal
5cc18fdb4b ... 2018-03-09 18:02:06 +05:30
Kovid Goyal
51b6b325b9 Add a keyboard shortcut to edit the kitty config file easily
Fixes #366
2018-03-09 17:57:09 +05:30
Kovid Goyal
b3cc6f3802 ... 2018-03-09 17:49:31 +05:30
Kovid Goyal
1295094715 README cleanups 2018-03-09 11:00:50 +05:30
Kovid Goyal
af85f58e3d version 0.8.1 2018-03-09 09:21:50 +05:30
Kovid Goyal
3b34821c86 Report unhandled exceptions during loop initialization in the unicode input kitten as well 2018-03-08 13:57:13 +05:30
Kovid Goyal
eaea0b16b5 Fix URL hints not working on macOS
Fixes #363
2018-03-08 13:38:16 +05:30
Kovid Goyal
964ffadc8e DRYer 2018-03-08 13:37:56 +05:30
Kovid Goyal
1b84064e5f ... 2018-03-08 13:01:35 +05:30
Kovid Goyal
dd128a99ac Report unahndled exceptions when starting loop in URL hints kitten 2018-03-08 12:58:54 +05:30
Kovid Goyal
bc829a9712 Use a dedicated static variable for tracking window system initialization 2018-03-06 13:55:06 +05:30
Kovid Goyal
3459c55ebf Add section on reporting bugs to CONTRIBUTING 2018-03-05 21:03:01 +05:30
Kovid Goyal
a631d950e1 Add a guide to contributing 2018-03-05 20:57:57 +05:30
Kovid Goyal
f35e2d76ad Add a note about using --login on macOS when changing the default shell 2018-03-05 14:54:20 +05:30
Kovid Goyal
8db838da9f macOS: Fix shell not starting in login mode on some computers. Fixes #247 2018-03-05 13:30:09 +05:30
Kovid Goyal
7254a880dc Guard against print failure 2018-03-05 13:29:26 +05:30
Kovid Goyal
a0df5b970b Report unhandled exceptions via log_error() as well 2018-03-05 10:28:33 +05:30
Kovid Goyal
54ed08c24e Ensure the extra glyphs array is always re-initialized 2018-03-04 23:36:39 +05:30
Kovid Goyal
97e1ecabdc Render private use unicode characters that are followed by a space as two cell ligatures. Fixes #357 2018-03-04 22:58:24 +05:30
Kovid Goyal
e716f6d35e Replace deprecated ASL with os_log on macOS 2018-03-04 12:28:06 +05:30
Kovid Goyal
c7506496da Unify error logging between python and C 2018-03-04 11:55:47 +05:30
Kovid Goyal
1e3d3df9b8 Remove unused code 2018-03-04 10:59:12 +05:30
Kovid Goyal
ed75ad0d41 Log a timestamp as well when printing error messages from python 2018-03-04 10:44:28 +05:30
Kovid Goyal
fd6159c0b4 Redirect stderr/stdout to console.app when launched via launchd on macOS 2018-03-04 10:17:43 +05:30
Kovid Goyal
976c322b83 Print a couple of errors to stderr instead of stdout 2018-03-04 08:58:36 +05:30
Kovid Goyal
28c1935800 Fix Unicode emoji presentation variant selector causing new fallback font to always be loaded 2018-03-03 21:32:43 +05:30
Kovid Goyal
1edf1524f8 Update bundled glfw 2018-03-03 11:21:09 +05:30
Kovid Goyal
0dfe101c0f brew's python3 handling seems to have changed 2018-03-03 11:09:07 +05:30
Kovid Goyal
a571821f73 Fix compilation on Travis (I hope) 2018-03-03 10:56:07 +05:30
Kovid Goyal
f8e6f87984 Dont use MSG_NOSIGNAL on Apple 2018-03-03 10:51:29 +05:30
Kovid Goyal
c7338bca6f Document how to control kitty from programs not running in a kitty window 2018-03-03 10:38:25 +05:30
Kovid Goyal
15f07f57bf Finish remote control via socket implementation 2018-03-03 10:32:49 +05:30
Kovid Goyal
ec989a45b5 ... 2018-03-03 08:55:05 +05:30
Kovid Goyal
e8286c50b2 Implement sending responses to peers 2018-03-02 12:35:32 +05:30
Kovid Goyal
bfbbe3db14 mutex remove_poll_fd()
It modifies talk_data.fds which can also be modified from the main
thread when adding a writer.
2018-03-02 11:13:47 +05:30
Kovid Goyal
6214a87522 Correct error handling for pthread_join 2018-03-02 11:08:11 +05:30
Kovid Goyal
743ff719c8 join the talk thread on exit
Also shutdown reading on the control socket after message received.
2018-03-02 11:02:18 +05:30
Kovid Goyal
b491eacb9c Ensure the moitor threads are shut down on exit 2018-03-02 10:32:12 +05:30
Kovid Goyal
5bfc89e13f Implement listening on the --listen-on socket 2018-03-02 10:26:19 +05:30
Kovid Goyal
52d2b7b09e Implement --listen-on option 2018-03-02 09:08:58 +05:30
Kovid Goyal
19e59d9575 Start refactoring peer message handling to allow multiple listening sockets and responses 2018-03-02 09:08:58 +05:30
Kovid Goyal
6fe4baf1de Move pthread includes into separate header 2018-03-02 09:08:58 +05:30
Kovid Goyal
bc21ec7551 Have kitty @ use /dev/tty instead of stdout/stdin
Allows redirecting those streams, while still being able to send
messages. Downside is that if user runs it outside kitty there wont
be any useful error message.
2018-03-02 09:08:58 +05:30
Kovid Goyal
aad4a1fd6a Dont fail for non-UTF-8 encoded config files, simply replace the undecodeable chars instead 2018-03-02 08:49:27 +05:30
Kovid Goyal
721595ef04 Ensure config file is always opened with UTF-8 2018-03-02 08:47:13 +05:30
Kovid Goyal
139838c717 Option to print debug information about font fallback 2018-02-28 21:43:40 +05:30
Kovid Goyal
c93238d8c9 Some documentation for the unicode input kitten 2018-02-28 00:29:11 +05:30
Kovid Goyal
5ee1fbe07d Copy the launcher script into linux-package
The launcher script is mostly useless on linux, but is needed
when using kitty.app built from source and might be useful on linux as
well, if running kitty without putting it on PATH.
2018-02-28 00:25:57 +05:30
Kovid Goyal
ee1287211d Typo in makefile app target 2018-02-27 21:06:42 +05:30
Kovid Goyal
94e8be6b1c ... 2018-02-27 20:29:08 +05:30
Kovid Goyal
053ba7f082 Nicer error message when user tries to run logo/make.py with missing tools 2018-02-27 19:56:52 +05:30
Kovid Goyal
e8f3f00792 Handle cols being zero 2018-02-27 18:48:48 +05:30
Kovid Goyal
740a89b77f Treat Ctrl+Alt+letter as Esc,Ctrl+letter
Follows the behavior of some other terminals and is better than
generating nothing, since apparently there are some terminal programs
that use these keys. Fixes #345
2018-02-27 08:46:09 +05:30
Kovid Goyal
1fe936dbbc Fix off by one when restoring cursor position after resize. Fixes #344 2018-02-25 09:15:48 +05:30
Kovid Goyal
11e85ac703 Swapped unicode input name and hex mode prompt strings 2018-02-24 14:51:49 +05:30
Kovid Goyal
4cb99be8e6 version 0.8.0 2018-02-24 11:11:56 +05:30
Kovid Goyal
8cf9fd3cdb ... 2018-02-23 09:38:07 +05:30
Kovid Goyal
b22950bb0a More work on README 2018-02-23 09:36:46 +05:30
Kovid Goyal
f87d62571b Add links to relevant parts of the README in the major features list 2018-02-23 09:13:20 +05:30
Kovid Goyal
42afc56b65 Update CHANGELOG with entry for macos_titlebar_color
Fixes #341
2018-02-22 21:21:33 +05:30
Splinter Suidman
10c3c7c41f Implement setting title bar color. 2018-02-22 21:19:55 +05:30
Kovid Goyal
e236539e3a Option for changing macOS titlebar color
Note that the actual implementation is still needed, this is just the
option definition/parsing code.
2018-02-22 15:07:24 +05:30
Kovid Goyal
1fc605cbc0 Move needs_special_handling definition into keys.c 2018-02-22 14:37:51 +05:30
Kovid Goyal
1e4963e727 Revert change to make alt+bs emit werase
Most linux terminals emit ESC+BS instead. And iTerm2 in Esc+ mode also
emits this. So go with the majority for greatest ecosystem
compatibility. Fixes #264
2018-02-22 13:51:14 +05:30
Kovid Goyal
95384d437a Use the nice array based interface for fcntl.ioctl 2018-02-20 17:01:14 +05:30
Kovid Goyal
e44910212c Sample code to use TIOCGWINSZ in python 2018-02-20 16:47:06 +05:30
Kovid Goyal
36b8802f43 Add a link to the graphics protocol page in the README 2018-02-20 16:32:57 +05:30
Kovid Goyal
a6b0554edc Merge branch 'master' of https://github.com/Polynomial-C/kitty 2018-02-20 15:42:23 +05:30
Lars Wendler
c1df5eac57 Added Gentoo to the list of Linux packagers. 2018-02-20 11:09:43 +01:00
Kovid Goyal
68bf1be8d0 render on cursor shape change as well 2018-02-20 11:54:35 +05:30
Kovid Goyal
d5edea3c7f render on cursor position change as well 2018-02-20 11:27:39 +05:30
Kovid Goyal
eb580f5ead Update CHANGELOG for padding color 2018-02-20 10:10:28 +05:30
Kovid Goyal
c99588082b Fix incorrect bottom blank rects in vertical and tall layouts 2018-02-20 10:06:37 +05:30
Kovid Goyal
96d241e9f3 Fix enabled_layouts in session files not being respected 2018-02-20 10:01:41 +05:30
Kovid Goyal
8f423c6d8f Fix padding color not tracking active window bg color 2018-02-20 09:52:19 +05:30
Kovid Goyal
f25ecedcab Always set the padding color to current window background 2018-02-20 09:43:59 +05:30
Kovid Goyal
2913c1aedc Change the color of the padding and margins to match the current background color of the window, when only a single window is visible.
Fixes #323
2018-02-20 09:43:49 +05:30
Kovid Goyal
5a15f7e8ad Sync to monitor refreshes by default
Prevents tearing while scrolling. See #318

Reduce draw calls while processing mouse move events to make latency
while selecting with the mouse acceptable. Also add a config option to
turn off monitor syncing, so people with keyboard repeat rates higher
than their monitor's refresh rate can use it.
2018-02-20 09:38:00 +05:30
Kovid Goyal
e6cb64baa5 Revert "Enable syncing of redraws to monitor refresh rate"
This reverts commit 6a51096304.
Turns out that dynamically changing the swap interval causes bad flicker
when rendering on X11 in a fullscreen window (or more generally, when
only a single X11 window is visible).
2018-02-20 08:32:33 +05:30
Kovid Goyal
537023ef5a Fix simple_render_screen() broken by multiple OSwindow draw calls optimization 2018-02-20 05:52:32 +05:30
Kovid Goyal
70125e0de5 Only build asan-launcher if --sanitize is given
Fixes #328
2018-02-16 08:56:30 +05:30
Kovid Goyal
8c5646b81b Merge branch 'build-package-fix' of https://github.com/13k/kitty 2018-02-16 08:22:30 +05:30
Kiyoshi '13k' Murata
bd741365cb Fix packaging trying to modify unrelated files
`package()` method in `setup.py` tries to compile and chmod all files
under the directory given by `--prefix PREFIX`.

If PREFIX is a directory containing other distributions (like
`/usr/local` or `$HOME/.local`), then it would try to compile - using
possibly the wrong python version - and chmod all files within PREFIX.
2018-02-15 19:46:51 -02:00
Kovid Goyal
efd9843920 Update CHANGELOG 2018-02-15 17:42:32 +05:30
Kovid Goyal
0bb8ec61e5 Fix regression caused by overlay window support code
Closing a window would not update the window layout, depending on the
position of the window in the current layout.
2018-02-15 09:16:00 +05:30
Kovid Goyal
6a51096304 Enable syncing of redraws to monitor refresh rate
Now, when large changes, such as scrolling occur, the OpenGL back buffer
swapping is synchronized to the monitor refresh rate (if supported by
the OS). This eliminates tearing artifacts when scrolling the screen fast.
Fixes #318
2018-02-14 20:59:58 +05:30
Kovid Goyal
807c8f9005 Do not send history buf in alternate screen mode 2018-02-14 20:46:12 +05:30
Kovid Goyal
9c21610215 Use a single generic function to get text and ANSI representations of all buffers 2018-02-14 20:38:53 +05:30
Kovid Goyal
97b4256ba4 Remove unused code 2018-02-14 18:50:52 +05:30
Kovid Goyal
e4b643fdaf Show a nice message when no URLs are found 2018-02-14 18:36:57 +05:30
Kovid Goyal
0bda7b3679 When running kittens respect current screen scroll 2018-02-14 18:35:32 +05:30
Kovid Goyal
51e3e9997c Allow clicking URLs via keybaord hints by pressing ctrl+shift+e 2018-02-14 17:18:57 +05:30
Kovid Goyal
9f52d427e5 http->https in readme 2018-02-14 17:08:09 +05:30
Kovid Goyal
ad706f9924 Make the list of URL prefixes configurable 2018-02-14 12:48:44 +05:30
Kovid Goyal
57cf789c75 Finish up the URL hints kitten 2018-02-14 12:34:01 +05:30
Kovid Goyal
62174fdbcc DRYer 2018-02-14 11:19:58 +05:30
Kovid Goyal
dff7ddea39 Make the default intense black a little lighter
Brings it closer to the color definitions at:
https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit
2018-02-14 11:17:07 +05:30
Kovid Goyal
0c3257b6b9 Start work on url hints kitten 2018-02-14 11:01:17 +05:30
Kovid Goyal
4bbf5c0bc9 Allow choosing a match by index in the search by name panel as well 2018-02-13 11:25:45 +05:30
Kovid Goyal
b0820f6e13 Use . instead of r for the index char 2018-02-13 11:10:35 +05:30
Kovid Goyal
b0f5d8dfdc Fix table row generation for non-name unicode input panels 2018-02-13 10:50:06 +05:30
Kovid Goyal
67e0d3723a Implement favorites for unicode input 2018-02-13 10:33:55 +05:30
Kovid Goyal
a36f4a4670 Add a Emoji panel to the unicode input kitten 2018-02-13 09:06:39 +05:30
Kovid Goyal
dab852c412 Implement searching for unicode characters by name 2018-02-12 14:08:54 +05:30
Kovid Goyal
193ac6cd81 Forgot to remove from recent when adding to top of list 2018-02-12 12:39:02 +05:30
Kovid Goyal
34ca8419bb Finish chose unicode symbol by recently used 2018-02-12 10:19:29 +05:30
Kovid Goyal
6094aabe26 ... 2018-02-12 10:19:29 +05:30
Kovid Goyal
19648257f2 Have wcwidth() ignore SGR 2018-02-12 10:19:29 +05:30
Kovid Goyal
3363a9459b Implement drawing of titlebar, remembering of mode and fix various bugs in tui 2018-02-12 10:19:29 +05:30
Kovid Goyal
4d92f4871a Mark names.h as being generated 2018-02-12 10:19:29 +05:30
Kovid Goyal
f0d4ad16d2 Work on search by name in unicode input 2018-02-12 10:19:29 +05:30
Kovid Goyal
2cc8402458 A FAQ entry about terminfo over SSH 2018-02-12 10:19:12 +05:30
Kovid Goyal
1c79320133 Fix #319 2018-02-11 13:03:20 +05:30
Kovid Goyal
8b099d969f oops 2018-02-11 11:37:05 +05:30
Kovid Goyal
61157e8763 Remove the passing of swap_interval as a constructor parameter
It was unused and makes it more complicated to override via an option,
if needed.
2018-02-11 11:14:48 +05:30
Kovid Goyal
f97d078f81 Fix kitty saving incorrect window heights
Typo caused saved window height to be actually the window width
2018-02-10 10:00:54 +05:30
Kovid Goyal
a14cf81422 Store cached window sizes in the cache dir rather than the config dir
A side-effect is that on the very next start kitty wont remember window
sizes, apologies for the on convenience.
2018-02-10 10:00:47 +05:30
Kovid Goyal
feeba9b5f5 Add a note about where kitty @ messaging works 2018-02-10 07:35:36 +05:30
Kovid Goyal
b1b76ca250 Redraw windows when the window manager tells us they have been damaged
Needed on systems with non-compositing window managers. Fix #317
2018-02-10 06:54:30 +05:30
Kovid Goyal
e119ed0daa Ignore harmless KeyError while modifying selectors 2018-02-09 20:20:18 +05:30
Kovid Goyal
8c18486836 Module with all the data for unicode entry by character name 2018-02-09 19:56:25 +05:30
Kovid Goyal
b6ed3951bc Add the kittens dir when building the package 2018-02-09 16:59:15 +05:30
Kovid Goyal
ea178ea689 Forgot to marcj launcher script executable 2018-02-09 16:48:04 +05:30
Kovid Goyal
973bbf3f8a Fix #316 2018-02-09 16:44:52 +05:30
Kovid Goyal
3068846d8f Implement using Ctrl+Shift+u to input unicode
Fixes #302
2018-02-08 22:47:17 +05:30
Kovid Goyal
194454715f Basic unicode input works 2018-02-08 22:16:39 +05:30
Kovid Goyal
ac02e053ee Dont save/restore DECCOLM since it is actually unused in kitty 2018-02-08 22:12:51 +05:30
Kovid Goyal
75db360929 ... 2018-02-08 12:57:57 +05:30
Kovid Goyal
f9141120aa A few fixes for the extended key protocol 2018-02-08 12:57:16 +05:30
Kovid Goyal
d19f9e5b96 Fix error handling in tui.loop 2018-02-08 12:33:27 +05:30
Kovid Goyal
213a223861 Typo in incremental decoder init 2018-02-08 11:56:34 +05:30
Kovid Goyal
ef9a24932f Start work on unicode input kitten 2018-02-08 11:00:57 +05:30
Kovid Goyal
bf5b0070c1 Add note about terminfo property used for styled underlines 2018-02-08 10:29:37 +05:30
Kovid Goyal
2ab6f57159 Add non-standard terminfo capabilities
Advertises support for truecolor and styled underlines.
The truecolor properties are used by at least tmux and neovim.
2018-02-08 10:26:13 +05:30
Kovid Goyal
77d46630d7 Update bundled glfw 2018-02-08 09:15:40 +05:30
Kovid Goyal
b78612aebd Entry point to run python on cmd line and from scripts 2018-02-08 09:11:13 +05:30
Kovid Goyal
0f63d1bfa7 ... 2018-02-07 22:41:03 +05:30
Kovid Goyal
66a897cc80 Add interrupt and eot callbacks 2018-02-07 19:46:53 +05:30
Kovid Goyal
3828511051 forgot to include in last commit 2018-02-07 14:40:23 +05:30
Kovid Goyal
226a89c184 Add JSON definition of key encoding 2018-02-07 14:39:11 +05:30
Kovid Goyal
e3b4919c17 Finish up tui.Loop 2018-02-07 13:30:34 +05:30
Kovid Goyal
168bc58635 The kittens learn about mice 2018-02-07 12:40:04 +05:30
Kovid Goyal
f4f0b8fd5f Kittens learn about bracketed paste 2018-02-07 10:39:05 +05:30
Kovid Goyal
13c034c613 Add link to ncurses FAQ on bce as well 2018-02-07 08:06:24 +05:30
Kovid Goyal
35f1658f4a Key and text handler for the kittens 2018-02-06 20:58:46 +05:30
Kovid Goyal
328f22adab Let update_cell_emtrics() know if it is being called in response to a DPI change 2018-02-06 20:12:57 +05:30
Kovid Goyal
22cf67b407 More work on tui.loop 2018-02-06 20:08:28 +05:30
Kovid Goyal
0c7d51dd9d Avoid unnecessary draw calls with multiple OS Windows
Do not ask the GPU to draw and swap buffers for OS Windows that are not
dirtied. See #313
2018-02-06 19:32:24 +05:30
Kovid Goyal
fa87ce72a8 A terminal input parse helper for the kittens 2018-02-06 17:29:05 +05:30
Kovid Goyal
ff2e5b3966 Avoid unnecessary calls to mark_for_codepoint 2018-02-06 11:23:39 +05:30
Kovid Goyal
96c93fa252 Add support for emoji presentation when choosing fallback fonts 2018-02-06 11:11:22 +05:30
Kovid Goyal
e830b7edf7 Add emoji presentation variation selector support to wcswidth() as well 2018-02-06 10:16:23 +05:30
Kovid Goyal
9c874f6685 Add support for the unicode emoji presentation variation selector 2018-02-06 09:52:55 +05:30
Kovid Goyal
b8ab15bea8 Fix incorrect window border drawing for overlay windows 2018-02-06 09:41:19 +05:30
Kovid Goyal
6c7247f726 Disable display_scrollback for overlay windows 2018-02-06 09:36:36 +05:30
Kovid Goyal
7674aa4e7c Add FAQ entry about bce in vim 2018-02-06 08:55:42 +05:30
Kovid Goyal
ebe97bf492 Get rid of safe_wcwidth
Since wcwidth is now in our control, we dont need to wrap it.
2018-02-05 10:11:30 +05:30
Kovid Goyal
fbe4d036d8 Have wcwidth() return 0 for marks instead of -1
Since kitty always treats marks as combinig chars, this allows us to
remove a few unnecessary branches
2018-02-05 10:06:05 +05:30
Kovid Goyal
c572b8bb1a Refactor screen_draw()
Make it a little faster and also clearer, splitting out
the logic for combining chars into a separate function.
2018-02-05 09:55:17 +05:30
Kovid Goyal
59a5e23466 Almost always resize glyphs that are too wide
When using FreeType, rescale glyphs that dont fit if they are more than
1px wider than the cell rather than 25% of the cell width. This matches
the behavior of CoreText and is needed for rendering the various Emoji
with default text presentation (i.e. emoji that have wcwidth() == 1)
2018-02-05 09:21:14 +05:30
Kovid Goyal
b9857f9499 Only consider emoji characters with emoji presentation to have width two
Fixes #308
2018-02-05 09:21:13 +05:30
Kovid Goyal
b667e3a577 DRYer 2018-02-05 09:19:12 +05:30
Kovid Goyal
240b1475c7 Fix regression that caused a few ligatures to not render correctly in rare circumstances
This was caused by cache corruption. is_special_glyph() and
is_empty_glyph() were treading over each other if called in
the right sequence. Fixes #303
2018-02-05 00:04:05 +05:30
Kovid Goyal
3f24e5b571 A few more places to remove wcwidth from 2018-02-04 22:47:02 +05:30
Kovid Goyal
fc7ec1d3f7 Get rid of the option to use the system wcwidth
The system wcwidth() is often wrong. Not to mention that if you SSH into
a different machine, then you have a potentially different wcwidth. The
only sane way to deal with this is to use the unicode standard.
2018-02-04 21:02:30 +05:30
Kovid Goyal
452ff02b15 Oops added extra file in previous commit 2018-02-04 20:34:02 +05:30
Kovid Goyal
c2cb43cc07 Framework for kittens 2018-02-04 20:23:52 +05:30
Kovid Goyal
6736fd3835 Get rid of the query escape code for styled underlines 2018-02-04 16:40:48 +05:30
Kovid Goyal
a1bd69a9c2 Fix incorrect handling of CSI s/r/u 2018-02-04 16:16:57 +05:30
Kovid Goyal
561e63ee2d Use an overlay window for browsing the scrollback buffer in less 2018-02-04 11:28:13 +05:30
Kovid Goyal
647b95631f Add tests for layout operations with an overlay window 2018-02-04 11:28:13 +05:30
Kovid Goyal
aa518b2520 Add tests for basic layout operations 2018-02-04 11:28:13 +05:30
Kovid Goyal
51c0f01539 Support for overlay windows in the layout manager 2018-02-04 11:28:02 +05:30
Kovid Goyal
cc9a19b303 Move set_active_window into base class
It was only used in a single sub-class anyway
2018-02-02 13:56:25 +05:30
Kovid Goyal
2ee9844c2b Track cursor position explicitly during rewrap
Instead of using heuristics to position the cursor after a resize, track
the position during re-wrapping and place the cursor at the re-wrapped
position. Fixes #242 (I hope)
2018-02-02 13:06:18 +05:30
Kovid Goyal
4c53a74fa9 Fix resize debounce implementation 2018-02-02 13:06:18 +05:30
Kovid Goyal
9b0ffdbf5a A spot of refactoring 2018-02-02 11:19:42 +05:30
Kovid Goyal
2777b89e45 Update bundled glfw 2018-02-01 13:03:26 +05:30
Kovid Goyal
7f90430414 Designating charsets should not switch to them
Fixes #301
2018-02-01 12:05:07 +05:30
Kovid Goyal
ee4e56edf9 ... 2018-02-01 10:26:17 +05:30
Kovid Goyal
93c83d03c0 More robust private mode restore 2018-02-01 09:45:34 +05:30
Kovid Goyal
855b3de473 Implement support for save/restore of DEC private modes (CSI ? s/r) 2018-02-01 09:19:43 +05:30
Kovid Goyal
a9be05c885 ... 2018-01-31 18:13:36 +05:30
Kovid Goyal
9f3dfc27da version 0.7.1 2018-01-31 10:37:58 +05:30
Kovid Goyal
4b4f6bc928 Update CHANGELOG 2018-01-31 10:34:54 +05:30
Kovid Goyal
273735f9dc ... 2018-01-31 10:14:08 +05:30
Kovid Goyal
b95e0fb80e Shorten build/run commands 2018-01-30 15:59:31 +05:30
Kovid Goyal
6ad21fc98f Update bundled glfw 2018-01-29 12:30:05 +05:30
Kovid Goyal
bff9b03935 ... 2018-01-28 10:18:02 +05:30
Kovid Goyal
edf9413356 Add a setting to adjust the width of cells, similar to the existing setting to adjust the height of cells 2018-01-28 10:16:59 +05:30
Kovid Goyal
c74f4a8165 Fix extra columns cut-off from the right edge of italic characters that are too wide to fit in a cell 2018-01-28 10:06:39 +05:30
Kovid Goyal
8201cd3288 Add a Makefile target for building kitty-profile 2018-01-26 21:35:48 +05:30
Kovid Goyal
1603310b86 Fix off-by-one when iterating over selections that stretch into the history buf
Fixes #295
2018-01-25 20:50:34 +05:30
Kovid Goyal
627b91ffba version 0.7.0 2018-01-24 15:33:16 +05:30
Kovid Goyal
9ad65f2e1d Cleanup layouts patch
Fix bottom rect in horizontal layout not covering all windows. Fix pep8
issues. Add README and CHANGELOG entries.
2018-01-23 19:35:30 +05:30
Guybrush Threepwood
a6a606ff3d Added vertical and horizontal layouts 2018-01-23 19:30:41 +05:30
Kovid Goyal
63317f9c78 macOS: Fix alt+arrow keys not working when disabling the macos_option_as_alt config option. 2018-01-21 15:41:56 +05:30
Kovid Goyal
46d9dfb614 ... 2018-01-20 17:33:55 +05:30
Kovid Goyal
be3b33af06 Update CHANGELOG 2018-01-19 17:08:21 +05:30
Kovid Goyal
04e1b8b1ae tab bar blank rects dont extend down enough 2018-01-19 17:05:18 +05:30
Kovid Goyal
213768b6e0 Option to place tab bar at the top edge
Fixes #288
2018-01-19 17:04:58 +05:30
Kovid Goyal
aff1abdb26 Fix top line of hollow block cursor 1px too high 2018-01-19 16:23:47 +05:30
Kovid Goyal
44a413df81 Fix blank rects on the sides of the tab bar not being drawn 2018-01-19 16:02:07 +05:30
Kovid Goyal
4f12c91fff Use the new region function everywhere
Centralizes window layout calculation and no longer assumes
tab bar geometry
2018-01-19 15:56:07 +05:30
Kovid Goyal
b6188bf436 Move window region calculations into one place 2018-01-19 11:31:44 +05:30
Kovid Goyal
b9a14e0e4a A Makefile target for building kitty.app 2018-01-19 10:42:12 +05:30
Kovid Goyal
6882c23f43 Update CHANGELOG 2018-01-18 16:26:33 +05:30
Kovid Goyal
80301d465b Handle non-BMP combining characters
Use a level of indirection to store combining characters. This allows
combining characters to be stored using only two bytes, even if they are
after USHORT_MAX
2018-01-18 16:25:42 +05:30
Kovid Goyal
32632264ee Mapping that can be used to store unicode mark symbols in only two bytes 2018-01-18 16:06:07 +05:30
Kovid Goyal
409bd37db5 Store combining chars as an array in the Cell
Makes it easier to increase the number of combining chars if needed,
rather than storing them as a mask.
2018-01-18 14:10:58 +05:30
Kovid Goyal
5fd4bc965f Annotate Cell structure
Make it clear what parts are needed only on the CPU
2018-01-18 12:47:49 +05:30
Kovid Goyal
e86e5ce1d8 ... 2018-01-18 00:15:39 +05:30
Kovid Goyal
5faa649452 Drop the dependency on libunistring 2018-01-18 00:09:40 +05:30
Kovid Goyal
2ddc7e8c80 Have all marks return a wcwidth of -1
Mirrors recent change to onsidering all marks combining chars instead of
only the marks with a non-zero combining class
2018-01-17 23:25:59 +05:30
Kovid Goyal
ed700ff830 ... 2018-01-17 21:59:10 +05:30
Kovid Goyal
33ed873997 Remove unnecessary extra test for combinig characters
There are not combining characters with a non-zero combining class that
are not in the marks category.
2018-01-17 21:56:30 +05:30
Kovid Goyal
9125c00f96 Update CHANGELOG 2018-01-17 21:50:00 +05:30
Kovid Goyal
73fe3293be Fix copying from selection being restricted to only the visible part of the selection. Fixes #287 2018-01-17 21:39:24 +05:30
Kovid Goyal
804c4fbe19 Recognize characters from the unicode Mark categories as combining characters, even if they do not have a combining class (i.e. are not re-ordered). Fixes #286 2018-01-15 11:24:11 +05:30
Kovid Goyal
d6c82ba21c oops 2018-01-14 11:18:44 +05:30
Kovid Goyal
67308f2ca1 Add some documentation for the shaping algorithm 2018-01-14 11:18:44 +05:30
Kovid Goyal
4a17a946fb Ensure groups dont have too many cells 2018-01-14 11:18:44 +05:30
Kovid Goyal
1ae7ae4a1d Fix consecutive separate ligatures being rendered in the same group
Rendering multiple ligatures in the smae group is bad for performance
and also causes incorrect rendering if the last ligature in the group
does not fit into the number of cells in the group.
2018-01-14 11:18:44 +05:30
Kovid Goyal
404ca23de3 Make handling of last glyph a little more intelligent 2018-01-14 11:18:44 +05:30
Kovid Goyal
d385952fef Add a bounds check 2018-01-14 11:18:44 +05:30
Kovid Goyal
f03cac8a9d Allow storing more flags in the special glyph cache 2018-01-14 11:18:44 +05:30
Kovid Goyal
4b501fd694 Fix rendering of ligatures with ligature fonts that dont use dummy glyphs 2018-01-14 11:18:43 +05:30
Kovid Goyal
872d39eb2c Have the ctrl+shift+<key> generate the ASCII C0 control codes for the few shifted control codes there are.
See #285
2018-01-14 11:18:30 +05:30
Kovid Goyal
0341cae922 Fix unused function warning 2018-01-13 15:49:44 +05:30
Kovid Goyal
5357a9a1cc Merge branch 'us/master' of https://github.com/koekeishiya/kitty 2018-01-13 07:33:30 +05:30
koekeishiya
3695538a11 fix mac os_window focus issue 2018-01-12 20:24:11 +01:00
Kovid Goyal
7780d52930 DRYer 2018-01-12 11:27:23 +05:30
Kovid Goyal
6a23b4ee47 Allow kitty @xxx in addition to kitty @ xxx 2018-01-12 11:23:34 +05:30
Kovid Goyal
f48b770036 macOS: Fix focus not being transferred on OSWindow close
Fixes #280
2018-01-12 08:05:12 +05:30
Kovid Goyal
81b5d2c4f2 Option to copy to clipboard on mouse select 2018-01-12 07:33:21 +05:30
Kovid Goyal
d43d6ab0a9 Update bundled glfw 2018-01-12 05:34:53 +05:30
Kovid Goyal
5a4e883360 Merge branch 'macos-logo-make' of https://github.com/zchee/kitty 2018-01-11 22:31:18 +05:30
Koichi Shiraishi
eb93cd4048 Add missing 64 size because doesn't create icon_32x32@2x.png 2018-01-12 00:59:19 +09:00
Koichi Shiraishi
d83e3fddb0 Add install 'optipng' description because logo/make.py depends 'optipng' 2018-01-12 00:58:02 +09:00
Kovid Goyal
80ca25e879 ... 2018-01-11 16:03:23 +05:30
Kovid Goyal
c86b34aacd Move to_color into config_utils 2018-01-11 16:02:52 +05:30
Kovid Goyal
8da426039b Make the config parsing code more re-useable 2018-01-11 12:17:18 +05:30
Kovid Goyal
9184e9a28f Update CHANGELOG 2018-01-11 10:46:50 +05:30
Kovid Goyal
578d537d5f kitty icat: Fix some PNG images not being displayed
Work around for bug in ImageMagick where it converts images
into rgba data with fewer rows than specified. Fixes #276
2018-01-11 09:56:40 +05:30
Kovid Goyal
236c92b2b4 No longer use a shell script for the wrapper .app 2018-01-11 08:40:35 +05:30
Kovid Goyal
66a46279f4 ... 2018-01-11 00:26:29 +05:30
Kovid Goyal
eb35edbe20 kitty icat: Fix typo that broke the SIGWNCH signal handler 2018-01-11 00:24:26 +05:30
Kovid Goyal
7cf2404331 Update CHANGELOG 2018-01-10 15:29:58 +05:30
Kovid Goyal
9ccc6bf835 Fix incorrect handling of zero extra pixel offset 2018-01-10 13:54:51 +05:30
Kovid Goyal
025a46bb35 Fix the in cell offset calculations 2018-01-10 13:50:44 +05:30
Kovid Goyal
677e8a1ae9 Make the signal handler a little simpler 2018-01-10 13:37:43 +05:30
Kovid Goyal
03702772d3 kitty icat: Add a --scale-up option to expand images when used with the --place operator 2018-01-10 13:32:05 +05:30
Kovid Goyal
3cd744b247 Implement @focus-window 2018-01-10 13:23:04 +05:30
Kovid Goyal
88523b2692 Add a note about @ls to the tutorial 2018-01-10 13:00:59 +05:30
Kovid Goyal
dcb39eb210 ... 2018-01-10 12:57:15 +05:30
Kovid Goyal
102823809b Add a tutorial for controlling kitty from scripts 2018-01-10 12:54:21 +05:30
Kovid Goyal
23f2b29069 Add --keep-focus for @new-window 2018-01-10 12:36:15 +05:30
Kovid Goyal
7b33a87725 @send-text allow sending from files and stdin 2018-01-10 10:37:43 +05:30
Kovid Goyal
6dde573ed9 Fix __name__ != __main__ when using runpy in the osx-bundle 2018-01-10 08:31:22 +05:30
Kovid Goyal
566e641be1 Allow easily building a kitty.app wrapper to run kitty from source 2018-01-10 07:44:16 +05:30
Kovid Goyal
08d5448523 Move creation of Info.plist and kitty.icns into osx-bundle 2018-01-10 06:58:57 +05:30
Kovid Goyal
c11a20f1ec Add --new-tab to @new-window 2018-01-09 23:09:57 +05:30
Kovid Goyal
e5b9bd2e5a Implement @get-text 2018-01-09 22:48:24 +05:30
Kovid Goyal
6ad49bd7fb Add an option to override the default shell 2018-01-09 16:28:46 +05:30
Kovid Goyal
5d082d8d5a Implement @new-window 2018-01-09 16:13:28 +05:30
Kovid Goyal
977575da73 Implement @close-tab 2018-01-09 15:30:46 +05:30
Kovid Goyal
bced6f31b1 Implement @close-window 2018-01-09 15:27:12 +05:30
Kovid Goyal
6bf04e22cc Fix send_text parsing choking on ''' 2018-01-09 13:10:28 +05:30
Kovid Goyal
2f9784809d Chunk up overly large send text inputs 2018-01-09 02:51:22 +05:30
Kovid Goyal
3e85497c2c Implement @set-tab-title 2018-01-08 16:13:38 +05:30
Kovid Goyal
3b551a1dee Implement @set-window-title 2018-01-08 14:04:27 +05:30
Kovid Goyal
d2fdb1c1eb DRYer 2018-01-08 13:57:43 +05:30
Kovid Goyal
db92af68e9 Fix a couple of typos 2018-01-08 13:54:08 +05:30
Kovid Goyal
815087460c ... 2018-01-08 13:25:25 +05:30
Kovid Goyal
b4cb9d7c4d ... 2018-01-08 13:07:47 +05:30
Kovid Goyal
c6d10c6a23 Use the launch time argv for cmdline on macOS 2018-01-08 13:07:06 +05:30
Kovid Goyal
464c7a80e2 Implement window matching for remote control 2018-01-08 13:01:57 +05:30
Kovid Goyal
4f56cce727 Fix client eating up send-text when seding to same window 2018-01-08 12:48:15 +05:30
Kovid Goyal
7dea6e0ef4 Initial implementation of send-text remote cmd 2018-01-08 12:48:15 +05:30
Kovid Goyal
8c143db381 Add documentation for the ls command 2018-01-08 12:48:15 +05:30
Kovid Goyal
0cea6d5a1b Implement window listing 2018-01-08 12:48:15 +05:30
Kovid Goyal
eff881f4bb Allow sending arbitrary sized escpae codes to children 2018-01-08 12:48:14 +05:30
Kovid Goyal
c64fd1760c More work on remote control 2018-01-08 12:48:14 +05:30
Kovid Goyal
9e361700d2 Handle reading of RC response via stdin 2018-01-08 12:48:14 +05:30
Kovid Goyal
1f976644bf Refactor read with timeout logic into its own function 2018-01-08 12:48:14 +05:30
Kovid Goyal
f3cb68ee40 Framework for remote control 2018-01-08 12:48:14 +05:30
Kovid Goyal
85a3da057f Session file: Allow setting the title for windows 2018-01-08 12:47:47 +05:30
Kovid Goyal
c551384369 Session file: Allow specifying multiple cd directives per tab to have different windows launched with different working directories 2018-01-08 12:38:01 +05:30
Kovid Goyal
ce230b071b Add tests for SGR protocol encoding 2018-01-07 23:48:16 +05:30
Kovid Goyal
13d5f04ad9 A spot of refactoring 2018-01-07 21:26:28 +05:30
Daniels Kursits
3b861de3d2 Fix mouse move events being reported as drag events
when using the SGR mouse reporting protocol

Fixes #271
2018-01-07 21:12:50 +05:30
Kovid Goyal
1ef010689d Add support for clearing the scrollback buffer
kitty now supports using \E3J to clear the screen and scrollback buffer.
See #268
2018-01-06 23:55:49 +05:30
Kovid Goyal
3523ab283f More trailing whitespace 2018-01-06 09:12:23 +05:30
Kovid Goyal
5b2a9b101d Fix trailing whitespace 2018-01-05 21:27:24 +05:30
Kovid Goyal
fdcfcfa1b9 Make alt+backspace delete the previous word
i.e. alt+backspace now sends ^W (werase). THis matches the behavior of
terminal.app and gnome-terminal. Fixes #264
2018-01-05 21:08:42 +05:30
Kovid Goyal
88e9c21a3b Ensure a kitty executable is on PATH even when running from source 2018-01-05 14:56:01 +05:30
Kovid Goyal
973352a98d Allow + prefixing of special invocations 2018-01-05 14:36:31 +05:30
Kovid Goyal
f06f871dfc Handle fork() failures more gracefully 2018-01-05 13:57:49 +05:30
Kovid Goyal
e03c713294 Remove a few more signal unsafe function calls between fork() and exec() 2018-01-05 00:24:15 +05:30
Kovid Goyal
aa107956f9 ... 2018-01-04 23:55:03 +05:30
Kovid Goyal
d725578e1b Silence spurious compiler warning 2018-01-04 23:54:35 +05:30
Kovid Goyal
239eb8202b Move fork()+exec() of child processes into C
By avoiding python in the child process before exec we ensure that
malloc and other unsafe to use after fork functions are not used.
Should also mean that less pages will need to be copied into thec hild
process, leading to marginally faster startups.
2018-01-04 23:19:09 +05:30
Kovid Goyal
58d7439719 Add a note on installing dev packages for X11 on linux
Fixes #260
2018-01-04 18:06:11 +05:30
Kovid Goyal
cc145ec3dd DRYer 2018-01-04 12:38:35 +05:30
Kovid Goyal
847ce37160 Take the mouse wheel multiplier into account when generating keypresses for mouse wheel events. Fixes #262 2018-01-04 12:34:31 +05:30
Kovid Goyal
0305009766 Remove --without-cairo from brew install since it is ignored anyway 2018-01-03 09:22:23 +05:30
Kovid Goyal
fe1b056371 Allow using macOS specific modifier key names in the config file
cmd and option can now be used instead of super and alt respectively.
2018-01-03 08:59:36 +05:30
Kovid Goyal
0c4804db79 DRYer 2017-12-31 09:04:22 +05:30
Kovid Goyal
f7e84df332 Add an explicit OpenGL version test
Apparently there are some pre 3.3 drivers that include the
texture_storage extension. Fixes #258
2017-12-31 08:36:50 +05:30
Kovid Goyal
bd654d22f4 Read the required wayland protocols version from upstream instead of hardcoding it 2017-12-28 14:12:46 +05:30
Kovid Goyal
115de36599 version 0.6.1 2017-12-28 10:40:42 +05:30
Kovid Goyal
b01c3483de Add an option to fade text in inactive windows
Fixes #256
2017-12-28 10:36:48 +05:30
Kovid Goyal
db7f566a0c Update Changelog 2017-12-27 10:17:34 +05:30
Kovid Goyal
9f806e76e7 Fix incorrect condition for aborting cursor geometry calculation 2017-12-27 10:07:21 +05:30
Kovid Goyal
12bdd4dddd Bump min version of wayland-protocols to match upstream 2017-12-27 07:24:38 +05:30
Kovid Goyal
72a1eb237d Fix regression that broke drawing of hollow cursor when window loses focus
Fixes #255
2017-12-27 07:15:48 +05:30
Kovid Goyal
6a89289907 Merge branch 'recmod' of https://github.com/grimpy/kitty 2017-12-27 06:40:53 +05:30
Kovid Goyal
7ed835cf13 Fix a crash when detecting URLs continued onto multiple lines
Fixes #244
2017-12-27 06:35:09 +05:30
Kovid Goyal
4621ff41d9 Skip building the wayland backend on systems with missing wayland protocol definitions
Fixes #254
2017-12-27 06:22:36 +05:30
Jo De Boeck
60e17d5224 Make it possible to modify rectangle selection modifiers
Signed-off-by: Jo De Boeck <deboeck.jo@gmail.com>
2017-12-24 18:40:25 +02:00
Kovid Goyal
1e2f7c705d ... 2017-12-22 12:36:40 +05:30
Kovid Goyal
1ebf0b95c4 Implement reading of cwd of a process on macOS as well 2017-12-21 12:30:34 +05:30
Kovid Goyal
c5acd94456 Add new actions to open tabs/windows with the working directory set to the working directory of the current window
Fixes #237
2017-12-21 11:29:21 +05:30
Kovid Goyal
448ffe01c3 Fix new window being created with different DPI not changing global DPI 2017-12-21 09:06:07 +05:30
Kovid Goyal
5c882f3290 Fix Travis flake failure on gen-wcwidth.py because of old python version 2017-12-20 23:38:16 +05:30
Kovid Goyal
70a4720bf9 Fix for window being opened on secondary monitor using primary monitor DPI 2017-12-20 23:01:06 +05:30
Kovid Goyal
c8aee8c881 Automatically adjust cell height when DPI changes
DPI changes are detected as a change in the ration of the window size to
the framebuffer size. I dont know how reliable that is. Possiblly Fix #77
2017-12-20 22:55:05 +05:30
Kovid Goyal
c2ad0607b8 Fix trailing whitespace in generated unicde data files 2017-12-20 22:44:20 +05:30
Kovid Goyal
d1282b9f55 Add a script to generate wcwidth as well
Generated function is more efficient than the implementation from
wcwidth9 and also makes it easy to update when the unicode standard
changes.
2017-12-20 16:18:05 +05:30
Kovid Goyal
11ee317884 Fix some emoji glyphs not colored on Linux
Linux has a plethora of fonts that contain some emoji glyphs. If one of
those fonts is used as a fallback font for a non-emoji character, it
also gets used for emojis -- leading to non-colored emoji. Fix by making
sure the first fallback font is a dedicated emoji font.
2017-12-20 10:40:27 +05:30
Kovid Goyal
e69de2f968 Use the new glfw API for setting WM_CLASS 2017-12-20 09:18:29 +05:30
Kovid Goyal
2f4f3e3331 Update bundled glfw 2017-12-20 09:07:06 +05:30
Kovid Goyal
020f8a2047 Add trailing space test to travis 2017-12-20 08:52:06 +05:30
Kovid Goyal
b8faba2a16 More trailing space removal 2017-12-20 08:50:09 +05:30
Kovid Goyal
0fcce6ec58 Remove trailing whitespace from native code files 2017-12-20 08:44:47 +05:30
Kovid Goyal
15f5ea92b8 Merge branch 'master' of https://github.com/FabioLolix/kitty 2017-12-20 08:24:20 +05:30
FabioLolix
2bbb5d25eb Updated readme 2017-12-20 00:12:58 +01:00
Kovid Goyal
8d94285a5d Ensure underlines are rendered even for fonts with very poor metrics
Fixes #236
2017-12-19 00:54:04 +05:30
Kovid Goyal
eed11361c5 Fix typo in config directory override env var 2017-12-18 06:59:19 +05:30
Kovid Goyal
b759f96f96 version 0.6.0 2017-12-18 06:39:55 +05:30
Kovid Goyal
df3342d121 Update CHANGELOG 2017-12-18 06:28:57 +05:30
Kovid Goyal
862ed40c44 Update CHANGELOG 2017-12-18 06:26:16 +05:30
Kovid Goyal
8018024cb7 Fix middle and right mouse button swapped
Fixes #235
2017-12-18 05:48:51 +05:30
Kovid Goyal
c8d5f232b3 Some documentation for the kitty extensions to DECCARA 2017-12-17 18:13:39 +05:30
Kovid Goyal
d48b76508b Implement DECCARA
Ability to set text attributes/colors in arbitrary screen regions,
instead of working via the cursor. Note that kitty extends the original
DECCARA spec from the VT-510 to allow setting all supported SGR
attributes.
2017-12-17 18:03:39 +05:30
Kovid Goyal
2d62e10a7e ... 2017-12-16 15:40:09 +05:30
Kovid Goyal
0b3a5a7d45 icat: Add --clear to clear all display images 2017-12-16 10:33:16 +05:30
Kovid Goyal
076658a1e8 Possible fix for crash reported in #233 2017-12-16 10:23:12 +05:30
Kovid Goyal
be1a05b322 ... 2017-12-16 10:22:03 +05:30
Kovid Goyal
945613555a icat: Add option to display image at arbitrary location on screen
Fixes #228
2017-12-16 09:45:49 +05:30
Kovid Goyal
5f75becc5a Add note about creating launcher app for running kitty from source 2017-12-16 09:29:19 +05:30
Kovid Goyal
51ac78f74d X11: Set the WINDOWID environment variable
Fixes #232
2017-12-16 08:57:52 +05:30
Kovid Goyal
3cce9b1c38 ... 2017-12-16 08:54:55 +05:30
Kovid Goyal
8a9ee6f3f5 ... 2017-12-15 16:32:28 +05:30
Kovid Goyal
d3059c09e0 Nicer CLI help output 2017-12-15 14:49:42 +05:30
Kovid Goyal
1f093b4ff2 icat: Add an option to only detect image display support 2017-12-15 14:06:41 +05:30
Kovid Goyal
50470b5747 icat: Add --transfer-mode option
Explicitly control the transfer mode instead of auto-detecting
2017-12-15 13:34:39 +05:30
Kovid Goyal
304f21e79d icat: Fix temp files not being deleted when transmitting using escape codes 2017-12-15 13:18:18 +05:30
Kovid Goyal
cb04deef63 icat: Add a command line argument for horizontal alignment 2017-12-15 13:08:27 +05:30
Kovid Goyal
ddb2e41352 Get rid of argparse from kitty-icat as well 2017-12-15 12:35:30 +05:30
Kovid Goyal
a6700c951a Also filter 8-bit control sequences when sanitizing 2017-12-15 09:36:45 +05:30
Kovid Goyal
684a2e05f4 Move logical DPI calculation into glfw module
Now DPI state is maintained in only one central place.
2017-12-14 18:30:53 +05:30
Kovid Goyal
c7e1a12eb6 Have pt_to_px use global_state instead of get_dpi
DRYer and reduces code size
2017-12-14 18:04:10 +05:30
Kovid Goyal
ce7be5a05e Fix #226 2017-12-14 06:42:52 +05:30
Kovid Goyal
433640de84 Support running on the "low power" GPU on dual GPU macOS machines
Fixes #136
2017-12-14 06:14:22 +05:30
Kovid Goyal
7f19424f2d Fix for kitty sometimes not detecting child death on macOS 2017-12-13 22:20:11 +05:30
Kovid Goyal
b9d0ec0d4c CoreText: Use the layout engine to calculate cell height
Slower, but hopefully more accurate, since it takes into account
whatever kludges Apple is currently using to calculate line height
in its applications.
2017-12-13 14:12:23 +05:30
Kovid Goyal
869abc4d5c ... 2017-12-13 14:05:01 +05:30
Kovid Goyal
872118fcbe CoreText: Fix incorrect underline position and thickness calculation 2017-12-13 13:59:11 +05:30
Kovid Goyal
da0309545e Ensure bounds in add_line() 2017-12-13 13:46:28 +05:30
Kovid Goyal
54b802f1e6 Ensure bounds in add_dline() 2017-12-13 13:45:11 +05:30
Kovid Goyal
d097403a12 Implement select-by-rectangle when holding down Ctrl+Alt
Fixes #225
2017-12-13 13:26:55 +05:30
Kovid Goyal
c81a8216dc Limit the max number of lines to extend URLs over 2017-12-13 12:18:35 +05:30
Kovid Goyal
95683c658b When hovering over a URL, highlight the URL fully even if it continues over multiple lines. Note that URL detection has not changed. A URL will be detected only if the mouse hovers over the line containing the start of the URL. 2017-12-13 11:11:13 +05:30
Kovid Goyal
d25c0d42bc CoreText: Ensure cell_width and cell_height are never zero 2017-12-13 09:35:50 +05:30
Kovid Goyal
77f0328f4f Ensure mouse cursor is in default state when focus is switched to the OSWindow 2017-12-13 08:54:11 +05:30
Kovid Goyal
a1b4f7c92d Fix COreText leak on exit 2017-12-13 08:27:33 +05:30
Kovid Goyal
47704f24c1 CoreText: Get rid of the line height fudge factor
It was leading to larger line heights than in iTerm on High Sierra with
Menlo. Also as per Apple documentation, line height should be ascent +
descent + leading.
https://developer.apple.com/library/content/documentation/TextFonts/Conceptual/CocoaTextArchitecture/TypoFeatures/TextSystemFeatures.html
2017-12-13 08:22:26 +05:30
Kovid Goyal
e0ef563885 Use glfw primary monitor content scale for logical DPI on macOS as well
It gives the correct DPI value on a MacBook Air monitor, while physical
DPI is too high, leading to overlarge fonts.
2017-12-12 23:47:42 +05:30
Kovid Goyal
2e570e21a0 Ensure kitty is on the PATH when running from kitty.app 2017-12-12 23:29:01 +05:30
Kovid Goyal
a962a28b36 ... 2017-12-12 22:23:16 +05:30
Kovid Goyal
898395253b Add test for ignored color id in SGR colon based color sequence 2017-12-12 18:50:37 +05:30
Kovid Goyal
346a9f68b1 Fix #227 2017-12-12 18:38:52 +05:30
Kovid Goyal
dbf8eb773c Add a FAQ entry about building kitty.app 2017-12-12 09:49:41 +05:30
Kovid Goyal
47ed1a4dca Make update-on-ox not depend on remote script 2017-12-11 23:11:34 +05:30
Kovid Goyal
4c566ee37f Clarify FAQ entry further 2017-12-11 21:38:16 +05:30
Kovid Goyal
a29b424477 CoreText: Implement resizing of glyphs too wide to fit 2017-12-11 20:34:23 +05:30
Kovid Goyal
56a30a014c Fix compilation order reversed 2017-12-11 20:28:36 +05:30
Kovid Goyal
abdc149f65 Update travis script 2017-12-11 19:10:00 +05:30
Kovid Goyal
005c4bf29e Finish up CoreText based rendering 2017-12-11 19:04:44 +05:30
Kovid Goyal
c86c166448 More work on positioning glyphs with CoreText 2017-12-11 18:48:14 +05:30
Kovid Goyal
0999ce159e Fix colors incorrect when rendering directly to buf 2017-12-11 10:43:32 +05:30
Kovid Goyal
98d8ab2953 Fix OT shaper not working on macOS
Also dont keep an extra reference to the hb font in fonts.c
2017-12-11 09:48:20 +05:30
Kovid Goyal
5407fa72b4 Start work on rendering with CoreText 2017-12-10 20:28:06 +05:30
Kovid Goyal
e332522a61 Mark backend API in fonts.h header 2017-12-10 09:21:46 +05:30
Kovid Goyal
ee27f23862 Add rgba and lcdfilter fields to the fc-dict 2017-12-09 12:58:23 +05:30
Kovid Goyal
b1853ca966 Dont insist color fonts have bitmaps 2017-12-09 12:01:43 +05:30
Kovid Goyal
ed2e83654f Draw emoji on macOS using CoreText rather than FreeType
Needed because FreeType cannot handle the latest version of the Apple
Color Emoji font, which probably uses SVG-in-OTF instead of SBIX.
Finishes up the color emoji implementation.
2017-12-09 12:01:43 +05:30
Kovid Goyal
ec6dcd53b5 Finish up placement of color emojis
Note that for some reason rendering is broken on Apple
2017-12-09 12:01:43 +05:30
Kovid Goyal
0b6fe99611 Report errors rendering glyphs 2017-12-09 12:01:43 +05:30
Kovid Goyal
03847b15f6 Implement downsampling of color emoji bitmaps
Still need to fix placement of the downsampled bitmaps in the cell
2017-12-09 12:01:43 +05:30
Kovid Goyal
8d7515bd9b Basic color emoji rendering working
Still need to downscale color bitmaps to fit into cells
2017-12-09 12:01:43 +05:30
Kovid Goyal
e4b839742c Add option to control using color emoji or not 2017-12-09 12:01:43 +05:30
Kovid Goyal
f3cdf4194a Prefer color emoji fonts 2017-12-09 12:01:43 +05:30
Kovid Goyal
ef6f4c2fbf Improve fontconfig fallback font queries for emoji 2017-12-09 12:01:43 +05:30
Kovid Goyal
9cda51b5a8 Store sprites in an RGBA texture
Needed to support color emoji
2017-12-09 12:01:42 +05:30
Kovid Goyal
b8093d6b83 ... 2017-12-09 11:28:49 +05:30
Kovid Goyal
ffedc5d170 ... 2017-12-09 11:01:32 +05:30
Kovid Goyal
f223cd4b56 Set use_system_wcwidth to no by default
I am tired of seeing the endless bug reports from people running on
systems with outdated wcwidth() implementations.
2017-12-09 10:53:13 +05:30
Kovid Goyal
111c7fa57c Ensure config file is always decoded as UTF-8 2017-12-08 01:27:35 +05:30
Kovid Goyal
e630abfe7f Revert change to use libpng16
Does not fix the OP's problem.
2017-12-06 21:10:48 +05:30
Kovid Goyal
11b17c09ce Call pkg-config with libpng16 instead of libpng
Should fix compilation on linux systems that have libpng12 as their
default libpng. libpng16 was released over five years ago! Sigh...
Fixes #216
2017-12-06 20:54:46 +05:30
Kovid Goyal
466d96c167 Remove spurious call to Py_DECREF 2017-12-06 10:13:57 +05:30
Kovid Goyal
c90223e4c8 Report unknown CSI r sequences 2017-12-06 00:31:03 +05:30
Kovid Goyal
01324a7ad2 Reduce the rescale threshold from 133% to 125% 2017-12-05 23:32:40 +05:30
Kovid Goyal
122ad8a1f8 Detect if a freetype font has color tables 2017-12-05 23:31:26 +05:30
Kovid Goyal
138bfcf2a8 Fix key-presses mapped to CSI codes not respecting SC81t mode 2017-12-05 20:21:13 +05:30
Kovid Goyal
c95418a947 Remove unused code 2017-12-05 20:21:13 +05:30
Kovid Goyal
b191727567 Some simple tests for sc81t 2017-12-05 20:21:12 +05:30
Kovid Goyal
c17c6cae4c Support S8C1T mode
That is, eight bit control codes. When in S8C1T mode, kitty will send
only eight bit control codes to the client.
2017-12-05 20:21:12 +05:30
Kovid Goyal
ed9b332da5 Add an option to control the underline style for highlighting URLs on mouse over 2017-12-05 12:28:10 +05:30
Kovid Goyal
e8441ce697 Ensure double underline is gapped even when underline thickness is less than three pixels 2017-12-05 11:42:35 +05:30
Kovid Goyal
f2d00589d8 Update test to match new set of pre-rendered sprites 2017-12-04 12:41:50 +05:30
Kovid Goyal
e81ba3b207 Change undercurl escape code to 4:x
See https://github.com/neovim/neovim/issues/7479
for discussion. Also implement double underline.
2017-12-04 12:26:50 +05:30
Kovid Goyal
27cd303a05 Centralize code to convert to SGR
Conversion from formatting attributes to SGR now always goes through a
Cursor.
2017-12-04 10:51:06 +05:30
Kovid Goyal
52ecdfe3a9 Fix incorrect termcap query responses
Did not realize that the responses had to be processed via tparm() i.e.
they should be the actual bytes not the textual representation of them.
This broke the backspace key in vim.
2017-12-03 21:34:55 +05:30
Kovid Goyal
70f71e8ada Fix #211 2017-12-03 00:30:11 +05:30
Kovid Goyal
d12063daad Add configurable shortcuts to go to a tab by number
Fixes #208
2017-12-02 16:31:40 +05:30
Kovid Goyal
b9798c74d4 Support for DCS status and capabilities reporting codes 2017-12-02 14:35:06 +05:30
Kovid Goyal
c12bce3d2f Respond to OSC color query escape codes 2017-12-01 21:02:30 +05:30
Kovid Goyal
73b501c961 Make color parsing a little more robust
Add a few tests for it
2017-12-01 20:02:47 +05:30
Kovid Goyal
08079ad889 Update README on layouts 2017-12-01 12:23:57 +05:30
Kovid Goyal
b4509e341a Update glfw 2017-12-01 12:16:18 +05:30
Kovid Goyal
08ee77d11c Allow D&D of files into kitty
Fixes #206
2017-12-01 12:16:17 +05:30
Kovid Goyal
868c1d634b Apparently libunistring is already installed by brew 2017-12-01 12:16:17 +05:30
Kovid Goyal
ccc67b66c4 Add more options to customize the tab-bar
Fixes #203
2017-12-01 12:16:17 +05:30
Kovid Goyal
a0702f4a97 Add an option to set the window title
Fixes #201
2017-12-01 12:16:17 +05:30
Kovid Goyal
cada4a8ca8 Move changelog entries 2017-12-01 12:16:17 +05:30
Kovid Goyal
af69f714b1 Update CHANGELOG 2017-12-01 12:16:17 +05:30
Kovid Goyal
9c135f9f4c Add a grid window layout
Fixes #192
2017-12-01 12:16:17 +05:30
Kovid Goyal
d1df5ad4e2 Enumerate window layout choices in help 2017-12-01 12:16:17 +05:30
Kovid Goyal
6352f585e8 Fix kitty discarding peer messages in rapid succession 2017-12-01 12:16:17 +05:30
Kovid Goyal
fe3bb92b54 ... 2017-12-01 12:16:17 +05:30
Kovid Goyal
59243355f6 ... 2017-12-01 12:16:16 +05:30
Kovid Goyal
fd49d17591 Paginate --help output 2017-12-01 12:16:16 +05:30
Kovid Goyal
1d9b36996a Line wrap --help output 2017-12-01 12:16:16 +05:30
Kovid Goyal
0cac74d39a Get rid of the horrible argparse
It's slow, bloated and has no support for decent output formatting
2017-12-01 12:16:16 +05:30
Kovid Goyal
fb41ecb2e5 Update bundled glfw 2017-12-01 12:16:16 +05:30
Kovid Goyal
0296d1f9a2 Fix refactor caused cursor visibility to no longer be respected 2017-12-01 12:16:16 +05:30
Kovid Goyal
b51100195a Dont use FBO's unless absolutely necessary
Negative z-index images dont need FBO based rendering when the
background is opaque. Finishes up support for background_opacity.

Fixes #31
2017-12-01 12:16:16 +05:30
Kovid Goyal
b86e0ef669 Tell the OS we dont use depth and stencil buffers 2017-12-01 12:16:16 +05:30
Kovid Goyal
86e33f739c Ensure OS windows have both buffers cleared after a resize/on first render 2017-12-01 12:16:16 +05:30
Kovid Goyal
259dcf376c DRYer 2017-12-01 12:16:16 +05:30
Kovid Goyal
466155fd24 API needed for kitty-bar 2017-12-01 12:16:16 +05:30
Kovid Goyal
452fd71fea Simplify blit vertex shader
Also fixes rendering on macOS which for some reason was not doing the
texture co-ordinate mapping correctly in the old shader.
2017-12-01 12:16:15 +05:30
Kovid Goyal
da8944b551 ... 2017-12-01 12:16:15 +05:30
Kovid Goyal
5e2587920a Call glViewport in the render loop
Ensure FBOs have correct viewport
2017-12-01 12:16:15 +05:30
Kovid Goyal
7fb48dc04c ... 2017-12-01 12:16:15 +05:30
Kovid Goyal
b8e477c6eb Clamp the FBO texture 2017-12-01 12:16:15 +05:30
Kovid Goyal
a3b85883f8 Block cursor should not be affected by background_opacity 2017-12-01 12:16:15 +05:30
Kovid Goyal
e1c553e7b2 Wakeup main loop on peer message received 2017-12-01 12:16:15 +05:30
Kovid Goyal
be6151730d Fix SPECIAL stage in interleaved rendering 2017-12-01 12:16:15 +05:30
Kovid Goyal
444d9536a7 Graphics programs should generate pre-multipled colors in interleaved mode
Also fix a few OpenGL state initialization issues.
2017-12-01 12:16:15 +05:30
Kovid Goyal
ffff343e3d Work on rendering to FBO 2017-12-01 12:16:15 +05:30
Kovid Goyal
f85c050235 Get background_opacity working, at the cost of breaking negative z-index image rendering.
Image rendering will need to use an FBO since OpenGL cannot do proper alpha compositing.
As a first step, the interleaved shaders now generate premultiplied colors as opengl can only alpha blend pre-multipled colors
2017-12-01 12:16:14 +05:30
Kovid Goyal
fe214f43cb Set _NET_STARTUP_ID before the window is mapped 2017-12-01 12:16:14 +05:30
Kovid Goyal
d9b0b5c08f oops, forgot one place to enable GL_BLEND 2017-12-01 12:16:14 +05:30
Kovid Goyal
a561697f04 No need for GL_BLEND while drawing background colors 2017-12-01 12:16:14 +05:30
Kovid Goyal
bbc140e020 Only enable GL_BLEND when actually needed 2017-12-01 12:16:14 +05:30
Kovid Goyal
2bcbcfff44 Start work on background opacity 2017-12-01 12:16:14 +05:30
Kovid Goyal
1fb81d2265 Fix incorrect blending of foreground and background colors when negative z-index images are present
Also optimize the blending calculation a bit by using the mix() function
and just adding the text and strike alphas.
2017-12-01 12:16:14 +05:30
Kovid Goyal
3b4a242e26 Fix sprites uniform not being initialized when using layered rendering
Had no actual bad effects since it is initialized to zero anyway
2017-12-01 12:16:14 +05:30
Kovid Goyal
b8937bc151 Only use wayland if a special env var is present
wayland is currently fairly broken. No window decorations and no key
auto-repeat.
2017-12-01 12:16:14 +05:30
Kovid Goyal
b3de442116 pretty colors 2017-12-01 12:16:14 +05:30
Kovid Goyal
fb797d7735 ... 2017-12-01 12:16:14 +05:30
Kovid Goyal
982a9320c5 Final fixes needed for wayland building
kitty now runs under wayland again
2017-12-01 12:16:13 +05:30
Kovid Goyal
47dec2c2e9 Dynamic detection of wayland 2017-12-01 12:16:13 +05:30
Kovid Goyal
eb8f4e0b3c isosx -> is_macos 2017-12-01 12:16:13 +05:30
Kovid Goyal
85fcd51ea3 Enable building of glfw-wayland backend 2017-12-01 12:16:13 +05:30
Kovid Goyal
9ec6cf721f Update compilation database even after failed builds 2017-12-01 12:16:13 +05:30
Kovid Goyal
bcd4c64b8a Key compilation database by output as well 2017-12-01 12:16:13 +05:30
Kovid Goyal
3b0d8ec500 Nicer error when pkg-config fails 2017-12-01 12:16:13 +05:30
Kovid Goyal
73ce2ccb47 remove unused header 2017-12-01 12:16:13 +05:30
Kovid Goyal
a5078afd1e Move the bell implementation into glfw 2017-12-01 12:16:13 +05:30
Kovid Goyal
32a6dd2aa1 Add a command line switch to set the name part of WM_CLASS independently 2017-12-01 12:16:13 +05:30
Kovid Goyal
02884c5045 Debounce audio bells 2017-12-01 12:16:12 +05:30
Kovid Goyal
25d7668b70 Add an option to control the audio bell volume on X11 2017-12-01 12:16:12 +05:30
Kovid Goyal
2ff39c1578 DRYer 2017-12-01 12:16:12 +05:30
Kovid Goyal
a11d6466c6 Update vendored glfw 2017-12-01 12:16:12 +05:30
Kovid Goyal
df56080303 Fix building on travis/macOS libunistring detection 2017-12-01 12:16:12 +05:30
Kovid Goyal
4d1eb1f729 Install libxkbcommon on Travis 2017-12-01 12:16:12 +05:30
Kovid Goyal
ec06dd7460 Add a --verbose build flag 2017-12-01 12:16:12 +05:30
Kovid Goyal
163ce2a066 Update CHANGELOG 2017-12-01 12:16:12 +05:30
Kovid Goyal
058c1bec10 Workaround for new windows not getting focus events on macOS 2017-12-01 12:16:12 +05:30
Kovid Goyal
ba40bf5e6f remove no longer needed code 2017-12-01 12:16:12 +05:30
Kovid Goyal
d457abdee4 Prevent glfw from doing stupid stuff on cocoa 2017-12-01 12:16:11 +05:30
Kovid Goyal
3773aaa8a1 Get it building on macOS 2017-12-01 12:16:11 +05:30
Kovid Goyal
cfc99baac4 Get rid of ctypes based loading of libglfw/libX11 2017-12-01 12:15:36 +05:30
Kovid Goyal
b6be6ee1e7 Explicitly set expandtab 2017-12-01 12:15:36 +05:30
Kovid Goyal
dfd8a69cf2 Build kitty against bundled glfw 2017-12-01 12:15:36 +05:30
Kovid Goyal
9307486254 Initial import of glfw 2017-12-01 12:15:36 +05:30
Kovid Goyal
6a627cca9e A spot of refactoring 2017-12-01 12:15:36 +05:30
Kovid Goyal
480f4bf44e Build script should not fail on python without threading 2017-12-01 12:15:36 +05:30
Kovid Goyal
b5b2f11b18 Enable parallel builds 2017-12-01 12:15:36 +05:30
Kovid Goyal
ee232fb08c API needed for kitty-bar 2017-12-01 12:15:36 +05:30
Kovid Goyal
ef7dcbf365 API to create initially hidden windows 2017-12-01 12:15:36 +05:30
Kovid Goyal
3e511d217b Pass the window class and size settings when creating a grouped window 2017-12-01 12:15:36 +05:30
Kovid Goyal
b08f4ab593 Use startup notifications in single instance mode 2017-12-01 12:15:35 +05:30
Kovid Goyal
fa1ae39480 Update Changelog 2017-12-01 12:15:35 +05:30
Kovid Goyal
96483a0e92 Finish single_instance implementation 2017-12-01 12:15:35 +05:30
Kovid Goyal
7deb68de61 Get IPC working 2017-12-01 12:15:35 +05:30
Kovid Goyal
bf09c33b99 Move option_parser into its own module 2017-12-01 12:15:35 +05:30
Kovid Goyal
9e5882c9fb Code to handle messages from peers 2017-12-01 12:15:35 +05:30
Kovid Goyal
c5d17934e4 Function to establish IPC communication 2017-12-01 12:15:35 +05:30
Kovid Goyal
c8c1a3618c Get the user cache dir path on macOS 2017-12-01 12:15:35 +05:30
Kovid Goyal
593b4c5a46 Use sigaction() rather than signal() to register signal handlers 2017-12-01 12:15:35 +05:30
Kovid Goyal
d7ea28f8e7 Fix sprite texture not initially bound for new OSWindow 2017-12-01 12:15:35 +05:30
Kovid Goyal
c4bcda80e9 Fix removing OSWindow breaking pointer references in glfw 2017-12-01 12:15:34 +05:30
Kovid Goyal
528573ac80 Make sure window context is correct for all remove_vao calls 2017-12-01 12:15:34 +05:30
Kovid Goyal
dba067d875 Ensure correct OpenGL ctx in effect when creating a new window 2017-12-01 12:15:34 +05:30
Kovid Goyal
5a5d27077c Shortcut to open new OSWindow
Note that rendering is still pretty buggy with multiple windows.
2017-12-01 12:15:34 +05:30
Kovid Goyal
c145dfc832 Forgot to destroy glfw window when closing OSWindow
Also fix double decref of OSWindow->window_title
2017-12-01 12:15:34 +05:30
Kovid Goyal
407431adc8 Debounce resize requests 2017-12-01 12:15:34 +05:30
Kovid Goyal
8e3b5ddb0b Also show mouse cursor when window gains focus 2017-12-01 12:15:34 +05:30
Kovid Goyal
e1b77f0a59 Ensure cleanup when closing OSWindow 2017-12-01 12:15:34 +05:30
Kovid Goyal
81a465f7bc ... 2017-12-01 12:15:34 +05:30
Kovid Goyal
0bec6ea15d Fix mem leak when closing tabs introduced by move to OSWindow 2017-12-01 12:15:34 +05:30
Kovid Goyal
2b988b01c6 Get rid of the needs_render tracking as it was too fragile. 2017-12-01 12:15:34 +05:30
Kovid Goyal
ab604fb149 more bugs 2017-12-01 12:15:33 +05:30
Kovid Goyal
d344c391fd ... 2017-12-01 12:15:33 +05:30
Kovid Goyal
449c1ba5d7 Ensure OSWindow references are not stale 2017-12-01 12:15:33 +05:30
Kovid Goyal
12340e4c60 Ensure window object is fully initialized in callbacks 2017-12-01 12:15:33 +05:30
Kovid Goyal
95aad91a49 ... 2017-12-01 12:15:33 +05:30
Kovid Goyal
c3f5b20ca7 more bugs 2017-12-01 12:15:33 +05:30
Kovid Goyal
f8c7a7a690 more bug fixes 2017-12-01 12:15:33 +05:30
Kovid Goyal
c5649df971 Fix various bugs introduced by the refactoring to support OSWindow 2017-12-01 12:15:33 +05:30
Kovid Goyal
9cedefb50c Port tab_manager and miscellaneous cleanups 2017-12-01 12:15:33 +05:30
Kovid Goyal
96f8f8c79d Remove unused code 2017-12-01 12:15:33 +05:30
Kovid Goyal
889d5b07a6 Pass os_window_id in activate_tab_at 2017-12-01 12:15:32 +05:30
Kovid Goyal
82d17c8a59 DRYer 2017-12-01 12:15:32 +05:30
Kovid Goyal
7ba3aa0c6f ... 2017-12-01 12:15:32 +05:30
Kovid Goyal
598f08e222 Avoid unneccessary roundtrip through python to create VAOs 2017-12-01 12:15:32 +05:30
Kovid Goyal
625798220a ... 2017-12-01 12:15:32 +05:30
Kovid Goyal
2f06c0f721 Remove last view uses of viewport_size and cell_size in python
Also move counters into C
2017-12-01 12:15:32 +05:30
Kovid Goyal
0ec793e8bc Finish porting of borders and layout 2017-12-01 12:15:32 +05:30
Kovid Goyal
e30f88d382 ... 2017-12-01 12:15:32 +05:30
Kovid Goyal
49be779982 Port drawing of borders 2017-12-01 12:15:32 +05:30
Kovid Goyal
2ac8ad39c9 Implement destruction of OS windows 2017-12-01 12:15:32 +05:30
Kovid Goyal
e11a50ae83 Work on migrating the code needed for application startup 2017-12-01 12:15:32 +05:30
Kovid Goyal
eecd0c8d9a Function to remove OSWindows 2017-12-01 12:15:31 +05:30
Kovid Goyal
974950e7de Allocate window management structures on the heap 2017-12-01 12:15:31 +05:30
Kovid Goyal
47446975ac Fix spelling of var name 2017-12-01 12:15:31 +05:30
Kovid Goyal
c69145b6bc Port state.c and all code that calls into it 2017-12-01 12:15:31 +05:30
Kovid Goyal
141a08ec7c Migrate child-monitor.c to use OSWindow 2017-12-01 12:15:31 +05:30
Kovid Goyal
f0003f223a Start work on multi-window support
Port the glfw.c module and various bits of code that depend on it.
2017-12-01 12:15:31 +05:30
Kovid Goyal
a4fe97c88c Apparently libunistring is now already install by brew 2017-12-01 12:08:28 +05:30
Kovid Goyal
cc23515a35 Make the publish script a little smarter 2017-12-01 10:31:50 +05:30
Kovid Goyal
8d2a720fb9 version 0.5.1 2017-12-01 10:15:18 +05:30
Kovid Goyal
9ed980a511 More 32bit fixes 2017-11-30 00:02:44 +05:30
Kovid Goyal
1365eafce5 ... 2017-11-29 18:15:12 +05:30
Kovid Goyal
07b70f8c95 Image display: Fix displaying images taller than two screen heights not scrolling properly
Fixes #194
2017-11-29 18:12:22 +05:30
Kovid Goyal
f16bf2a136 ... 2017-11-29 08:32:00 +05:30
Kovid Goyal
0f2bcfabb3 Sanity check when moving baseline for line height adjustment 2017-11-29 08:30:34 +05:30
Kovid Goyal
d3e8c616b0 Fix text not vertically centered when adjusting line height
Fixes #193
2017-11-29 08:27:28 +05:30
Kovid Goyal
99888996a0 Implement special rendering for unicode block characters
Fixes #184
2017-11-26 21:29:00 +05:30
Kovid Goyal
4c94e16936 Refactor the box drawing showcase code
Make it work with the new font render infrastructure
2017-11-26 19:53:25 +05:30
Kovid Goyal
235f3940f2 DRYer 2017-11-26 18:10:34 +05:30
Kovid Goyal
e86c2f2000 Fix shift+up/down not generating correct escape codes
Fixes #186
2017-11-26 17:34:34 +05:30
Kovid Goyal
65b212fa1b Add a config option to control the line thickness for box drawing characters
Fixes #183
2017-11-26 11:24:27 +05:30
Kovid Goyal
4b0ff03868 Increase max ligature length to 9 chars
Fixes #182
2017-11-26 10:33:57 +05:30
Kovid Goyal
8961eaaa9d Fix compilation error on 32bot systems
Fixes #185
2017-11-26 08:22:14 +05:30
Kovid Goyal
356722b9a6 Fix build failure on systems with __OPTIMZE__ defined
Fixes #181
2017-11-24 22:42:56 +05:30
Kovid Goyal
89e5ae28bb Dont fail to start if the user's /etc/passwd is missing an entry for the current uid
Appears to happen on some nix systems. Fixes #178
2017-11-23 00:40:21 +05:30
Kovid Goyal
b40e1e6492 Decrease minimum fonts size to 4pt 2017-11-21 07:13:17 +05:30
Kovid Goyal
4dc6918b13 Get rid of the send_text_map code
Just transform send_text directives in the config file to map
directives.
2017-11-19 08:56:34 +05:30
Kovid Goyal
1d45a831ef version 0.5.0 2017-11-19 07:59:01 +05:30
Kovid Goyal
32920fee5b Fix super imposing of glyphs generating fringes 2017-11-19 07:56:35 +05:30
Kovid Goyal
121de41930 Make send_text a normal keybaord shortcut action
Uses the new support for arguments to shortcut actions. Fixes #173
2017-11-17 01:27:26 +05:30
Kovid Goyal
a553107da8 Update README 2017-11-16 10:46:42 +05:30
Kovid Goyal
8cad6ae9d6 Fix leak-on-exit from libstartup-notification 2017-11-16 10:29:21 +05:30
Kovid Goyal
ed60e7cf19 Fix #172 2017-11-16 07:47:08 +05:30
Kovid Goyal
a9db9f8874 ... 2017-11-14 12:41:09 +05:30
Kovid Goyal
b9b2570369 Reduce brew install harfbuzz time on travis 2017-11-14 12:01:06 +05:30
Kovid Goyal
c4f61de3fe Add a couple more targets to the makefile 2017-11-14 09:48:59 +05:30
Kovid Goyal
523c9ff0d1 Make incremental building the default 2017-11-14 09:47:08 +05:30
Kovid Goyal
a02fd8411a Generate a compilation database, useful for llvm tooling 2017-11-14 09:31:23 +05:30
Kovid Goyal
98d8d6b915 Update CHANGELOG 2017-11-13 19:48:06 +05:30
Kovid Goyal
2b87e1f601 Fix #170 2017-11-13 19:47:54 +05:30
Kovid Goyal
084fb23930 Forgot to clear hash table roots after deleting
Doesn't matter in normal usage, but causes tests to fail.
2017-11-13 16:12:28 +05:30
Kovid Goyal
244840255b Remove unused function 2017-11-13 16:03:44 +05:30
Kovid Goyal
94c11af7c8 Refactor the font management code
Use a hash table for special glyph status caching
Manage (almost) all global state with a single object
Allocate all fonts on the heap
Fix the use-after-free for fallback fonts
2017-11-13 15:53:34 +05:30
Kovid Goyal
26e6716f67 A test that reliably triggers the current failure 2017-11-13 15:30:30 +05:30
Kovid Goyal
aef8b4ae67 Allow re-use of ensure_space_for macro 2017-11-13 15:29:52 +05:30
Kovid Goyal
a97ba08cbb Fix asan test failure 2017-11-13 09:31:48 +05:30
Kovid Goyal
ddc327b772 Prevent DoS attacks via requesting too many fallback fonts 2017-11-13 08:40:47 +05:30
Kovid Goyal
a70f6405ac Allocate fallback fonts on the heap
The size of a font is quite large ~ 100KB so it does not make sense to
store their data statically.
2017-11-13 08:39:30 +05:30
Kovid Goyal
bf0ad30d17 DRYer 2017-11-13 07:30:35 +05:30
Kovid Goyal
6fbe52acf4 ... 2017-11-13 07:13:42 +05:30
Kovid Goyal
9fccc38382 Better fix for not using the unsafe to break flag
Recognize special glyphs by comparing the index to the glyph for the
codepoint in the font. Cannot rely on glyph width as many glyphs have
zero width. For example the glyph for space characters.
2017-11-13 07:03:58 +05:30
Kovid Goyal
339c0d2980 Put back consumed API 2017-11-12 23:43:22 +05:30
Kovid Goyal
336857a106 A more general cp->gid API 2017-11-12 23:43:21 +05:30
Kovid Goyal
d01e5f72fc Use a cache for dummy glyph lookups 2017-11-12 23:43:21 +05:30
Kovid Goyal
5c6be7f637 Insulate emoji test from system wcwidth 2017-11-12 23:43:21 +05:30
Kovid Goyal
088087df73 Use only cluster numbers and glyph sizes for grouping glyphs into cells
See https://github.com/behdad/harfbuzz/issues/615 for discussion
2017-11-12 23:43:21 +05:30
Kovid Goyal
0bd093ec2e Also fix mouse URXVT_PROTOCOL
Fixes #169
2017-11-12 22:11:20 +05:30
Kovid Goyal
4613e161ce Fix incorrect encoding for mouse events in the UTF8_PROTOCOL
Fixes #167
2017-11-12 22:05:01 +05:30
Kovid Goyal
dad9444db0 Dont crash if harfbuzz return null info or positions pointers 2017-11-12 17:18:49 +05:30
Kovid Goyal
dd0080d3ce Fix #168 2017-11-12 16:14:59 +05:30
Kovid Goyal
6b9303ba7d Dont store standard cursors on the window object 2017-11-12 12:42:09 +05:30
Kovid Goyal
eb32423fb6 oops 2017-11-12 12:33:44 +05:30
Kovid Goyal
9bb2a05a9b Update list of major features 2017-11-12 11:49:42 +05:30
Kovid Goyal
653fc0dd7e Fix #50 2017-11-12 11:42:50 +05:30
Kovid Goyal
cee6ef9941 Center multi-cell glyph runs 2017-11-12 11:04:52 +05:30
Kovid Goyal
67a37f1f41 Adjust the point size of fallback and symbol fonts so that their heights match the current cell height 2017-11-12 10:30:57 +05:30
Kovid Goyal
604e82fd65 oops 2017-11-11 21:15:19 +05:30
Kovid Goyal
5f4e003bed Add a ligature shaping test 2017-11-11 20:55:53 +05:30
Kovid Goyal
53e9f35c1f Add test for harfbuzz shaping 2017-11-11 18:47:34 +05:30
Kovid Goyal
c56a2ed055 Ensure that harfbuzz always uses the OpenType shaper 2017-11-11 18:25:25 +05:30
Kovid Goyal
e5d411b80d Refactor font code
DRYer with global state stored in fewer places. And only round-tripping
through python for font selection, not face creation.
2017-11-11 18:14:22 +05:30
Kovid Goyal
98e93cb4bd Workaround for broken CTFontCreateForString 2017-11-11 10:16:43 +05:30
Kovid Goyal
f5040532c5 Ensure combining chars are zero-width regardless of wcwidth implementation 2017-11-11 09:29:28 +05:30
Kovid Goyal
447a2fe8cf ... 2017-11-11 09:20:34 +05:30
Kovid Goyal
a14defbab7 Change the showcase fonts 2017-11-11 09:13:04 +05:30
Kovid Goyal
3592f82e4f Implement fallback fonts in CoreText 2017-11-11 08:08:03 +05:30
Kovid Goyal
4edfa9f4fd Implement loading of bitmap fonts via FreeType
Needed for some fallback fonts such as Apple Color Emoji
2017-11-11 08:07:18 +05:30
Kovid Goyal
51fe1e4dab ... 2017-11-11 07:12:50 +05:30
Kovid Goyal
2df9f3500c Build with --debug in update-on-ox 2017-11-11 07:12:21 +05:30
Kovid Goyal
289cfe7584 Fix bold-italic variant not being auto-selected on macOS 2017-11-10 22:06:11 +05:30
Kovid Goyal
b603d7abb7 Ensure underline_thickness is not zero 2017-11-10 21:46:50 +05:30
Kovid Goyal
3437433ed4 ... 2017-11-10 17:43:47 +05:30
Kovid Goyal
cccacfdf7c Restore Apple's line height fudge factor on macOS 2017-11-10 17:38:36 +05:30
Kovid Goyal
c6fa0503af Simplify font_units_to_pixels
Make use of the precalculated scaling value in the FT Face metrics
object
2017-11-10 17:23:28 +05:30
Kovid Goyal
579933ac27 ... 2017-11-10 15:55:59 +05:30
Kovid Goyal
541f389a06 Work on using FreeType to render on macOS as well 2017-11-10 15:39:53 +05:30
Kovid Goyal
d2654db6f0 oops 2017-11-10 14:57:44 +05:30
Kovid Goyal
c2b2833a37 API to load FreeType font from path and psname 2017-11-10 14:50:15 +05:30
Kovid Goyal
b0fffad0c2 API to create FreeType face from in memory data 2017-11-10 14:30:54 +05:30
Kovid Goyal
774956053a Allow storing arbitrary data on FreeType Face objects 2017-11-10 14:20:20 +05:30
Kovid Goyal
5c582f7639 Start work on harfbuzz rendering on macs 2017-11-10 12:52:54 +05:30
Kovid Goyal
ccc0433fa1 ... 2017-11-10 11:26:58 +05:30
Kovid Goyal
43bf056f09 Add a command to list fonts 2017-11-10 11:02:32 +05:30
Kovid Goyal
1d7b650fd0 ... 2017-11-10 10:30:34 +05:30
Kovid Goyal
fefe6c9024 Use fc-list instead of fc-match to select fonts
This is because there is no way to force fc-match to return a monospace
font. So if the user specifies a non-existent font we end up with some
non-monospaced font, which looks terrible.

Also, this makes the font selection logic or macOS and Linux similar.
2017-11-10 10:15:37 +05:30
Kovid Goyal
b58e900806 Call prerender() in rendering tests setup 2017-11-10 08:30:35 +05:30
Kovid Goyal
ec58777d01 Fix compilation against old versions of fontconfig 2017-11-10 08:28:44 +05:30
Kovid Goyal
7a0b649cbd Fix resizing of fonts 2017-11-10 07:34:52 +05:30
Kovid Goyal
e15bc71930 Code to list fontconfig fonts 2017-11-09 20:53:10 +05:30
Kovid Goyal
6d02e884d8 oops 2017-11-09 17:30:30 +05:30
Kovid Goyal
6d7546aa8c pre-rendering must happen after layout 2017-11-09 17:11:37 +05:30
Kovid Goyal
ace91f04af More appropriate location for function definition 2017-11-09 17:04:31 +05:30
Kovid Goyal
934d21ac30 Wire up a few remaining pieces 2017-11-09 16:55:46 +05:30
Kovid Goyal
79d8c04b00 Hook up render_line 2017-11-09 16:55:45 +05:30
Kovid Goyal
6c838bbc28 Implement dirty line tracking 2017-11-09 16:55:45 +05:30
Kovid Goyal
0277be5856 Track line dirty status in the line buffer 2017-11-09 16:55:45 +05:30
Kovid Goyal
71dcf13edf Fix compiler warning 2017-11-09 16:55:45 +05:30
Kovid Goyal
bc0a77ee31 Only detect support once when testing rendering 2017-11-09 16:55:45 +05:30
Kovid Goyal
758d315b8e Better fix for test 2017-11-09 16:55:45 +05:30
Kovid Goyal
3ec64a17f8 Dont call the font change machinery when the actual size has not changed 2017-11-09 16:55:45 +05:30
Kovid Goyal
dc7d705c87 Runa simplified version of the font rendering test on macOS 2017-11-09 16:55:45 +05:30
Kovid Goyal
6c98b676bb Fix crash on macOS when changing font size 2017-11-09 16:55:45 +05:30
Kovid Goyal
dd6108de5b DRYer 2017-11-09 16:55:44 +05:30
Kovid Goyal
aa1b94aed0 Ensure descriptor is always set for coretext font objects 2017-11-09 16:55:44 +05:30
Kovid Goyal
75e1b30fc1 DRYer 2017-11-09 16:55:44 +05:30
Kovid Goyal
a8bca1c119 Skip the rendering test on macOS
macOS is underpowered junk.
2017-11-09 16:55:44 +05:30
Kovid Goyal
d05ea312ef Fix crash on macOS when failing to get font_descriptor 2017-11-09 16:55:44 +05:30
Kovid Goyal
e72f153a66 Avoid unneccessary exception when failling to find a fallback font 2017-11-09 16:55:44 +05:30
Kovid Goyal
da8bf5adc7 Add rendering tests 2017-11-09 16:55:44 +05:30
Kovid Goyal
ce0e5a893f Make the showcase output a little nicer 2017-11-09 16:55:44 +05:30
Kovid Goyal
c8b7b49d56 Ensure underline_position is viable 2017-11-09 16:55:44 +05:30
Kovid Goyal
9842a47f85 Install an up-to-date version of harfbuzz on travis 2017-11-09 16:55:44 +05:30
Kovid Goyal
1db4286a12 Fix rendering of wide chars 2017-11-09 16:55:43 +05:30
Kovid Goyal
4234a9d963 Sigh apparently unsafe break is not enough 2017-11-09 16:55:43 +05:30
Kovid Goyal
6da465d7d7 Correct the x_offset calculation 2017-11-09 16:55:43 +05:30
Kovid Goyal
a1cb01b3b2 Fix grouping of combining char glyphs 2017-11-09 16:55:43 +05:30
Kovid Goyal
6920d37042 Rendering ligatures now works 2017-11-09 16:55:43 +05:30
Kovid Goyal
1dcdf9534b ... 2017-11-09 16:55:43 +05:30
Kovid Goyal
f9c21b1cb3 Sigh, legacy linux distros 2017-11-09 16:55:43 +05:30
Kovid Goyal
58be99a27e Work on rendering ligatures correctly 2017-11-09 16:55:43 +05:30
Kovid Goyal
ae06879193 Mark unused pending implementation 2017-11-09 16:55:43 +05:30
Kovid Goyal
f121773276 Fix fallback fonts not being free'd on exit 2017-11-09 16:55:42 +05:30
Kovid Goyal
4726bcd210 Implement rendering of glyphs from font files in Freetype 2017-11-09 16:55:42 +05:30
Kovid Goyal
891942494f Implement laoding of harfbuz buffer 2017-11-09 16:55:42 +05:30
Kovid Goyal
0b8e8bff16 Infra to display rendered strings as images for testing 2017-11-09 16:55:42 +05:30
Kovid Goyal
898e87aa7b Dont allocate space for dummy fonts
Also move sprite_map test into fonts test module
2017-11-09 16:55:42 +05:30
Kovid Goyal
d153794c05 ... 2017-11-09 16:55:42 +05:30
Kovid Goyal
742c60f37f harfbuzz is now needed on macOS as well 2017-11-09 16:55:42 +05:30
Kovid Goyal
81143e0c7e Test to render all box drawing characters under the sanitizers 2017-11-09 16:55:42 +05:30
Kovid Goyal
7f610f3b4e ... 2017-11-09 16:55:42 +05:30
Kovid Goyal
4ba17df570 Forward declaration of Face_Type needed 2017-11-09 16:55:42 +05:30
Kovid Goyal
00a73e4d12 Fix weird crash with clang asan 2017-11-09 16:55:41 +05:30
Kovid Goyal
6501ee45b6 Forgot to add bi info to sm_faces 2017-11-09 16:55:41 +05:30
Kovid Goyal
b0bee2f1f3 oops 2017-11-09 16:55:41 +05:30
Kovid Goyal
5a044c0320 ... 2017-11-09 16:55:41 +05:30
Kovid Goyal
6a2f964123 ... 2017-11-09 16:55:41 +05:30
Kovid Goyal
0518cabef6 Infrastructure for rendering cells in the test suite 2017-11-09 16:55:41 +05:30
Kovid Goyal
7d7d82a68d Start working on actually rendering lines of text 2017-11-09 16:55:38 +05:30
Kovid Goyal
0c4bb6a0d6 ... 2017-11-09 16:45:45 +05:30
Kovid Goyal
f25d2ea540 Rip out the old sprite update code 2017-11-09 16:45:45 +05:30
Kovid Goyal
38a5e76c50 More work on line based rendering
Should now build on all platforms
2017-11-09 16:45:45 +05:30
Kovid Goyal
d873d11202 Remove unused code 2017-11-09 16:45:45 +05:30
Kovid Goyal
729395c887 Release old hb_font when changing font size 2017-11-09 16:45:44 +05:30
Kovid Goyal
5007a82ea6 Install harfbuzz on travis + brew 2017-11-09 16:45:44 +05:30
Kovid Goyal
83e114d211 Implement new font methods for CoreText 2017-11-09 16:45:44 +05:30
Kovid Goyal
0d92ea72e1 Add harfbuzz includes on macOS as well 2017-11-09 16:45:44 +05:30
Kovid Goyal
646e8dab0a Fix regression in handling zero cells caused by refactoring 2017-11-09 16:45:44 +05:30
Kovid Goyal
8fc9f97c12 ... 2017-11-09 16:45:44 +05:30
Kovid Goyal
3643a78b18 Start work on line based rendering 2017-11-09 16:45:44 +05:30
Kovid Goyal
8431eef970 Get rid of no longer needed GPU function indirection 2017-11-09 16:45:02 +05:30
Kovid Goyal
e8798b5bf2 Fix UBSan not available on OS X clang 2017-11-08 17:50:32 +05:30
Kovid Goyal
9bef53459f Fix application icon not being placed in apps sub-directory in linux bundle 2017-11-08 17:38:34 +05:30
Kovid Goyal
c2f008672c Use clang by default on macOS 2017-11-08 17:30:55 +05:30
Kovid Goyal
216a66ec4c Add some .gitattributes to ignore generated files in difss/lang stats 2017-11-08 17:12:39 +05:30
Kovid Goyal
c1a1b06fe7 Use -Og when building in debug mode 2017-11-08 17:12:35 +05:30
Kovid Goyal
802524a17a Update CHANGELOG 2017-11-08 16:06:58 +05:30
Kovid Goyal
ea4edaaddd Remove glew from build script 2017-11-08 16:02:35 +05:30
Kovid Goyal
7941ac1810 Remove no longer needed mac specific OpenGL extensions check 2017-11-08 15:59:55 +05:30
Kovid Goyal
de6967df0d Dont strip symbols when updating on ox 2017-11-08 15:56:09 +05:30
Kovid Goyal
ceef207812 Fix compilation with clang 2017-11-08 15:43:59 +05:30
Kovid Goyal
7ed272e971 Use the glad provided facility for debugging OpenGL 2017-11-08 15:40:07 +05:30
Kovid Goyal
6362499fc2 Switch to using glad instead of glew 2017-11-08 15:15:25 +05:30
Kovid Goyal
ff528604dd Add a akeyboard shortcut to toggle full-screen mode 2017-11-08 11:21:54 +05:30
Kovid Goyal
505ae90fd7 macOS: Add an setting to have the option key not behave as alt 2017-11-08 09:14:19 +05:30
Kovid Goyal
1f9acf99b0 Match extended keyboard protocol modifier bitmask with the CSIu protocol from xterm 2017-11-08 08:24:15 +05:30
Kovid Goyal
5392ceea7d Update CHANGELOG 2017-11-07 23:20:19 +05:30
Kovid Goyal
ba1883c1de X11: Add support for startup notifications
Prevents busy cursor in i3 root window after launching and quitting
kitty immediately.
2017-11-07 23:19:15 +05:30
Kovid Goyal
3a81b186b0 Strip bracketed paste end sequence when pasting 2017-11-07 22:16:35 +05:30
Kovid Goyal
204b6fa3e8 Use nested switch statements for key lookup
Replace giant key look up table with nested switch statements.
A little slower, but reduces memory consumption and makes it easier to
add new keyboard modes in the future, if needed. Key lookup was not a
performance bottleneck, in any case.
2017-11-07 20:58:34 +05:30
Kovid Goyal
f3c99546d7 Update CHANGELOG 2017-11-07 17:20:45 +05:30
Kovid Goyal
f137ea7094 Fix handling of alt (option) key on macOS
It now works just as in linux. i.e. alt+a sends <esc>a to the client.
No longer needs turning off alt to generate unicode at the OS level.
2017-11-07 16:19:37 +05:30
Kovid Goyal
88df0890ae Fix crash when displaying more than 64 images in a single session
Also DRYer
2017-11-07 13:34:31 +05:30
Kovid Goyal
aaf593d2df Add a few bounds checks 2017-11-05 10:27:10 +05:30
Kovid Goyal
a614fe615f Improve error reporting of incomplete SGR codes 2017-11-05 10:17:40 +05:30
Kovid Goyal
3cb74a25ba Fix handling of empty SGR code
Was broken by refactoring to support colons in SGR codes
2017-11-05 10:06:33 +05:30
Kovid Goyal
c0114d5e4e DRYer 2017-11-05 09:22:15 +05:30
Kovid Goyal
e90aaa8470 Add support for colons in SGR codes 2017-11-05 08:47:21 +05:30
Kovid Goyal
c762f6199b ... 2017-11-05 08:43:02 +05:30
Kovid Goyal
7119c04c81 ... 2017-11-03 10:22:36 +05:30
Kovid Goyal
18dde7b26c ... 2017-11-03 10:01:52 +05:30
Kovid Goyal
013fd31493 Output more details about unknown CSI codes 2017-11-02 20:48:30 +05:30
Kovid Goyal
490310a9f1 Drop obsolete dependency on xrdb 2017-11-02 11:07:33 +05:30
Kovid Goyal
d900811a7b Merge branch 'subpixel' of https://github.com/lxcode/kitty 2017-11-02 08:25:36 +05:30
Kovid Goyal
b06a09c01a Merge branch 'osxdpi' of https://github.com/lxcode/kitty 2017-11-02 08:24:56 +05:30
lxcode
81f14edb49 Enable subpixel quantization and positioning 2017-11-01 15:37:43 -07:00
lxcode
d39ba72591 Wrong indent level 2017-11-01 15:23:58 -07:00
Kovid Goyal
f04fbde6ca Free argvw in asan-launcher 2017-11-01 15:00:52 +05:30
Kovid Goyal
d9ff3bce72 Cleanup compiler flags a little 2017-11-01 14:35:57 +05:30
Kovid Goyal
21ed07d7ce Ensure python type objects are declared in onlya single unit 2017-11-01 13:14:50 +05:30
Kovid Goyal
6cbd1d1727 Move the tabbar destroy logic into the tab bar class 2017-11-01 12:49:00 +05:30
Kovid Goyal
27701351e1 Fix double-free at exit if in alternate screen mode 2017-11-01 12:16:30 +05:30
Kovid Goyal
6370dccb1a ASAN build fixes 2017-11-01 12:12:15 +05:30
Kovid Goyal
cc77d06ec7 ... 2017-11-01 12:05:33 +05:30
Kovid Goyal
04a61d0e21 Convert test-launcher into a generic asan-launcher so that it can be used to run kitty as well 2017-11-01 12:03:59 +05:30
Kovid Goyal
96f85b187e Handle request to render zerowidth text more gracefully 2017-11-01 11:16:45 +05:30
Kovid Goyal
27a1f27e59 Fix crash caused if a unicode combing character is sent before any text 2017-11-01 11:12:22 +05:30
Kovid Goyal
4098b33bb7 Handle old harfbuzz versions that dont have hb_ft_font_changed 2017-10-30 10:53:52 +05:30
Kovid Goyal
657d0c4e2d Update harfbuzz font when size of font is changed 2017-10-30 10:20:10 +05:30
Kovid Goyal
b0663c1a3c ... 2017-10-28 13:58:43 +05:30
Kovid Goyal
20ff9ff977 Handle negative x-bearing 2017-10-28 13:54:56 +05:30
Kovid Goyal
ed6049b4be Micro-optimization 2017-10-28 13:45:52 +05:30
Kovid Goyal
76d6d5f94b Update Changelog 2017-10-28 10:22:53 +05:30
Kovid Goyal
d8629a2d5b DRYer
Reuse most of the code from the draw_complex_glyph code path for drawing
simple glyphs. Avoids overhead of harfbuzz for simple glyphs.
2017-10-28 10:17:27 +05:30
Kovid Goyal
0652fa1696 Finish up harfbuzz based rendering 2017-10-28 09:33:43 +05:30
Kovid Goyal
a5e6ab2bee More work on complex glyph rendering 2017-10-27 18:17:39 +05:30
Kovid Goyal
b5d105186c Use width instead of pitch 2017-10-27 14:25:18 +05:30
Kovid Goyal
e274b809e2 oops 2017-10-27 14:11:46 +05:30
Kovid Goyal
a2fdea1a98 ... 2017-10-27 13:06:41 +05:30
Kovid Goyal
855d91d9dd Fix composition of bitmaps 2017-10-27 12:50:49 +05:30
Kovid Goyal
8a049039ef More work on rendering complex glyphs 2017-10-27 12:42:12 +05:30
Kovid Goyal
4bea6b7ad9 More work on complex glyph rendering 2017-10-27 11:19:57 +05:30
Kovid Goyal
5b0e2311e9 Store hinting flags on the Face object 2017-10-27 11:19:57 +05:30
Kovid Goyal
25c6735a5f ... 2017-10-27 11:19:57 +05:30
Kovid Goyal
1356bcbb9a Let harfbuzz compile on Travis 2017-10-27 11:19:57 +05:30
Kovid Goyal
c841106902 Allow querying fontconfig for multiple characters 2017-10-27 11:19:57 +05:30
Kovid Goyal
91963095d0 More work on rendering complex glyphs 2017-10-27 11:19:57 +05:30
Kovid Goyal
692bdd3ad5 Allow testing of rendering combined glyphs 2017-10-27 11:19:57 +05:30
Kovid Goyal
e6f758b986 Simplify line_text_at() 2017-10-27 11:19:57 +05:30
Kovid Goyal
89d5387a52 Link against harfbuzz 2017-10-27 11:19:57 +05:30
Kovid Goyal
2b9034759a ... 2017-10-27 10:29:25 +05:30
Kovid Goyal
b4d824e165 Use the glfw 3.3 content scale API to get DPI on X11/wayland 2017-10-27 10:27:42 +05:30
Kovid Goyal
39bc0cd8c5 Wrap the glfw 3.3 content scale API 2017-10-27 10:17:33 +05:30
Kovid Goyal
a2b2e767c1 Merge branch 'patch-1' of https://github.com/tex/kitty 2017-10-26 16:24:32 +05:30
Milan Svoboda
da2d334b7a Add NixOs / nixpkgs installationinfo 2017-10-26 12:10:01 +02:00
Kovid Goyal
05363ba501 ... 2017-10-25 14:48:28 +05:30
Kovid Goyal
e43a26d64c Better error message when GLEW initialization fails 2017-10-25 14:32:44 +05:30
Kovid Goyal
c5c8a18c99 Script to easily update kitty on my macOS test machine 2017-10-24 10:08:03 +05:30
Kovid Goyal
2f5b110c41 Implement an option to have focus follow the mouse
Fixes #156
2017-10-24 09:29:28 +05:30
Kovid Goyal
2443d76ac3 Apparently pep8 now just does not let you use the name l
This is one of the most hilarious bugs in pep8 I have come across
2017-10-23 17:40:53 +05:30
Kovid Goyal
8b54df31ef Fix new pep8 ambiguous name warning 2017-10-23 17:33:57 +05:30
Kovid Goyal
4e7b957cc7 version 0.4.2 2017-10-23 17:11:04 +05:30
Kovid Goyal
b1424cc4c7 ... 2017-10-23 17:09:52 +05:30
Kovid Goyal
be7d0e2016 forgot to remove debugging printf 2017-10-23 16:46:57 +05:30
Kovid Goyal
7e8d509fdd Fix #153 2017-10-23 16:45:17 +05:30
Kovid Goyal
8672a29503 Use a C based SIGCHLD handler
Running python code in signal handlers makes me nervous
2017-10-23 12:42:03 +05:30
Kovid Goyal
32a1886b31 version 0.4.1 2017-10-23 11:19:30 +05:30
Kovid Goyal
70bfe8589f Better fix for #152 2017-10-23 11:12:31 +05:30
Kovid Goyal
4f3d71d4ee Fix a regression that broke setting custom key mappings
Fixes #152
2017-10-23 11:04:02 +05:30
Kovid Goyal
0df0fd6a0b Handle EINTR in reap_zombies 2017-10-22 19:29:13 +05:30
Kovid Goyal
2b9198866a ... 2017-10-22 19:25:51 +05:30
Kovid Goyal
6350652009 Reap zombies in a signal handler
Avoids relying on jernel behavior, which may not be portable across all
unices
2017-10-22 19:13:13 +05:30
Kovid Goyal
d239db8492 Simply reaping of dead processes
Let the kernel do the reaping, since we do not care about the exit code
anyway. This should also fix #151.
2017-10-22 17:42:49 +05:30
Kovid Goyal
bdb6723564 Remove unused code 2017-10-22 17:13:38 +05:30
Kovid Goyal
d6bf5aa011 Remove unused code 2017-10-22 17:13:11 +05:30
Kovid Goyal
b5c4fbb42b ... 2017-10-22 17:11:58 +05:30
Kovid Goyal
1276bd6f5d Simply code to query xrdb for Xft.dpi 2017-10-22 17:09:30 +05:30
Kovid Goyal
be6e41c400 version 0.4.0 2017-10-22 09:48:43 +05:30
Kovid Goyal
a9e26952e9 ... 2017-10-22 09:29:19 +05:30
Kovid Goyal
348cdf5d5d Expose wcwidth to the python api 2017-10-22 09:22:32 +05:30
Kovid Goyal
a527cc88f3 ... 2017-10-21 14:03:48 +05:30
Kovid Goyal
17cfd98545 ... 2017-10-21 13:46:19 +05:30
Kovid Goyal
09c723380c Refactoring to allow using kitty in other projects 2017-10-21 12:16:46 +05:30
Kovid Goyal
ff35bd61a8 API to easily get primary monitor size from python 2017-10-21 10:10:57 +05:30
Kovid Goyal
eb5fe234f4 API to easily render a Screen object from python 2017-10-21 10:04:56 +05:30
Kovid Goyal
113494b4c6 Re-organize a few blurbs 2017-10-20 18:24:13 +05:30
Kovid Goyal
b7e8bd2faf Fix error when using @arg for stdin and no match found 2017-10-20 18:02:39 +05:30
Kovid Goyal
aaf94b61ed ... 2017-10-20 18:00:28 +05:30
Kovid Goyal
9a1b85081e Allow creating shortcuts to run arbitrary programs in new windows/tabs 2017-10-20 17:49:52 +05:30
Kovid Goyal
626847f2f5 Document specifying a different program for pass_selection_to_program 2017-10-20 15:43:09 +05:30
Kovid Goyal
6b8d38e4b9 ... 2017-10-20 13:46:50 +05:30
Kovid Goyal
227d21184a Add a new shortcut to pass the current selection to an external program 2017-10-20 13:30:23 +05:30
Kovid Goyal
f947c2eecb Redirect std streams to devnull when opening URL 2017-10-20 13:07:48 +05:30
Kovid Goyal
6a42a510bf ... 2017-10-20 12:38:26 +05:30
Kovid Goyal
efc8b898f8 Allow combining multiple independent actions into a single shortcut
Fixes #128
2017-10-20 12:31:36 +05:30
Kovid Goyal
e8a1ada5bf Allow passing arguments to functions mapped to shortcuts 2017-10-20 11:22:43 +05:30
Kovid Goyal
73b6cc433b ... 2017-10-20 11:15:33 +05:30
Kovid Goyal
4f6084c9f2 Use /proc/sef instead of /proc/getpid() 2017-10-20 10:57:06 +05:30
Kovid Goyal
6c9615df0d ... 2017-10-18 14:03:05 +05:30
Kovid Goyal
073c330800 Better wayland detection 2017-10-18 14:02:12 +05:30
Kovid Goyal
e558880e8f Load glfw primary selection functions dynamically
Allows kitty to run on wayland. Also dont try to set the window
icon on wayland.
2017-10-18 12:46:32 +05:30
Kovid Goyal
d4e5bc4141 Fix compilation with glfw 3.2 2017-10-18 09:13:19 +05:30
Kovid Goyal
7f3c808e66 Use glfw 3.3 functions for the primary selection
Allows us to drop the dependency on xsel for systems with glfw 3.3
2017-10-17 21:44:56 +05:30
Kovid Goyal
9322b210ff typo 2017-10-17 21:41:33 +05:30
Kovid Goyal
3d7e8e3e84 typo 2017-10-17 20:43:22 +05:30
Kovid Goyal
40d80c7833 Remove note about macOS versions + graphics 2017-10-17 17:59:45 +05:30
Kovid Goyal
e908484491 Also output error number when glewInit() fails
glewGetErrorString() is incomplete/not maintained
2017-10-17 16:47:38 +05:30
Kovid Goyal
25913f77e0 Add a clean action to setup.py 2017-10-17 13:35:54 +05:30
Kovid Goyal
66803e6873 Workaround to get graphics working on Apple's buggy products
Apparently some macOS OpenGL drivers cannot handle using a VAO with
attributes that have different divisors/apply to different shaders. So
use a separate VAO for graphics rendering. This is a small performance hit,
but is the price of supporting substandard computers.
2017-10-17 12:15:52 +05:30
Kovid Goyal
40722f42d3 ... 2017-10-17 10:18:03 +05:30
Kovid Goyal
192b16e9ff Add Lenna to the test dir so the gr.py script becomes self-sufficient 2017-10-17 10:15:38 +05:30
Kovid Goyal
02dc637ed0 Use the correct blend function for text 2017-10-17 09:51:21 +05:30
Kovid Goyal
2aa29f1873 typo 2017-10-16 22:05:29 +05:30
Kovid Goyal
199d5b34a4 Add note about needing High Sierra for graphics 2017-10-16 22:04:05 +05:30
Kovid Goyal
48b98c583e Fix incorrect scrolling of images with specified number of rows 2017-10-16 22:02:55 +05:30
Kovid Goyal
090ee5b846 Disable graphics on older macOS machines
I give up, trying to work around Apple's buggy drivers without even
having a machine to test my workarounds on is too hard. Simply disable
graphics on macOS < 10.13

Fixes #141
2017-10-16 21:23:29 +05:30
Kovid Goyal
55db07c79f Only display Lenna if she exists in the gr script 2017-10-16 18:52:17 +05:30
Kovid Goyal
75e84a4519 Let the gr.pt script run with python2 as well 2017-10-16 18:50:57 +05:30
Kovid Goyal
e679fa9a1c Possible fix for #141
Presumably on older macOS versions the Apple OpenGL drivers cannot handle both
non-sequential and non-zero based binding locations. Sigh.
2017-10-16 18:39:49 +05:30
Kovid Goyal
6f0922d5e3 Merge branch 'master' of https://github.com/eldentyrell/kitty
Fix #143
2017-10-16 16:57:51 +05:30
Elden Tyrell
4663133871 correct off-by-one error in initial tabstops so emacs renders properly 2017-10-16 03:50:11 -07:00
Kovid Goyal
3f8b2184a6 Add a sanity check to ensure the attribute location binding worked 2017-10-13 10:06:12 +05:30
Kovid Goyal
2f7e517b5b Update comment to reflect code 2017-10-12 16:51:35 +05:30
Kovid Goyal
f2e8877032 ... 2017-10-12 16:10:19 +05:30
Kovid Goyal
555409ea73 Apple's OpenGL drivers are sad
Apparently they cant handle non-sequential binding locations. Sigh.
2017-10-12 15:36:38 +05:30
Kovid Goyal
30baf81858 Fix #140 2017-10-12 12:58:38 +05:30
Kovid Goyal
76a591e7d1 ... 2017-10-10 11:34:19 +05:30
Kovid Goyal
57d16a02c0 Update changelog and add some performance comparisons 2017-10-10 09:21:42 +05:30
Kovid Goyal
5c55502946 ... 2017-10-09 15:22:38 +05:30
Kovid Goyal
ef7fa507fb ... 2017-10-09 15:21:33 +05:30
Kovid Goyal
1ceefde2d0 Graphics rendering is now merged into master!
Fix #33
2017-10-09 15:20:15 +05:30
Kovid Goyal
94eaaae4a6 Handle font size changes, rescaling images 2017-10-09 15:15:13 +05:30
Kovid Goyal
3cce238b2b Relayout images on screen resizes
The strategy is very simple, images are not rescaled or re-positioned in
any way.
2017-10-09 12:43:37 +05:30
Kovid Goyal
f9b52249d1 Remove unused code 2017-10-09 11:58:25 +05:30
Kovid Goyal
f396fe59ca Implement a quota for image data 2017-10-09 11:31:57 +05:30
Kovid Goyal
b4b6968e07 Clear the alt screen graphics buffer when switching away from it as well as to it 2017-10-08 23:14:56 +05:30
Kovid Goyal
747f7b076d Implement control code for deleting images 2017-10-08 22:51:00 +05:30
Kovid Goyal
3f9f5ae076 DRYer 2017-10-08 11:48:23 +05:30
Kovid Goyal
2058682d1f ... 2017-10-08 11:46:10 +05:30
Kovid Goyal
201ac973e3 Make clear as also delete images 2017-10-07 16:43:17 +05:30
Kovid Goyal
df87c051bd Add a note about the optional dep on ImageMagick for icat 2017-10-07 11:55:45 +05:30
Kovid Goyal
f76077a45c icat: switch to ImageMagick and also add support for local client speedup by using a file to transmit the data 2017-10-07 11:46:00 +05:30
Kovid Goyal
836e9d98b4 Forgot to actually switch grman on buffer switch 2017-10-07 10:12:16 +05:30
Kovid Goyal
d5088a3e5b Do image clipping using OpenGL rather than on the CPU 2017-10-07 10:08:26 +05:30
Kovid Goyal
3a344d86fe Add graphics protocol detection to icat.py 2017-10-07 09:01:31 +05:30
Kovid Goyal
6a65f23f98 Add a a=q mode for querying without storing image data 2017-10-06 23:43:42 +05:30
Kovid Goyal
9e284442e8 ... 2017-10-06 23:11:14 +05:30
Kovid Goyal
135358423c Remove use of random data in the tests 2017-10-06 22:52:50 +05:30
Kovid Goyal
31173245f8 Send ACKs to client when displaying images by id 2017-10-06 22:39:17 +05:30
Kovid Goyal
ad5a276ddb Fix test broken by clipping of images to screen area 2017-10-06 22:34:21 +05:30
Kovid Goyal
4bc852e615 A spot of refacatoring 2017-10-06 21:36:54 +05:30
Kovid Goyal
d4e493727e Clip all rendered images to screen boundaries 2017-10-06 21:22:52 +05:30
Kovid Goyal
8d3ec7451b typo 2017-10-06 21:14:39 +05:30
Kovid Goyal
652e1084bc ... 2017-10-06 21:10:45 +05:30
Kovid Goyal
a9d31541c1 Implement clipped scrolling of images when in page area mode 2017-10-06 21:08:10 +05:30
Kovid Goyal
480645877a Clear graphics when switching to the alternate screen buffer 2017-10-05 23:01:47 +05:30
Kovid Goyal
600bff73d6 Off-by-one for image visibility testing
Also delete all images that overlap the screen on reset
2017-10-05 22:54:52 +05:30
Kovid Goyal
1c9612bd55 Turn on LTO for release builds 2017-10-05 21:18:21 +05:30
Kovid Goyal
259e01e879 Add test for deleting images after they scroll off 2017-10-05 21:14:56 +05:30
Kovid Goyal
240c9b5d8b A spot of refactoring 2017-10-05 20:54:45 +05:30
Kovid Goyal
689227dce4 Scroll images with text 2017-10-05 20:23:32 +05:30
Kovid Goyal
a4e7985fb0 Condition on negative refs as well as in the future we will use interleaved drawing for background opacity as well 2017-10-05 18:21:29 +05:30
Kovid Goyal
9bd231c4f9 Note that integers in the protocol are 32-bit 2017-10-05 18:15:10 +05:30
Kovid Goyal
7bf8b3c3c1 ... 2017-10-05 18:10:11 +05:30
Kovid Goyal
57a6d53a45 Document the image display protocol 2017-10-05 18:08:12 +05:30
Kovid Goyal
49aeae4aad Fix invocation of the image cat script as kitty icat 2017-10-05 17:19:17 +05:30
Kovid Goyal
664975b707 Show off kitty's graphics capabilities 2017-10-05 16:49:34 +05:30
Kovid Goyal
c3ab6ff780 Fix vertically inverted rendering of PNG 2017-10-04 23:38:36 +05:30
Kovid Goyal
6ad7260871 Dont compress PNG files 2017-10-04 23:26:15 +05:30
Kovid Goyal
e8f72c90f3 Add note about needing S key for PNG + compression 2017-10-04 23:25:27 +05:30
Kovid Goyal
75244b1416 ... 2017-10-04 23:07:59 +05:30
Kovid Goyal
952f0ad98c Accommodate the underpowered Apple lineup
macOS is missing glDrawArraysInstancedBaseInstance
2017-10-04 22:44:03 +05:30
Kovid Goyal
c726a15ed4 ... 2017-10-04 21:08:28 +05:30
Kovid Goyal
5d6af442c1 Correctly query num of cols/rows in icat 2017-10-04 20:06:07 +05:30
Kovid Goyal
596a392e68 micro optimization 2017-10-04 19:46:19 +05:30
Kovid Goyal
46bb482e96 Fix y-axis mapping incorrect for images 2017-10-04 19:34:34 +05:30
Kovid Goyal
e9bc64205e Code (not working) to draw graphics 2017-10-04 18:29:48 +05:30
Kovid Goyal
8f05f752af Code to update graphics buffer 2017-10-04 17:41:11 +05:30
Kovid Goyal
124a41643f Add a comment about the use of layout locations 2017-10-04 17:29:30 +05:30
Kovid Goyal
138a37ccac Start work on the graphics program 2017-10-04 17:22:00 +05:30
Kovid Goyal
e1650d5df7 Implement interleaved drawing of cells 2017-10-04 16:11:20 +05:30
Kovid Goyal
3f615666df Call grman_update_layers 2017-10-04 15:39:31 +05:30
Kovid Goyal
96a9d64bcb A spot of refactoring 2017-10-04 15:34:54 +05:30
Kovid Goyal
bd09e2ebf1 Allow re-using VAO objects between different types of cell program 2017-10-04 15:33:15 +05:30
Kovid Goyal
ad040271b9 Initialize uniforms for all cell program variants 2017-10-04 14:46:36 +05:30
Kovid Goyal
ead73c8209 Prepare for two stage rendering of cells 2017-10-04 14:15:51 +05:30
Kovid Goyal
b032130a20 A spot of refactoring 2017-10-04 10:56:44 +05:30
Kovid Goyal
c5837d4577 More work on the iamge cat utility. Make it useable as a standalone script 2017-10-04 10:22:31 +05:30
Kovid Goyal
1a8d9314fe Fix transmission of chunked compressed data 2017-10-04 10:19:25 +05:30
Kovid Goyal
9ccf9636ce Allow running icat script outside of kitty 2017-10-03 21:37:55 +05:30
Kovid Goyal
e56042c41a Graceful handling of errors from rsvg-convert 2017-10-03 21:31:47 +05:30
Kovid Goyal
72626279c2 Start work on image cat utility 2017-10-03 21:31:42 +05:30
Kovid Goyal
acc43ce9dc Handle T action with chunked transfer correctly 2017-10-03 20:34:48 +05:30
Kovid Goyal
c87dcdbe3c Tests for displaying graphics 2017-10-03 16:10:04 +05:30
Kovid Goyal
aec1612de2 API to enable image placement tests
Also fix cursor movement handling after graphics command
2017-10-02 10:35:51 +05:30
Kovid Goyal
7c488888a0 more work on displaying graphics 2017-10-01 20:17:48 +05:30
Kovid Goyal
6d960e4130 ... 2017-10-01 09:12:14 +05:30
Kovid Goyal
3cbc20005b Implement sending of image data to GPU 2017-10-01 09:04:46 +05:30
Kovid Goyal
e2a8115328 ... 2017-09-30 18:36:25 +05:30
Kovid Goyal
28ae99ed37 More work on displaying images 2017-09-30 14:46:17 +05:30
Kovid Goyal
e5898ad4b0 More work on displaying images 2017-09-30 13:51:52 +05:30
Kovid Goyal
b722bc809c More work on displaying images 2017-09-30 13:51:52 +05:30
Kovid Goyal
710d00674a Export the free texture function 2017-09-30 13:51:52 +05:30
Kovid Goyal
9078ca975e A spot of refactoring 2017-09-30 13:51:52 +05:30
Kovid Goyal
4f98d10caa Remove the requirement to specify sizes for PNG files 2017-09-30 13:51:52 +05:30
Kovid Goyal
9e5dbb45d4 Move the graphics protocol documentation to a separate file 2017-09-30 13:51:52 +05:30
Kovid Goyal
5e5065715e ... 2017-09-30 13:51:52 +05:30
Kovid Goyal
8be7679a38 grrr 2017-09-30 13:51:52 +05:30
Kovid Goyal
6297c9a719 ... 2017-09-30 13:51:52 +05:30
Kovid Goyal
933621b038 Better libpng error handling 2017-09-30 13:51:51 +05:30
Kovid Goyal
c31e608ff9 Tests for loading PNG images 2017-09-30 13:51:51 +05:30
Kovid Goyal
671bcafee5 Dont carry the fd around 2017-09-30 13:51:51 +05:30
Kovid Goyal
c01f009e42 Remove sz requirement and implement proper fix for failure to mmap shm objects on OS X. Apparently they have to be mapped shared. 2017-09-30 13:51:51 +05:30
Kovid Goyal
dbd7ec5b27 Allow specifying the offset and size for reading data from files
Also require size to be specified for SHM objects to support platforms
such as macOS that have no way to get the size from the fd.
2017-09-30 13:51:51 +05:30
Kovid Goyal
898136dbdc Free the mapped file early if possible 2017-09-30 13:51:51 +05:30
Kovid Goyal
ef91f9dc8f Use fstat to get SHM file size instead of seeking 2017-09-30 13:51:51 +05:30
Kovid Goyal
bfd7675639 ... 2017-09-30 13:51:51 +05:30
Kovid Goyal
b644d4620a OS X does not support write() with shared memory 2017-09-30 13:51:51 +05:30
Kovid Goyal
03dd6e0490 Test for image loading from shared memory 2017-09-30 13:51:50 +05:30
Kovid Goyal
dfca991173 Test for loading image data from file 2017-09-30 13:51:50 +05:30
Kovid Goyal
13c4c605b3 Prevent loading of too large PNG images 2017-09-30 13:51:50 +05:30
Kovid Goyal
8e5c4b6f7a Require data size to be sent for PNG format 2017-09-30 13:51:50 +05:30
Kovid Goyal
d0d769f26b Test for zlib de-compression 2017-09-30 13:51:50 +05:30
Kovid Goyal
558b208edd Fix compressed key not being parsed 2017-09-30 13:51:50 +05:30
Kovid Goyal
35acb1497a Fix chunked loading of images 2017-09-30 13:51:50 +05:30
Kovid Goyal
8cd1f76d2b Framework for testing loading of images 2017-09-30 13:51:50 +05:30
Kovid Goyal
f0ee728b94 Fix failing flake 2017-09-30 13:51:50 +05:30
Kovid Goyal
b4a96428f3 DRYer 2017-09-30 13:51:50 +05:30
Kovid Goyal
7d6d8efc26 ... 2017-09-30 13:51:49 +05:30
Kovid Goyal
f3ee3784f7 Fix longjmp handling when calling libpng 2017-09-30 13:51:49 +05:30
Kovid Goyal
7da08d37d2 File to host graphics tests 2017-09-30 13:51:49 +05:30
Kovid Goyal
23c2bdb6f0 Dont silently wrap too large ids, instead ignore the graphics command 2017-09-30 13:51:49 +05:30
Kovid Goyal
7736629bc4 Fix graphics id not going upto UINT32_MAX 2017-09-30 13:51:49 +05:30
Kovid Goyal
204bd97198 Nicer error responses on bad graphics data 2017-09-30 13:51:49 +05:30
Kovid Goyal
2786976c63 ... 2017-09-30 13:51:49 +05:30
Kovid Goyal
7567f96a34 Python API to get image data from gr. manager for tests 2017-09-30 13:51:49 +05:30
Kovid Goyal
cf33ef8666 ... 2017-09-30 13:51:49 +05:30
Kovid Goyal
9860ed544f Respond to load commands when an id is present 2017-09-30 13:51:49 +05:30
Kovid Goyal
9601ed79f1 Travis build fixes 2017-09-30 13:51:48 +05:30
Kovid Goyal
e5b5fb2773 fmt defaults to RGBA and ignore add commands for images with no width/height 2017-09-30 13:51:48 +05:30
Kovid Goyal
01fb9436dd Code to read compressed and PNG encoded image data 2017-09-30 13:51:48 +05:30
Kovid Goyal
df1e06ec2c DRYer 2017-09-30 13:51:48 +05:30
Kovid Goyal
c973a7326e Dont link against rt on macOS 2017-09-30 13:51:48 +05:30
Kovid Goyal
9facc5f7d3 DRYer 2017-09-30 13:51:48 +05:30
Kovid Goyal
66bce4b8cd Code to read image data 2017-09-30 13:51:48 +05:30
Kovid Goyal
c567acb4e5 Work on loading images 2017-09-30 13:51:48 +05:30
Kovid Goyal
8418cc04c1 Start work on the graphics manager 2017-09-30 13:51:48 +05:30
Kovid Goyal
e52818d54c Move the screen datatype decls into screen.h 2017-09-30 13:51:47 +05:30
Kovid Goyal
15e03f74f4 Also report the payload for graphics commands 2017-09-30 13:51:47 +05:30
Kovid Goyal
56c2e0c26a Report incomplete graphics commands as parser errors 2017-09-30 13:51:47 +05:30
Kovid Goyal
83de392b39 ... 2017-09-30 13:51:47 +05:30
Kovid Goyal
3c89f80603 More tests for the graphics control code parser 2017-09-30 13:51:47 +05:30
Kovid Goyal
8e64895c23 Framework for testing graphics command parsing 2017-09-30 13:51:47 +05:30
Kovid Goyal
967e65e150 Use a static b64 decoding table 2017-09-30 13:51:47 +05:30
Kovid Goyal
9f5d731d8d ... 2017-09-30 13:51:47 +05:30
Kovid Goyal
ef312a3d1c ... 2017-09-30 13:51:47 +05:30
Kovid Goyal
705298737a Fix off by one 2017-09-30 13:51:47 +05:30
Kovid Goyal
a7b95f73be Cleanup handling of ,; in the GR control code parser 2017-09-30 13:51:46 +05:30
Kovid Goyal
a9ed44eecc Implement decoding of graphics command payload 2017-09-30 13:51:46 +05:30
Kovid Goyal
b8d9629ee4 Start work on parsing of graphics escape code 2017-09-30 13:51:46 +05:30
Kovid Goyal
5b24d51fcd Fix failing screen resize test
Take into account the index that now happens to ensure that
the cursor is on a new line.
2017-09-30 13:51:35 +05:30
Kovid Goyal
e832524bfc Ensure cursor is on a blank line after a resize 2017-09-30 13:25:31 +05:30
Kovid Goyal
a783325464 Nicer parsing of dependencies file 2017-09-30 12:25:03 +05:30
Kovid Goyal
af99c172fe Use dependency mapping when doing incremental builds 2017-09-30 12:18:08 +05:30
Kovid Goyal
b5b9a7ba6d Fix compilation with clang 2017-09-30 11:56:30 +05:30
Kovid Goyal
2909fddaa2 Split out GL API wrapping code into its own header 2017-09-30 11:48:52 +05:30
Kovid Goyal
7863857b2c Use a UBO for all cell program uniforms 2017-09-30 11:44:44 +05:30
Kovid Goyal
b28cec3236 Give Face objects a nice __repr__ 2017-09-30 08:01:04 +05:30
Kovid Goyal
55498b5a44 Avoid unnecessary calls to glBindTexture 2017-09-30 07:00:46 +05:30
Kovid Goyal
8d03d7216f Do not crash when failing to render a glyph, instead render the missing glyph and print an error msg to stderr 2017-09-29 11:57:17 +05:30
Kovid Goyal
7ddaa70498 Cleanup freetype library on exit 2017-09-28 11:22:18 +05:30
Kovid Goyal
150ffab72d finalize the fontconfig library on exit 2017-09-28 11:06:56 +05:30
Kovid Goyal
cda385b37c Fix #132 2017-09-28 10:01:08 +05:30
Kovid Goyal
28146a4e9c Proper fix for sending constant uniform to cell program 2017-09-28 09:55:17 +05:30
Kovid Goyal
0ad9149ca8 Avoid one more call to set uniforms 2017-09-26 11:27:04 +05:30
Kovid Goyal
f9972bc33c ... 2017-09-26 09:13:50 +05:30
Kovid Goyal
e6cff1e9b6 Fix #130 2017-09-26 09:10:24 +05:30
Kovid Goyal
c64527c333 Fix #129 2017-09-26 08:22:26 +05:30
Kovid Goyal
9cfc19e010 Dont shadow the glfw global mouse state variable 2017-09-25 22:00:00 +05:30
Kovid Goyal
af971af4ca Remove unused code 2017-09-25 21:59:52 +05:30
Kovid Goyal
3471887817 ... 2017-09-25 18:05:25 +05:30
Kovid Goyal
cd88505ca7 Fix #120 2017-09-25 17:47:30 +05:30
Kovid Goyal
3ca45ab241 Fix cursor moving one line up when resizing 2017-09-20 10:59:31 +05:30
Kovid Goyal
564f19d248 ... 2017-09-19 11:17:17 +05:30
Kovid Goyal
5622efb710 Add a CHANGELOG 2017-09-19 10:33:23 +05:30
Kovid Goyal
a857a35348 Unhide mouse cursor on focus in 2017-09-18 20:28:55 +05:30
Kovid Goyal
93ca469d85 Only set the glfw error callback immediately before initializing glfw
Avoids spurious glfw not initialized error messages in case fo
exceptions that occur before the call to init
2017-09-18 08:46:25 +05:30
Kovid Goyal
1e01c2a07c Remove unused code 2017-09-18 08:40:37 +05:30
Kovid Goyal
efaee69486 Fix detection of glfinithintstring 2017-09-18 08:40:02 +05:30
Kovid Goyal
558e4af3c6 Make the curly underline a bit thicker 2017-09-17 21:09:30 +05:30
Kovid Goyal
8490457cab ... 2017-09-17 21:01:50 +05:30
Kovid Goyal
6585c11808 Make the curly underline an actual curl 2017-09-17 20:30:36 +05:30
Kovid Goyal
142cba54b3 DRYer 2017-09-17 19:36:47 +05:30
Kovid Goyal
19b065b6a4 Fix underline not being set to background color when cursor is over it 2017-09-17 19:28:01 +05:30
Kovid Goyal
826a64c8dc Fix wide cursor not being rendered 2017-09-17 19:23:01 +05:30
Kovid Goyal
14103db2ee Coalesce another couple of uniforms 2017-09-17 18:10:32 +05:30
Kovid Goyal
51d037fb70 Coalesce a couple of set uniform calls into a single one 2017-09-17 17:48:42 +05:30
Kovid Goyal
b433380e1d Make the cell shader a little more readable 2017-09-17 17:38:03 +05:30
Kovid Goyal
df4df76d24 Switch to using an opaque block cursor
The text is rendered in the background color on top of the opaque
block cursor. We use the background color since applications can change
both cursor and background colors, so it is up to the application to
ensure the colors have good contrast. Fix #126
2017-09-17 13:03:02 +05:30
Kovid Goyal
2d0c6a43c5 Fix broken reverse video 2017-09-16 17:39:07 +05:30
Kovid Goyal
0307497e06 Fix broken scrolling 2017-09-16 17:11:30 +05:30
Kovid Goyal
bc1de92534 Fix the broken tests 2017-09-16 17:05:58 +05:30
Kovid Goyal
37feb65204 Move wakeup calls into child-monitor 2017-09-16 16:46:23 +05:30
Kovid Goyal
9cd146fe3e Remove the buf_toggled callback 2017-09-16 16:31:29 +05:30
Kovid Goyal
7b1576d960 Remove unneccessary python callbacks 2017-09-16 15:03:18 +05:30
Kovid Goyal
6361da9e0b ... 2017-09-16 14:34:47 +05:30
Kovid Goyal
50a1bf528c Get rid of the bell callback, just handle it all in C 2017-09-16 14:34:23 +05:30
Kovid Goyal
2ddbac073a DRYer 2017-09-16 12:56:41 +05:30
Kovid Goyal
33f48e8268 Fix rendering occasionally not occurring after input received 2017-09-16 12:51:30 +05:30
Kovid Goyal
ee581ebdf4 Remove unused code 2017-09-16 12:26:35 +05:30
Kovid Goyal
81879db2db Fix new_input_at not protected by read lock 2017-09-16 12:24:31 +05:30
Kovid Goyal
3675c27268 Fix the new_window keyboard shortcut being passed through 2017-09-16 11:22:58 +05:30
Kovid Goyal
a92b3c605f Move the text attributes out of the char type
This means that more text attributes can be added in the future (there
are 8 bits available) and there is no need to keep bit twiddling when
accessing the chars themselves. Also means less data needs to be sent to
the GPU. Cell size does not change since there were currently 2 unused
bytes because of alignment.
2017-09-16 11:02:42 +05:30
Kovid Goyal
85ed5c1515 Remove unnecessary conditional operators 2017-09-16 09:43:43 +05:30
Kovid Goyal
b7a5c064c2 Fix some Alt based shortcuts not working 2017-09-16 09:32:17 +05:30
Kovid Goyal
34084e7ab5 Neaten up keys.h 2017-09-16 09:16:30 +05:30
Kovid Goyal
728f33700a Fine tune the artificial delays in the render loop
There are now two numbers, repaint_delay and input_delay
that control how often the screen is repainted and how frequently
input received from the child process is processed.

This halves the CPU usage in intensive cases such as scrolling
a file in less. The CPU usage of kitty + X when scrolling is now
significantly lower than all the other terminals on my system.

MROAWR!

...
2017-09-16 08:20:23 +05:30
Kovid Goyal
43ebddc28f Fix writing to child causing excessive CPU usage
Couple of bugs combined.
2017-09-15 21:56:20 +05:30
Kovid Goyal
c5e989bc94 Move the key handler to C 2017-09-15 21:46:00 +05:30
Kovid Goyal
a4d71bcf5c Move the text input callback to C 2017-09-15 18:33:45 +05:30
Kovid Goyal
ddbe0703a3 Remove unused code 2017-09-15 18:10:17 +05:30
Kovid Goyal
b2c7272af1 Store key combos that need special handling in a table for fast lookup 2017-09-15 18:06:26 +05:30
Kovid Goyal
0423c55dc1 Move a few externs into appropriate header files 2017-09-15 11:56:08 +05:30
Kovid Goyal
0b656246fd Fix cursor width incorrect after scrolling 2017-09-15 11:44:16 +05:30
Kovid Goyal
28430a4104 Fix wide chars not being rendered 2017-09-15 11:43:05 +05:30
Kovid Goyal
f0a9f32d0a Fix cursor not being rendered on empty cells 2017-09-15 11:08:42 +05:30
Kovid Goyal
44c897a61a Translate key presses to bytes using a lookup table 2017-09-15 10:45:27 +05:30
Kovid Goyal
b5af266b87 A spot of refactoring 2017-09-15 10:45:27 +05:30
Kovid Goyal
9989363ecd Make the URL highlight color configurable 2017-09-15 10:45:27 +05:30
Kovid Goyal
53ea5c678d Highlight links with a underline on mouseover 2017-09-15 10:45:27 +05:30
Kovid Goyal
464291bbb1 Port click on URL code to C 2017-09-15 10:45:27 +05:30
Kovid Goyal
ed3427f349 Dont use the python unicodedata module as we use libunistring
No sense in loading two hude unicode datasets into memory
2017-09-15 10:45:27 +05:30
Kovid Goyal
21accfe114 Send mouse events to child directly in C 2017-09-15 10:45:26 +05:30
Kovid Goyal
ee0a539e01 Reclaim write buffer space once no longer needed 2017-09-15 10:45:26 +05:30
Kovid Goyal
d236955dfb ... 2017-09-15 10:45:26 +05:30
Kovid Goyal
32a11d9d21 Avoid mallocs when writing small amounts of data to the child 2017-09-15 10:45:26 +05:30
Kovid Goyal
43c4c71abd Port mouse event encoding code to C 2017-09-15 10:45:26 +05:30
Kovid Goyal
b9ac13c379 Move the scroll event handler to C 2017-09-15 10:45:26 +05:30
Kovid Goyal
11bb21e8a4 Remove unused code 2017-09-15 10:45:26 +05:30
Kovid Goyal
4bfe7e1069 Fix incorrect cell co-ordinates when more than one window visible in the layout 2017-09-15 10:45:26 +05:30
Kovid Goyal
4feaf13556 Implement drag scrolling in C 2017-09-15 10:45:26 +05:30
Kovid Goyal
a27004da35 Port drag select to C 2017-09-15 10:45:26 +05:30
Kovid Goyal
cf6894d74f Port multi-click handler to C 2017-09-15 10:45:25 +05:30
Kovid Goyal
a921180224 Port middle-click-to-paste to C 2017-09-15 10:45:25 +05:30
Kovid Goyal
7e4948be10 Port switch focus on click code to C 2017-09-15 10:45:25 +05:30
Kovid Goyal
04a45babfb DRYer 2017-09-15 10:45:25 +05:30
Kovid Goyal
1c1d0a4e91 Port mouse cursor change over hyperlinks to C 2017-09-15 10:45:25 +05:30
Kovid Goyal
271b623f82 More URL detection tests 2017-09-15 10:45:25 +05:30
Kovid Goyal
88d896e745 Move function to detect URLs into C code 2017-09-15 10:45:25 +05:30
Kovid Goyal
745b6222c2 Start work on migrating the mouse handlers to C 2017-09-15 10:45:25 +05:30
Kovid Goyal
42329e5d46 Merge the char_grid and window modules 2017-09-15 10:45:25 +05:30
Kovid Goyal
240c683504 DRYer 2017-09-15 10:45:24 +05:30
Kovid Goyal
c683725434 Get rid of the timers infrastructure
It is not needed with a pure state machine.
Note that drag scrolling still has to be ported from using
timers.
2017-09-15 10:45:24 +05:30
Kovid Goyal
f3cd0a4966 ... 2017-09-15 10:45:24 +05:30
Kovid Goyal
573dd8c99e ... 2017-09-15 10:45:24 +05:30
Kovid Goyal
6d8b59cb61 Track window and application titles in C
Allows removing of the last bit fo python from the render loop
2017-09-15 10:45:24 +05:30
Kovid Goyal
c41ede4d20 Dont use a timer for mouse hiding 2017-09-15 10:45:24 +05:30
Kovid Goyal
13ac050bf8 Move cursor render call to C 2017-09-15 10:45:24 +05:30
Kovid Goyal
6e4b977128 Track application focus state in global state 2017-09-15 10:45:24 +05:30
Kovid Goyal
e6df82b255 Move the char grid render call into C 2017-09-15 10:45:24 +05:30
Kovid Goyal
943a1575ad Move render call for tab bar to C code 2017-09-15 10:45:24 +05:30
Kovid Goyal
2e0cbb88bb Call draw_borders() directly from C 2017-09-15 10:45:23 +05:30
Kovid Goyal
8e379df24f Ensure the visual bell is cleared
UI thread must wakeup after visual bell duration
2017-09-15 10:45:23 +05:30
Kovid Goyal
ccf5391b45 Move visual bell tracking into the Screen object 2017-09-15 10:45:23 +05:30
Kovid Goyal
ca5eb4feb5 Start working on central object to track state 2017-09-15 10:45:23 +05:30
Kovid Goyal
c1cb4df9d2 Avoid unnecessary use of timers for resize_pty 2017-09-15 10:45:23 +05:30
Kovid Goyal
367ffb602c Color table buffer has to be bound before each render
Other wise the last created child's buffer is always used
2017-09-15 10:45:23 +05:30
Kovid Goyal
4e8ade53d8 Fix compilation on apple 2017-09-15 10:45:23 +05:30
Kovid Goyal
bc8a8d83fc Restore a couple fo python bindings needed for the test suite 2017-09-15 10:45:23 +05:30
Kovid Goyal
7f6befe4f9 Remove the python OpenGL wrapper as it is no longer needed 2017-09-15 10:45:23 +05:30
Kovid Goyal
86893db46b Fix re-alloc of sprite texture 2017-09-15 10:45:22 +05:30
Kovid Goyal
3c3eeb1835 ... 2017-09-15 10:45:22 +05:30
Kovid Goyal
3a883ad436 Move the sprites GPU code to shaders.c 2017-09-15 10:45:22 +05:30
Kovid Goyal
cc8271b766 Fix compilation on macOS 2017-09-15 10:45:22 +05:30
Kovid Goyal
1246032b67 Remove unused code 2017-09-15 10:45:22 +05:30
Kovid Goyal
9eea178890 Make --debug-gl have zero runtime cost when absent 2017-09-15 10:45:22 +05:30
Kovid Goyal
44f456089b Migrate the cell program 2017-09-15 10:45:22 +05:30
Kovid Goyal
2fff6e1cb9 Directly rende r borders instead of going through the active tab 2017-09-15 10:45:22 +05:30
Kovid Goyal
ff6c366b8a Remove unused code 2017-09-15 10:45:22 +05:30
Kovid Goyal
6701d52e26 Simplify error handling of open gl code 2017-09-15 10:45:22 +05:30
Kovid Goyal
11e147c718 ... 2017-09-15 10:45:21 +05:30
Kovid Goyal
634cd53454 Remove unused code 2017-09-15 10:45:21 +05:30
Kovid Goyal
084f31292b ... 2017-09-15 10:45:21 +05:30
Kovid Goyal
1e37041b50 Fix rendering of horizontal borders 2017-09-15 10:45:21 +05:30
Kovid Goyal
2a24199c90 Migrate the borders program 2017-09-15 10:45:21 +05:30
Kovid Goyal
5905216f96 Use instanced rendering for the borders 2017-09-15 10:45:21 +05:30
Kovid Goyal
3ddf963c5c API to map VAO buffers 2017-09-15 10:45:21 +05:30
Kovid Goyal
778c3c075a Migrate the cursor program 2017-09-15 10:45:21 +05:30
Kovid Goyal
d2b3052918 Code to get uniform locations 2017-09-15 10:45:21 +05:30
Kovid Goyal
8ce2794a8a More work on migrating shader code 2017-09-15 10:45:20 +05:30
Kovid Goyal
c1dc4d0575 ... 2017-09-15 10:45:20 +05:30
Kovid Goyal
9c184c794a Migrate function to compile programs 2017-09-15 10:45:20 +05:30
Kovid Goyal
d3f2620caf Migrate GL setup and error handling code 2017-09-15 10:45:20 +05:30
Kovid Goyal
a1c9c90fc8 Start work on moving shaders.py to C 2017-09-15 10:45:20 +05:30
Kovid Goyal
83f4b6e391 Remove unused code 2017-09-15 10:45:20 +05:30
Kovid Goyal
cc9ed734cf Get rid of prepare_for_render as it is not needed anymore 2017-09-15 10:45:20 +05:30
Kovid Goyal
98daddc39a Move selection render tracking into the Screen class 2017-09-15 10:45:20 +05:30
Kovid Goyal
408c719c5f Move selection tracking into the Screen class 2017-09-15 10:45:20 +05:30
Kovid Goyal
5caea75115 ... 2017-09-15 10:45:20 +05:30
Kovid Goyal
19bd068599 Raise an error on negative scroll amounts 2017-09-15 10:45:19 +05:30
Kovid Goyal
2490199e52 Move scroll tracking into the screen object 2017-09-15 10:45:19 +05:30
Kovid Goyal
726a6370ad ... 2017-09-15 10:45:19 +05:30
Kovid Goyal
00b8db26fc Add libunistring on travis 2017-09-15 10:45:19 +05:30
Kovid Goyal
544c402c9f Move word selection code into C, avoiding the need for the python regex module 2017-09-15 10:45:19 +05:30
Kovid Goyal
9bea1001f9 Speedup unicode character property lookup
Use libunistring instead of building predicates from the unicode
database
2017-09-15 10:45:19 +05:30
Kovid Goyal
63882e1fdc Make selection smarter
It now does not add trailing blank cells on selected lines to the
selection.
2017-09-15 10:45:19 +05:30
Kovid Goyal
5103381c27 DRYer 2017-09-15 10:45:19 +05:30
Kovid Goyal
56e55ddbc3 Fix incorrect handling of auto for bold and italic fonts on macOS 2017-09-15 10:45:19 +05:30
Kovid Goyal
a261e1f57d Fix erro on python built without threading 2017-09-15 10:45:19 +05:30
Kovid Goyal
5ceec08d32 Use buffer mapping for the tabbar selbuf 2017-09-15 10:45:18 +05:30
Kovid Goyal
92d53daf22 Dont spam resize_pty events, include a small timeout 2017-09-15 10:45:18 +05:30
Kovid Goyal
99acc4adcb Fix a couple of recursive timer adds 2017-09-15 10:45:18 +05:30
Kovid Goyal
827d086c54 Allow re-adding of timers during timers_call() 2017-09-15 10:45:18 +05:30
Kovid Goyal
fb820faf11 Prevent timers being added in a call 2017-09-15 10:45:18 +05:30
Kovid Goyal
0aecae288f Avoid extra function call when waking up for cursor blink rendering 2017-09-15 10:45:18 +05:30
Kovid Goyal
3274327fe7 Speedup as_unicode by avoiding an unnecessary malloc/free 2017-09-15 10:45:18 +05:30
Kovid Goyal
f97127f587 ... 2017-09-15 10:45:18 +05:30
Kovid Goyal
b8c34c3ee2 Move implementation of screen_line() into C 2017-09-15 10:45:18 +05:30
Kovid Goyal
4ae3abb3cb Fix selection being cleared when drag scrolling 2017-09-15 10:45:18 +05:30
Kovid Goyal
5c1747b2c8 Use buffer mapping for the selection buffer 2017-09-15 10:45:17 +05:30
Kovid Goyal
2611678855 ... 2017-09-15 10:45:17 +05:30
Kovid Goyal
746a20a11d Cleanup data-types.h 2017-09-15 10:45:17 +05:30
Kovid Goyal
3072eac222 DRYer sprites 2017-09-15 10:45:17 +05:30
Kovid Goyal
a4580f2126 DRYer glfw 2017-09-15 10:45:17 +05:30
Kovid Goyal
4a27793651 DRYer CoreText 2017-09-15 10:45:17 +05:30
Kovid Goyal
5ed4b29e4b DRYer fontconfig module 2017-09-15 10:45:17 +05:30
Kovid Goyal
b8678871df Remove some unnecessary declarations from data-types.h 2017-09-15 10:45:17 +05:30
Kovid Goyal
457bf8c289 Move gl binding code into its own module 2017-09-15 10:45:17 +05:30
Kovid Goyal
dd8be35922 ... 2017-09-15 10:45:17 +05:30
Kovid Goyal
b4d1cfea50 ... 2017-09-15 10:45:16 +05:30
Kovid Goyal
7113d5c293 Use a mapped buffer to send color table to the GPU 2017-09-15 10:45:16 +05:30
Kovid Goyal
bc97cfa024 Use a null to represent a blank rather than a space
This has performance benefits when clearing (can use a single
memset). Also allows detecting trailing whitespace on lines correctly.
2017-09-15 10:45:16 +05:30
Kovid Goyal
382daacb73 Remove the support for multiple top-level glfw windows 2017-09-15 10:45:16 +05:30
Kovid Goyal
aa526db772 Another place that was using python threading APIs 2017-09-15 10:45:16 +05:30
Kovid Goyal
1f9510ab9e Fix incorrect decoration colors 2017-09-15 10:45:16 +05:30
Kovid Goyal
b8acb9b133 Pass cell data to GPU directly
Converts update_cell_range() to a simple memcpy(). The GPU has to do
roughly the same amount of work (there is one extra attribute, and one
extra calculation for reverse video).
2017-09-15 10:45:16 +05:30
Kovid Goyal
51231b7eb2 Migrate tabs to also use the new buffer mapping API 2017-09-15 10:45:16 +05:30
Kovid Goyal
029ff84f09 Remove the change tracker related tests
The change tracker no longer exists
2017-09-15 10:45:16 +05:30
Kovid Goyal
f5dbe36cf3 Remove the now useless change tracking code 2017-09-15 10:45:16 +05:30
Kovid Goyal
906937149e Copy cell data to the GPU in a single pass 2017-09-15 10:45:15 +05:30
Kovid Goyal
f324d8ec4f Fix a couple of bugs in the buffer map API 2017-09-15 10:45:15 +05:30
Kovid Goyal
2089d2bfdf Fix main_loop() not returning NULL when an error has occurred 2017-09-15 10:45:15 +05:30
Kovid Goyal
281cb50780 API to map OpenGL buffers 2017-09-15 10:45:15 +05:30
Kovid Goyal
012b209a56 Update CELL data structure 2017-09-15 10:45:15 +05:30
Kovid Goyal
c0593d9f1f Get rid of update_screen
No longer needed.
2017-09-15 10:45:15 +05:30
Kovid Goyal
f655112bda Directly copy the sprite positions into the GPU buffer 2017-09-15 10:45:15 +05:30
Kovid Goyal
c4680aae2c Track sprite positions in the Cell structure 2017-09-15 10:45:15 +05:30
Kovid Goyal
a8d5ad2c1a ... 2017-09-15 10:45:15 +05:30
Kovid Goyal
333eb3534a ... 2017-09-15 10:45:14 +05:30
Kovid Goyal
1a42356f68 Forgot to close stdin_read_fd in the master process 2017-09-15 10:45:14 +05:30
Kovid Goyal
1197549e5b Remove the last use of the python threading module 2017-09-15 10:45:14 +05:30
Kovid Goyal
d2749f5ccc Sigh 2017-09-15 10:45:14 +05:30
Kovid Goyal
6379b3f898 Forgot to modify the fds array in remove children 2017-09-15 10:45:14 +05:30
Kovid Goyal
c97afd7b44 Handle unexpected closing of child fds gracefully 2017-09-15 10:45:14 +05:30
Kovid Goyal
9b9003ded0 Simplify code to set thread names 2017-09-15 10:45:14 +05:30
Kovid Goyal
5550c7a95f _GNU_SOURCE needed on apple as well? 2017-09-15 10:45:14 +05:30
Kovid Goyal
fe7f3233ba Fix initial tab bar visibility when starting a session with multiple tabs 2017-09-15 10:45:14 +05:30
Kovid Goyal
a52f0939df Make using the timer for wakeups more efficient 2017-09-15 10:45:14 +05:30
Kovid Goyal
ff3ddfd369 Simply use of repaint_delay in parse_input()
Dont maintain per child parse times. Instead just gate it globally.
This could result in slowdowns with lots of very active children, but
that seems unlikely.
2017-09-15 10:45:13 +05:30
Kovid Goyal
161161f840 Dont include stropts.h on macs 2017-09-15 10:45:13 +05:30
Kovid Goyal
b0e1c74fdd Note about interaction of cursor_blink_time and repaint_delay 2017-09-15 10:45:13 +05:30
Kovid Goyal
1bd46b0636 Avoid extra wakeup when rendering blinking cursor 2017-09-15 10:45:13 +05:30
Kovid Goyal
5e676090fa Report failures to write to child 2017-09-15 10:45:13 +05:30
Kovid Goyal
4d31624a69 Better handling of failure to execute child
exec() a shell instead so that we are not left with a forked but not
execed process
2017-09-15 10:45:13 +05:30
Kovid Goyal
c9695efd18 ... 2017-09-15 10:45:13 +05:30
Kovid Goyal
7dc51d7d9e Handle ioctl failures when resizing the tty more gracefully 2017-09-15 10:45:13 +05:30
Kovid Goyal
d5d812ccfe Fix for session with empty enabled_layouts 2017-09-15 10:45:13 +05:30
Kovid Goyal
af02b735e7 Move child process management into child-monitor.c 2017-09-15 10:45:13 +05:30
Kovid Goyal
52ab534e22 Move setting of IUTF8 into child-monitor.c 2017-09-15 10:45:12 +05:30
Kovid Goyal
895eedeb9b Apparently pthread_mutex_t is a scalar on macs 2017-09-15 10:45:12 +05:30
Kovid Goyal
5972a37550 Work on centralising lifecycle management in the child monitor 2017-09-15 10:45:12 +05:30
Kovid Goyal
079054f798 Fix tab bar rendering 2017-09-15 10:45:12 +05:30
Kovid Goyal
914f7ddbd5 Fix zero division 2017-09-15 10:45:12 +05:30
Kovid Goyal
5357876128 Ensure screen objects are de-allocated immediately on close instead of waiting for garbage collection 2017-09-15 10:45:12 +05:30
Kovid Goyal
b20367b888 Avoid dict lookups when calling python callbacks 2017-09-15 10:45:12 +05:30
Kovid Goyal
6698712b44 Respect repaint_delay when calling render() as well 2017-09-15 10:45:12 +05:30
Kovid Goyal
21b799905d Move the main loop into the C module 2017-09-15 10:45:12 +05:30
Kovid Goyal
02870d7221 Move the signal received handler into the C module 2017-09-15 10:45:12 +05:30
Kovid Goyal
d4991424f9 Set the python thread switch interval to forever 2017-09-15 10:45:11 +05:30
Kovid Goyal
1684bda1e9 Better thread name 2017-09-15 10:45:11 +05:30
Kovid Goyal
e8b5a72c96 Remove GIL management code since it is no longer needed 2017-09-15 10:45:11 +05:30
Kovid Goyal
7f180ad3d9 Do not use the python threading module
Threading in python imposes significant overhead.
Instead create the thread using pthreads directly
2017-09-15 10:45:11 +05:30
Kovid Goyal
94c4c00859 Move signal handling code into the C module 2017-09-15 10:45:11 +05:30
Kovid Goyal
1308bbac2d Move creation of wakeup fds to c module 2017-09-15 10:45:11 +05:30
Kovid Goyal
76890a2b71 Do not perform any python API calls in the I/O thread 2017-09-15 10:45:11 +05:30
Kovid Goyal
2c8f3b6d98 Remove unnecessary extra lock/unlock of children_mutex 2017-09-15 10:45:11 +05:30
Kovid Goyal
0e46994d0a Restore repaint_delay 2017-09-15 10:45:11 +05:30
Kovid Goyal
44650c5723 Make reading into the screen read buffer more efficient 2017-09-15 10:45:11 +05:30
Kovid Goyal
234bb07b67 Initial attempt at moving all threading code into a single file 2017-09-15 10:45:10 +05:30
Kovid Goyal
fea79878fa Make the monotonic() function available everywhere 2017-09-15 10:45:10 +05:30
Kovid Goyal
0365828a5b Remove all python threading related code 2017-09-15 10:45:10 +05:30
Kovid Goyal
fa30a95b46 ... 2017-09-15 10:45:10 +05:30
Kovid Goyal
f44d56b116 Ensure GIL is not released when rendering sprites 2017-09-15 10:45:10 +05:30
Kovid Goyal
6127d2d122 Make the sprite map globally accessible from C code as well as python code
The lock was removed as the Python GIL is sufficient to serialize access
to the SpriteMap structure.
2017-09-15 10:45:10 +05:30
Kovid Goyal
4feff2e2da Fix rendering of strikethrough not working 2017-09-15 10:45:10 +05:30
Kovid Goyal
8624dbac2c Sigh, stupid OpenGL
Apparently glGetUniformIndices has different declarations on different
systems.
2017-09-15 10:45:10 +05:30
Kovid Goyal
4c0cf93562 Fix tab bar not rendering because of selection handling changes 2017-09-15 10:45:10 +05:30
Kovid Goyal
d12573a67d Dont send the color table to the GPU on every frame 2017-09-15 10:45:09 +05:30
Kovid Goyal
d7b433f6b7 API for Uniform Block Objects 2017-09-15 10:45:09 +05:30
Kovid Goyal
b1168f6c6c Handle zero timeout correctly 2017-09-15 10:45:09 +05:30
Kovid Goyal
91e263cabb Fix sub-millisecond and no event waits not working 2017-09-15 10:45:09 +05:30
Kovid Goyal
ed15f2f97e Get the layout of the Cell structure 2017-09-15 10:45:09 +05:30
Kovid Goyal
6689595277 Dont use Py_UCS4 for char_type 2017-09-15 10:45:09 +05:30
Kovid Goyal
34f946fd98 Move rendering of selection to GPU 2017-09-15 10:45:09 +05:30
Kovid Goyal
a5bec84554 ... 2017-09-15 10:45:09 +05:30
Kovid Goyal
0fae3e1b10 ... 2017-09-15 10:45:09 +05:30
Kovid Goyal
a56e1296fd Refactor the tab bar into its own class
Also ensure that Screen APIs are only used in the child thread in the
tab bar
2017-09-15 10:45:09 +05:30
Kovid Goyal
acdeaaeda5 Move the border shaders into their own files 2017-09-15 10:45:08 +05:30
Kovid Goyal
a44e3a3a50 Ensure line numbers reported by the GLSL compiler are correct 2017-09-15 10:45:08 +05:30
Kovid Goyal
db40445572 Do color mapping on the GPU 2017-09-15 10:45:08 +05:30
Kovid Goyal
1d888c9194 Centralise color management into ColorProfile 2017-09-15 10:45:08 +05:30
Kovid Goyal
b50eaa9cbb ColorProfile should belong to Screen 2017-09-15 10:45:08 +05:30
Kovid Goyal
fe764ab6b6 oops 2017-09-15 10:45:08 +05:30
Kovid Goyal
bab4680828 ... 2017-09-15 10:45:08 +05:30
Kovid Goyal
564010c7cd Migrate history.c 2017-09-15 10:45:08 +05:30
Kovid Goyal
052fd46ff9 Migrate sprites.c 2017-09-15 10:45:08 +05:30
Kovid Goyal
4fd8c7cfaa DRYer 2017-09-15 10:45:08 +05:30
Kovid Goyal
37f0cf86d0 Migrated line.c 2017-09-15 10:45:07 +05:30
Kovid Goyal
0cbd3a2820 Start work on using a struct for the cell
Should eventually allow the screen buf to be sent directly to the GPU
without a serialization step.

Migrates line-buf.c
2017-09-15 10:45:07 +05:30
Kovid Goyal
af3c89d79f oops 2017-09-15 10:45:07 +05:30
Kovid Goyal
a1d75eb00d Use a function pointer to avoid a branch in loop() 2017-09-15 10:45:07 +05:30
Kovid Goyal
6176607ac4 Initial stab at switching to poll() instead of select()
Also avoid python code in the child monitoring inner loop
2017-09-15 10:45:07 +05:30
Kovid Goyal
40254625d9 Fix timers not being replaced 2017-09-15 10:45:07 +05:30
Kovid Goyal
29b16d0856 Fix timers not being re-sorted on replace 2017-09-15 10:45:07 +05:30
Kovid Goyal
ff72b1f96f Limit sprite co-ordinates to fit in uint16_t 2017-09-15 10:45:07 +05:30
Kovid Goyal
a429bcbb22 Dont use the glfw timer function as it requires glfwInit 2017-09-15 10:45:07 +05:30
Kovid Goyal
3c7305b93c ... 2017-09-15 10:45:07 +05:30
Kovid Goyal
f9b1a71edd Move the timers implementation to C
It is used int he hot loop for monitoring the child process
2017-09-15 10:45:06 +05:30
Kovid Goyal
2de0c82f18 Fix incorrect full keyboard mode escape codes 2017-09-15 10:44:56 +05:30
Kovid Goyal
cdb12f2049 Fix #122 2017-09-13 14:20:20 +05:30
Kovid Goyal
ca310fc2f2 Add a note about border visibility 2017-09-12 06:52:33 +05:30
Kovid Goyal
273210cb97 Ignore resize requests for very small sizes. Fixes #119 2017-08-28 20:31:01 +05:30
Kovid Goyal
b957ef441c Avoid function name conflict with index from string.h
Hopefully Fixes #118
2017-08-27 21:17:18 +05:30
Kovid Goyal
31775c8b50 ... 2017-08-26 15:19:33 +05:30
Kovid Goyal
8199802b44 Remove unused code 2017-08-26 15:10:55 +05:30
Kovid Goyal
941c553172 Implement an option to adjust the line height
Fixes #116
2017-08-26 14:14:51 +05:30
Kovid Goyal
8ee1c851a1 Optimize the bit twiddling in sprite_position_for 2017-08-26 13:05:18 +05:30
Kovid Goyal
4ce9f550ac Inline to_color for an easy performance boost 2017-08-26 10:52:24 +05:30
Kovid Goyal
7041616837 More semantic handling of profile arg when compiling 2017-08-26 10:36:04 +05:30
Kovid Goyal
6a3c812470 Forgot to remove python profiling from one place 2017-08-26 10:35:11 +05:30
Kovid Goyal
778b090467 ... 2017-08-26 10:25:50 +05:30
Kovid Goyal
a922b4c789 Add instrumentation to analyse kitty performance 2017-08-26 10:24:12 +05:30
Kovid Goyal
e43bf891e4 Print a warning when the specified font family does not exist 2017-08-25 09:55:46 +05:30
Kovid Goyal
fa8203ff31 CoreText: Use a scoring function to find the best matching font
Also if the specified family does not exist, fallback to Menlo
2017-08-25 09:53:11 +05:30
Kovid Goyal
212207d667 Test function for family matching 2017-08-24 22:27:28 +05:30
Kovid Goyal
95a3c51a4b Remove unused code 2017-08-24 22:22:55 +05:30
Kovid Goyal
697a7b78b3 macOS: Fix selecting fonts using full names (including sub-family) not working
Fixes #83
2017-08-24 19:16:12 +05:30
Kovid Goyal
58644e2b37 Function to get all fonts on macOS 2017-08-24 15:05:42 +05:30
Kovid Goyal
ddcd4daede macOS: Fix wide characters having their right edges slightly truncated 2017-08-24 12:46:41 +05:30
Kovid Goyal
678bd97e1f Merge branch 'patch-1' of https://github.com/leonardt/kitty 2017-08-24 08:01:52 +05:30
Leonard (Lenny) Truong
2eb4bf7a1d Typo fix in default kitty.conf 2017-08-23 14:28:51 -07:00
Kovid Goyal
e0e517d6ec Modify VAO API to allow using multiple buffers 2017-08-23 17:32:46 +05:30
Kovid Goyal
b6679ff7b5 version 0.3.0 2017-08-23 07:25:37 +05:30
Kovid Goyal
de80003103 macOS: Show the current window title in the global menu bar 2017-08-22 22:46:46 +05:30
Kovid Goyal
2b0596c7f9 Add a basic global menubar on macOS
Fixes #111
2017-08-22 20:59:56 +05:30
Kovid Goyal
3d15a1d786 Fix textures not being rendered in a render call that also uploads textures
The active texture should not be unbound in the upload texture functions
2017-08-22 18:34:25 +05:30
Kovid Goyal
1fcb865202 ... 2017-08-22 18:19:46 +05:30
Kovid Goyal
1c56de5605 Change default usage mode to GL_STREAM_DRAW 2017-08-22 18:10:28 +05:30
Kovid Goyal
adbce71fb4 Remove unused code 2017-08-22 18:04:40 +05:30
Kovid Goyal
00e3ea8c08 Remove unused code 2017-08-22 17:32:40 +05:30
Kovid Goyal
36432c8616 API to conveniently download data from a vertex buffer 2017-08-22 12:51:30 +05:30
Kovid Goyal
03e0b9de04 Use vertex buffers instead of texture buffers
Apparently, integer samplers for textFetch() are broken on some macOS
Intel drivers. Fixes #101
2017-08-22 12:08:35 +05:30
Kovid Goyal
4364163ceb Use a single buffer for multiple vertex arrays 2017-08-22 07:59:51 +05:30
Kovid Goyal
ffd9ec653d Allow programs to be used with multiple vertex array objects 2017-08-22 00:24:45 +05:30
Kovid Goyal
ee3c3e4cb4 Binding for DeleteVertexArray 2017-08-22 00:18:03 +05:30
Kovid Goyal
277c46908d Remove unused code 2017-08-21 23:55:39 +05:30
Kovid Goyal
8e27c80e1f A spot of refactoring 2017-08-21 23:26:30 +05:30
Kovid Goyal
afa767c3a8 Support vertex attrib divisors 2017-08-21 23:24:05 +05:30
Kovid Goyal
67ec04fba3 Also use the buffer manager for vertex arrays 2017-08-21 23:10:25 +05:30
Kovid Goyal
f35bf7f1ba Move buffer management into its own class 2017-08-21 22:53:13 +05:30
Kovid Goyal
4fdb55e260 Ensure window with hidden chrome is resizable on macOS 2017-08-21 21:06:34 +05:30
Kovid Goyal
be06669e8f Ensure we dont exceed GL_MAX_TEXTURE_BUFFER_SIZE 2017-08-21 20:53:02 +05:30
Kovid Goyal
313253cd95 Add glFlush() and glFinish() bindings 2017-08-21 19:55:28 +05:30
Kovid Goyal
8c16be2ccd Remove unused code 2017-08-21 19:38:52 +05:30
Kovid Goyal
e1b276786b Fix #112 2017-08-21 19:10:06 +05:30
Kovid Goyal
05f5a05c20 Ensure sprite map size tracking is always correct 2017-08-21 17:39:30 +05:30
Kovid Goyal
7e79aac275 Fix incorrect tracking of previous buffer sizes to avoid re-allocs 2017-08-21 17:12:46 +05:30
Kovid Goyal
0a21819e16 DRYer 2017-08-21 16:53:04 +05:30
Kovid Goyal
fe3e51a00d Move the GLSL shaders into their own files 2017-08-21 16:39:34 +05:30
Kovid Goyal
21874339f1 Remove un-needed binding of the sprite_map buffer 2017-08-21 15:51:55 +05:30
Kovid Goyal
4f22fcdaac Code to verify buffer uploads are working 2017-08-21 15:30:50 +05:30
Kovid Goyal
0424d665d5 Function to read data from OpenGL buffers 2017-08-21 15:29:05 +05:30
Kovid Goyal
0bbea6812e Avoid unnecessary reallocs for cell data
Only re-allocate when the buffer size changes
2017-08-21 14:56:29 +05:30
Kovid Goyal
101a50b0ff Do not use GL_ARB_texture_buffer_object_rgb32
This is not available on macOS using Intel graphics cards
2017-08-21 12:46:09 +05:30
Kovid Goyal
a9f3a698d2 Also check for required OpenGL extensions on OS X 2017-08-21 11:21:57 +05:30
Kovid Goyal
5117a2c17a version 0.2.8 2017-08-05 08:21:20 +05:30
Kovid Goyal
ebce1d7c61 Fix incorrect handling of escape codes to change default foreground and background colors. Fixes #104 2017-08-04 21:57:22 +05:30
Kovid Goyal
e4668c1aff Replay set_dynamic_color and set_color_table_color 2017-08-04 20:47:59 +05:30
Kovid Goyal
2519c49c02 Fix incorrect escape codes generated when using the obsolete "normal" mouse protocol.
Fixes #105
2017-08-04 20:09:18 +05:30
Kovid Goyal
9e512ff58a Ensure queue_action is only called after the Tab object is fully initialized
Fix #103
2017-08-04 07:52:25 +05:30
Kovid Goyal
ed50595aca Add a --detach option
Allows kitty to detach itself from the controlling terminal. Useful
when launching kitty from a GUI environment with broken stdout/stderr or
when launching from a terminal that you want to close later without
affecting the launched kitty instance.
2017-08-03 22:35:47 +05:30
Kovid Goyal
9d62d087e0 Redirect xsel std streams to /dev/null
Prevents hanging if the streams are blocked. Fixes #102
2017-08-03 21:55:09 +05:30
Kovid Goyal
6b933e33f5 If the saved initial window size fails, retry creating the window with a standard size. Fixes #98 2017-07-30 08:32:51 +05:30
Kovid Goyal
a86931f401 Use the new glfw API to set WM_CLASS if available 2017-07-27 18:11:23 +05:30
Kovid Goyal
fc4e1595e8 Print a warning about unknown config keys 2017-07-23 22:59:30 +05:30
Kovid Goyal
b36c3f3425 Clean up config merging 2017-07-23 22:45:57 +05:30
Kovid Goyal
e427fd1233 Fix #95 2017-07-23 21:36:43 +05:30
Kovid Goyal
dd3af45043 Implement a send_text action to allow using keyboard shortcuts to send arbitrary text
Fixes #94
2017-07-23 14:37:15 +05:30
Kovid Goyal
304d42d4c2 Fix #93
Ignore invalid language names returned by the coca framework on macOS
2017-07-16 22:49:05 +05:30
Kovid Goyal
abca9280e7 Fix #92 2017-07-15 08:22:40 +05:30
211 changed files with 151487 additions and 8870 deletions

13
.gitattributes vendored Normal file
View File

@@ -0,0 +1,13 @@
kitty/wcwidth-std.h linguist-generated=true
kitty/emoji.h linguist-generated=true
kitty/keys.h linguist-generated=true
kitty/charsets.c linguist-generated=true
kitty/key_encoding.py linguist-generated=true
kitty/unicode-data.c
kitty/rgb.py linguist-generated=true
kitty/gl-wrapper.* linguist-generated=true
kitty/khrplatform.h linguist-generated=true
kitty/glfw-wrapper.* linguist-generated=true
glfw/*.c linguist-vendored=true
glfw/*.h linguist-vendored=true
kittens/unicode_input/names.h linguist-generated=true

15
.gitignore vendored
View File

@@ -1,10 +1,15 @@
*.js
*.pyj-cached
*.so
.build-cache
*.pyc
*.pyo
tags
build
README.html
linux-package
kitty.app
logo/*.iconset
test-launcher
compile_commands.json
glad/out
asan-launcher
kitty-profile
dev
__pycache__
glfw/wayland-*-client-protocol.[ch]

View File

@@ -13,11 +13,17 @@ matrix:
apt:
packages:
- libfontconfig1-dev
- libglew-dev
- libharfbuzz-dev
- libxi-dev
- libxrandr-dev
- libxinerama-dev
- libxcursor-dev
- libunistring-dev
- libxcb-xkb-dev
- libxkbcommon-dev
- libxkbcommon-x11-dev
- libpng-dev
- python3-pil
- os: linux
dist: trusty
@@ -31,11 +37,17 @@ matrix:
apt:
packages:
- libfontconfig1-dev
- libglew-dev
- libharfbuzz-dev
- libxi-dev
- libxrandr-dev
- libxinerama-dev
- libxcursor-dev
- libunistring-dev
- libxcb-xkb-dev
- libxkbcommon-dev
- libxkbcommon-x11-dev
- libpng-dev
- python3-pil
- os: linux
dist: trusty
@@ -44,16 +56,22 @@ matrix:
env:
- RUN_FLAKE=1 BUILD_PKG=1
language: python
python: "3.5"
python: "3.6"
addons:
apt:
packages:
- libfontconfig1-dev
- libglew-dev
- libharfbuzz-dev
- libxi-dev
- libxrandr-dev
- libxinerama-dev
- libxcursor-dev
- libunistring-dev
- libxcb-xkb-dev
- libxkbcommon-dev
- libxkbcommon-x11-dev
- libpng-dev
- python3-pil
- clang
- os: osx
language: generic
@@ -66,8 +84,8 @@ matrix:
env:
global:
- PYTHON=python3
- PKG_CONFIG_PATH=$HOME/glfw/lib/pkgconfig:$PKG_CONFIG_PATH
- LD_LIBRARY_PATH=$HOME/glfw/lib:$LD_LIBRARY_PATH
- PKG_CONFIG_PATH=$HOME/harfbuzz/lib/pkgconfig:$PKG_CONFIG_PATH
- LD_LIBRARY_PATH=$HOME/harfbuzz/lib:$LD_LIBRARY_PATH
- ASAN_OPTIONS=leak_check_at_exit=0
install: |
@@ -76,22 +94,24 @@ install: |
if [[ "$TRAVIS_OS_NAME" == 'osx' ]]; then
if [[ "$USE_BREW" == "1" ]]; then
brew update;
brew install python3;
brew install glfw;
brew upgrade python;
brew install harfbuzz --without-glib --without-gobject-introspection --without-graphite2 --without-icu4c --without-freetype;
else
mkdir -p $SW;
curl https://download.calibre-ebook.com/travis/kitty/osx.tar.xz | tar xJ -C $SW;
fi
else
wget -O glfw-3.2.1.zip https://github.com/glfw/glfw/archive/3.2.1.zip
unzip -q glfw-3.2.1.zip
cd glfw-3.2.1
cmake -DBUILD_SHARED_LIBS=ON -DGLFW_BUILD_EXAMPLES=OFF -DGLFW_BUILD_TESTS=OFF -DGLFW_BUILD_DOCS=OFF -DCMAKE_INSTALL_PREFIX=$HOME/glfw
make
pushd /tmp
wget https://github.com/behdad/harfbuzz/releases/download/1.6.3/harfbuzz-1.6.3.tar.bz2
tar xf harfbuzz-1.6.3.tar.bz2
cd harfbuzz-1.6.3
./configure --prefix=$HOME/harfbuzz --disable-dependency-tracking --disable-static --with-glib=no --with-gobject=no --with-cairo=no --with-fontconfig=no --with-icu=no --with-directwrite=no --with-freetype=yes
make -j2
make install
cd ..
popd
fi
pkg-config --cflags glfw3
pkg-config --cflags harfbuzz
if [[ "$TRAVIS_OS_NAME" != 'osx' ]]; then
PLIB=$(ldd `which python` | grep libpython | cut -d ' ' -f 3)
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:`dirname $PLIB`
@@ -100,10 +120,10 @@ install: |
before_script:
- echo $LD_LIBRARY_PATH
- $PYTHON setup.py build --debug $SANITIZE_ARG;
- if [[ "$TRAVIS_OS_NAME" != 'osx' ]]; then ldd ./test-launcher `which $PYTHON`; fi
- $PYTHON setup.py build --debug --verbose $SANITIZE_ARG;
script:
- ./test-launcher
- if grep -Inr '\s$' kitty kitty_tests *.py *.asciidoc .gitattributes .gitignore; then echo Trailing whitespace found, aborting.; exit 1; fi
- if [[ -z $SANITIZE_ARG ]]; then $PYTHON test.py; else ./asan-launcher test.py; fi
- if [[ "$RUN_FLAKE" == "1" ]]; then flake8 --count .; fi
- if [[ "$BUILD_PKG" == "1" ]]; then $PYTHON setup.py linux-package; fi

364
CHANGELOG.rst Normal file
View File

@@ -0,0 +1,364 @@
Changelog
==============
kitty is a feature full, cross-platform, *fast*, GPU based terminal emulator.
version 0.8.3 [2018-03-29]
-----------------------------
- Fix a regression that broke the visual bell and invert screen colors escape
code
- Allow double-click and triple-click + drag to extend selections word at a
time or line at a time
- Add a keyboard shortcut to set the tab title
- Fix setting window title to empty via OSC escape code not working correctly
- Linux: Fix cell width calculation incorrect for some fonts (cell widths are
now calculated by actually rendering bitmaps, which is slower but more
accurate)
- Allow specifying a system wide kitty config file, for all users
- Add a --debug-config command line flag to output data about the system and
kitty configuration.
- Wayland: Fix auto-repeat of keys not working
version 0.8.2 [2018-03-17]
-----------------------------
- Allow extending existing selections by right clicking
- Add a configurable keyboard shortcut and remote command to set the font size to a specific value
- Add an option to have kitty close the window when the main processes running in it exits, even if there are still background processes writing to that terminal
- Add configurable keyboard shortcuts to switch to a specific layout
- Add a keyboard shortcut to edit the kitty config file easily
- macOS: Fix restoring of window size not correct on Retina screens
- macOS: Add a facility to specify command line arguments when running kitty from the GUI
- Add a focus-tab remote command
- Fix screen not being refreshed immediately after moving a window.
- Fix a crash when getting the contents of the scrollback buffer as text
version 0.8.1 [2018-03-09]
-----------------------------
- Extend kitty's remote control feature to work over both UNIX and TCP sockets,
so now you can control kitty from across the internet, if you want to.
- Render private use unicode characters that are followed by a space as a two
character ligature. This fixes rendering for applications that misuse
private-use characters to display square symbols.
- Fix Unicode emoji presentation variant selector causing new a fallback font
instance to be created
- Fix a rare error that prevented the Unicode input kitten from working
sometimes
- Allow using Ctrl+Alt+letter in legacy keyboard modes by outputting them as Ctrl+letter and Alt+letter.
This matches other terminals' behavior.
- Fix cursor position off-by-one on horizontal axis when resizing the terminal
- Wayland: Fix auto-repeat of keys not working
- Wayland: Add support for window decorations provided by the Wayland shell
- macOS: Fix URL hints not working
- macOS: Fix shell not starting in login mode on some computers
- macOS: Output errors into console.app when running as a bundle
version 0.8.0 [2018-02-24]
-----------------------------
- A framework for kittens, that is, small terminal programs designed to run
inside kitty and extend its capabilities. Examples include unicode input and
selecting URLs with the keyboard.
- Input arbitrary unicode characters by pressing Ctrl+Shift+u. You can choose
characters by name, by hex code, by recently used, etc. There is even and
editable Favorites list.
- Open URLs using only the keyboard. kitty has a new "hints mode". Press
Ctrl+Shift+e and all detected URLs on the screen are highlighted with a key
to press to open them. The facility is customizable so you can change
what is detected as a URL and which program is used to open it.
- Add an option to change the titlebar color of kitty windows on macOS
- Only consider Emoji characters with default Emoji presentation to be two
cells wide. This matches the standard. Also add support for the Unicode Emoji
variation presentation selector.
- Prevent video tearing during high speed scrolling by syncing draws
to the monitor's refresh rate. There is a new configuration option to
control this ``sync_to_monitor``.
- When displaying only a single window, use the default background color of the
window (which can be changed via escape codes) as the color for the margin
and padding of the window.
- Add some non standard terminfo capabilities used by neovim and tmux.
- Fix large drop in performance when using multiple top-level windows on macOS
- Fix save/restore of window sizes not working correctly.
- Remove option to use system wcwidth(). Now always use a wcwidth() based on
the Unicode standard. Only sane way.
- Fix a regression that caused a few ligature glyphs to not render correctly in
rare circumstances.
- Browsing the scrollback buffer now happens in an overlay window instead of a
new window/tab.
version 0.7.1 [2018-01-31]
---------------------------
- Add an option to adjust the width of character cells
- Fix selecting text with the mouse in the scrollback buffer selecting text
from the line above the actually selected line
- Fix some italic fonts having the right edge of characters cut-off,
unnecessarily
version 0.7.0 [2018-01-24]
---------------------------
- Allow controlling kitty from the shell prompt/scripts. You can
open/close/rename windows and tabs and even send input to specific windows.
See the README for details.
- Add option to put tab bar at the top instead of the bottom
- Add option to override the default shell
- Add "Horizontal" and "Vertical" window layouts
- Sessions: Allow setting titles and working directories for individual windows
- Option to copy to clipboard on mouse select
- Fix incorrect reporting of mouse move events when using the SGR protocol
- Make alt+backspace delete the previous word
- Take the mouse wheel multiplier option in to account when generating fake key
scroll events
- macOS: Fix closing top-level window does not transfer focus to other
top-level windows.
- macOS: Fix alt+arrow keys not working when disabling the macos_option_as_alt
config option.
- kitty icat: Workaround for bug in ImageMagick that would cause some images
to fail to display at certain sizes.
- Fix rendering of text with ligature fonts that do not use dummy glyphs
- Fix a regression that caused copying of the selection to clipboard to only
copy the visible part of the selection
- Fix incorrect handling of some unicode combining marks that are not re-ordered
- Fix handling on non-BMP combining characters
- Drop the dependency on libunistring
version 0.6.1 [2017-12-28]
---------------------------
- Add an option to fade the text in inactive windows
- Add new actions to open windows/tabs/etc. with the working directory set to
the working directory of the current window.
- Automatically adjust cell size when DPI changes, for example when kitty is
moved from one monitor to another with a different DPI
- Ensure underlines are rendered even for fonts with very poor metrics
- Fix some emoji glyphs not colored on Linux
- Internal wcwidth() implementation is now auto-generated from the unicode
standard database
- Allow configuring the modifiers to use for rectangular selection with the
mouse.
- Fix incorrect minimum wayland version in the build script
- Fix a crash when detecting a URL that ends at the end of the line
- Fix regression that broke drawing of hollow cursor when window loses focus
version 0.6.0 [2017-12-18]
---------------------------
- Support background transparency via the background_opacity option. Provided
that your OS/window manager supports transparency, you can now have kitty
render pixels that have only the default background color as
semi-transparent.
- Support multiple top level (OS) windows. These windows all share the sprite
texture cache on the GPU, further reducing overall resource usage. Use
the shortcut `ctrl+shift+n` to open a new top-level window.
- Add support for a *daemon* mode using the `--single-instance` command line
option. With this option you can have only a single kitty instance running.
All future invocations simply open new top-level windows in the existing
instance.
- Support colored emoji
- Use CoreText instead of FreeType to render text on macOS
- Support running on the "low power" GPU on dual GPU macOS machines
- Add a new "grid" window layout
- Drop the dependency on glfw (kitty now uses a modified, bundled copy of glfw)
- Add an option to control the audio bell volume on X11 systems
- Add a command line switch to set the name part of the WM_CLASS window
property independently.
- Add a command line switch to set the window title.
- Add more options to customize the tab-bar's appearance (font styles and
separator)
- Allow drag and drop of files into kitty. On drop kitty will paste the
file path to the running program.
- Add an option to control the underline style for URL highlighting on hover
- X11: Set the WINDOWID environment variable
- Fix middle and right buttons swapped when sending mouse events to child
processes
- Allow selecting in a rectangle by holding down Ctrl+Alt while dragging with
the mouse.
version 0.5.1 [2017-12-01]
---------------------------
- Add an option to control the thickness of lines in box drawing characters
- Increase max. allowed ligature length to nine characters
- Fix text not vertically centered when adjusting line height
- Fix unicode block characters not being rendered properly
- Fix shift+up/down not generating correct escape codes
- Image display: Fix displaying images taller than two screen heights not
scrolling properly
version 0.5.0 [2017-11-19]
---------------------------
- Add support for ligature fonts such as Fira Code, Hasklig, etc. kitty now
uses harfbuzz for text shaping which allow it to support advanced OpenType
features such as contextual alternates/ligatures/combining glyphs/etc.
- Make it easy to select fonts by allowing listing of monospace fonts using:
kitty list-fonts
- Add an option to have window focus follow mouse
- Add a keyboard shortcut (ctrl+shift+f11) to toggle fullscreen mode
- macOS: Fix handling of option key. It now behaves just like the alt key on
Linux. There is an option to make it type unicode characters instead.
- Linux: Add support for startup notification on X11 desktops. kitty will
now inform the window manager when its startup is complete.
- Fix shell prompt being duplicated when window is resized
- Fix crash when displaying more than 64 images in the same session
- Add support for colons in SGR color codes. These are generated by some
applications such as neovim when they mistakenly identify kitty as a libvte
based terminal.
- Fix mouse interaction not working in apps using obsolete mouse interaction
protocols
- Linux: no longer require glew as a dependency
version 0.4.2 [2017-10-23]
---------------------------
- Fix a regression in 0.4.0 that broke custom key mappings
- Fix a regression in 0.4.0 that broke support for non-QWERTY keyboard layouts
- Avoid using threads to reap zombie child processes. Also prevent kitty from
hanging if the open program hangs when clicking on a URL.
version 0.4.0 [2017-10-22]
---------------------------
- Support for drawing arbitrary raster graphics (images) in the terminal via a
new graphics protocol. kitty can draw images with full 32-bit color using both
ssh connections and files/shared memory (when available) for better
performance. The drawing primitives support alpha blending and z-index.
Images can be drawn both above and below text. See
https://github.com/kovidgoyal/kitty/blob/master/graphics-protocol.asciidoc
for details.
- Refactor kitty's internals to make it even faster and more efficient. The CPU
usage of kitty + X server while doing intensive tasks such as scrolling a
file continuously in less has been reduced by 50%. There are now two
configuration options ``repaint_delay`` and ``input_delay`` you can use to
fine tune kitty's performance vs CPU usage profile. The CPU usage of kitty +
X when scrolling in less is now significantly better than most (all?) other
terminals. See https://github.com/kovidgoyal/kitty#performance
- Hovering over URLs with the mouse now underlines them to indicate they
can be clicked. Hold down Ctrl+Shift while clicking to open the URL.
- Selection using the mouse is now more intelligent. It does not add
blank cells (i.e. cells that have no content) after the end of text in a
line to the selection.
- The block cursor in now fully opaque but renders the character under it in
the background color, for enhanced visibility.
- Allow combining multiple independent actions into a single shortcut
- Add a new shortcut to pass the current selection to an external program
- Allow creating shortcuts to open new windows running arbitrary commands. You
can also pass the current selection to the command as an arguments and the
contents of the screen + scrollback buffer as stdin to the command.

25
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,25 @@
### Reporting bugs
Please first search existing bug reports (especially closed ones) for a report
that matches your issue.
When reporting a bug, provide full details of your environment, that means, at
a minimum, kitty version, OS and OS version, kitty config (ideally a minimal
config to reproduce the issue with).
### Contributing code
Install [the dependencies](https://github.com/kovidgoyal/kitty#dependencies)
using your favorite package manager. Build and run kitty [from
source](https://github.com/kovidgoyal/kitty#install-and-run-from-source).
Make a fork, submit your Pull Request. If it's a large/controversial change, open an issue
beforehand to discuss it, so that you don't waste your time making a pull
request that gets rejected.
If the code you are submitting is reasonably easily testable, please contribute
tests as well (see the `kitty_tests/` sub-directory for existing tests, which
can be run with `./test.py`).
That's it.

View File

@@ -1,5 +1,34 @@
ifdef V
VVAL=--verbose
endif
ifdef VERBOSE
VVAL=--verbose
endif
all:
python3 setup.py
python3 setup.py $(VVAL)
test:
python3 setup.py test
python3 setup.py $(VVAL) test
clean:
python3 setup.py $(VVAL) clean
# A debug build
debug:
python3 setup.py build $(VVAL) --debug
# Build with the ASAN and UBSAN sanitizers
asan:
python3 setup.py build $(VVAL) --debug --sanitize
profile:
python3 setup.py build $(VVAL) --profile
logo/kitty.iconset/icon_256x256.png: logo/kitty.svg logo/make.py
logo/make.py
rendered_logo: logo/kitty.iconset/icon_256x256.png
app: rendered_logo
python3 setup.py kitty.app $(VVAL)

View File

@@ -5,25 +5,33 @@
:sc_close_tab: pass:quotes[`ctrl+shift+q`]
:sc_close_window: pass:quotes[`ctrl+shift+w`]
:sc_copy_to_clipboard: pass:quotes[`ctrl+shift+c`]
:sc_decrease_font_size: pass:quotes[`ctrl+shift+minus`]
:sc_edit_config_file: pass:quotes[`ctrl+shift+f2`]
:sc_eighth_window: pass:quotes[`ctrl+shift+8`]
:sc_fifth_window: pass:quotes[`ctrl+shift+5`]
:sc_first_window: pass:quotes[`ctrl+shift+1`]
:sc_fourth_window: pass:quotes[`ctrl+shift+4`]
:sc_increase_font_size: pass:quotes[`ctrl+shift+equal`]
:sc_input_unicode_character: pass:quotes[`ctrl+shift+u`]
:sc_move_tab_backward: pass:quotes[`ctrl+shift+,`]
:sc_move_tab_forward: pass:quotes[`ctrl+shift+.`]
:sc_move_window_backward: pass:quotes[`ctrl+shift+b`]
:sc_move_window_forward: pass:quotes[`ctrl+shift+f`]
:sc_move_window_to_top: pass:quotes[`ctrl+shift+``]
:sc_new_os_window: pass:quotes[`ctrl+shift+n`]
:sc_new_tab: pass:quotes[`ctrl+shift+t`]
:sc_new_window: pass:quotes[`ctrl+shift+enter`]
:sc_next_layout: pass:quotes[`ctrl+shift+l`]
:sc_next_tab: pass:quotes[`ctrl+shift+right`]
:sc_next_window: pass:quotes[`ctrl+shift+]`]
:sc_ninth_window: pass:quotes[`ctrl+shift+9`]
:sc_pass_selection_to_program: pass:quotes[`ctrl+shift+o`]
:sc_paste_from_clipboard: pass:quotes[`ctrl+shift+v`]
:sc_paste_from_selection: pass:quotes[`ctrl+shift+s` or `shift+insert`]
:sc_previous_tab: pass:quotes[`ctrl+shift+left`]
:sc_previous_window: pass:quotes[`ctrl+shift+[`]
:sc_restore_font_size: pass:quotes[`ctrl+shift+backspace`]
:sc_run_simple_kitten_text_url_hints: pass:quotes[`ctrl+shift+e`]
:sc_scroll_end: pass:quotes[`ctrl+shift+end`]
:sc_scroll_home: pass:quotes[`ctrl+shift+home`]
:sc_scroll_line_down: pass:quotes[`ctrl+shift+down` or `ctrl+shift+j`]
@@ -31,11 +39,13 @@
:sc_scroll_page_down: pass:quotes[`ctrl+shift+page_down`]
:sc_scroll_page_up: pass:quotes[`ctrl+shift+page_up`]
:sc_second_window: pass:quotes[`ctrl+shift+2`]
:sc_set_tab_title: pass:quotes[`ctrl+shift+alt+t`]
:sc_seventh_window: pass:quotes[`ctrl+shift+7`]
:sc_show_scrollback: pass:quotes[`ctrl+shift+h`]
:sc_sixth_window: pass:quotes[`ctrl+shift+6`]
:sc_tenth_window: pass:quotes[`ctrl+shift+0`]
:sc_third_window: pass:quotes[`ctrl+shift+3`]
:sc_toggle_fullscreen: pass:quotes[`ctrl+shift+f11`]
// END_SHORTCUT_BLOCK
++++
@@ -45,26 +55,32 @@ image::https://travis-ci.org/kovidgoyal/kitty.svg?branch=master[Build status, li
== Major Features
* Uses OpenGL for rendering, offloads rendering to the GPU for link:#performance[lower system
load] and buttery smooth scrolling. Uses threaded rendering to minimize input
latency.
* Supports all modern terminal features: link:graphics-protocol.asciidoc[graphics (images)], unicode,
true-color, OpenType ligatures, mouse protocol, focus tracking, bracketed paste and so on.
* Supports tiling multiple terminal windows side by side in different
layouts without needing to use an extra program like tmux
link:#layouts[layouts] without needing to use an extra program like tmux
* Supports all modern terminal features: unicode, true-color, mouse
protocol, focus tracking, bracketed paste and so on.
* Can be link:remote-control.asciidoc[controlled from scripts or the shell prompt], even over SSH.
* Allows you to view the scrollback buffer in a separate window
using your favorite pager program such as less
* Has a framework for _kittens_, small terminal programs that can be used to extend kitty's functionality.
For example, they are used for link:#unicode-input[Unicode input] and link:#url-hints[URL hints].
* Support startup sessions which allow you to specify the window/tab layout,
* Supports link:#startup-sessions[startup sessions] which allow you to specify the window/tab layout,
working directories and programs to run on startup.
* Easily hackable (UI layer written in python, inner loops in C for
speed). Less than ten thousand lines of code.
* Cross-platform support: kitty currently works on Linux and macOS, but because
it uses only OpenGL for rendering, it should be trivial to port to other
platforms.
* Uses OpenGL for rendering, offloads rendering work to the GPU for lower system load.
* Allows you to open link:#the-scrollback-buffer[the scrollback buffer] in a separate
window using arbitrary programs of your choice. This is useful for browsing
the history comfortably in a pager or editor.
* Cross-platform support: kitty currently works on Linux and macOS, but because it
uses only OpenGL for rendering, it should be trivial to port to
other platforms.
image::screenshot.png?raw=true[Screenshot, showing three programs in the "Tall" layout]
@@ -79,12 +95,15 @@ the following dependencies are installed first.
=== Dependencies
* python >= 3.5
* glfw >= 3.2
* glew >= 2.0 (not needed on macOS)
* harfbuzz >= 1.5.0
* zlib
* libpng
* freetype (not needed on macOS)
* fontconfig (not needed on macOS)
* xrdb and xsel (only on X11 based systems)
* ImageMagick (optional, needed to use the `kitty icat` tool to display images in the terminal)
* gcc or clang (required only for building)
* pkg-config (required only for building)
* For building on Linux in addition to the above dependencies you might also need to install the `-dev` packages for `xcursor`, `xrandr`, `xinerama`, `libgl1-mesa` and `xkbcommon-x11`, if they are not already installed by your distro.
=== Install and run from source
@@ -95,27 +114,33 @@ git clone https://github.com/kovidgoyal/kitty && cd kitty
Now build the C parts of kitty with the following command:
....
python3 setup.py build
make
....
You can run kitty, as:
....
python3 /path/to/kitty/folder
python3 .
....
=== Linux packages
* Arch linux: AUR git package https://aur.archlinux.org/packages/kitty-git/
* Arch Linux: AUR git package https://aur.archlinux.org/packages/kitty-git/
* Arch Linux: AUR stable package https://aur.archlinux.org/packages/kitty/
* NixOS / nixpkgs: https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/misc/kitty/default.nix
* Gentoo: https://packages.gentoo.org/packages/x11-terms/kitty
* openSUSE: https://build.opensuse.org/package/show/X11:terminals/kitty
=== macOS packages
kitty is available as a macOS `dmg` file for easy installation from the
link:../../releases[releases page]. You can also run kitty directly from
source using the above install from source instructions, after installing its
two dependencies (`python >= 3.5` and `glfw >= 3.2` using http://brew.sh/[brew]
or a similar package manager)
dependencies using http://brew.sh/[brew] or a similar package manager.
== Design philosophy
@@ -123,7 +148,7 @@ or a similar package manager)
kitty is designed for power keyboard users. To that end all its controls
work with the keyboard (although it fully supports mouse interactions as
well). Its configuration is a simple, human editable, single file for
easy reproducability (I like to store config files in source control).
easy reproducibility (I like to store config files in source control).
The code in kitty is designed to be simple, modular and hackable. It is
written in a mix of C (for performance sensitive parts) and Python (for
@@ -178,6 +203,7 @@ windows are:
|Next layout | {sc_next_layout}
|Move tab forward | {sc_move_tab_forward}
|Move tab backward | {sc_move_tab_backward}
|Set tab title | {sc_set_tab_title}
|===
@@ -190,6 +216,7 @@ windows are:
|Action |Shortcut
|New window | {sc_new_window}
|New OS window| {sc_new_os_window}
|Close window | {sc_close_window}
|Next window | {sc_next_window}
|Previous window | {sc_previous_window}
@@ -200,50 +227,109 @@ windows are:
|===
=== Miscellaneous
|===
|Action |Shortcut
|Increase font size | {sc_increase_font_size}
|Decrease font size | {sc_decrease_font_size}
|Restore font size | {sc_restore_font_size}
|Toggle fullscreen | {sc_toggle_fullscreen}
|Input unicode character | {sc_input_unicode_character}
|Click URL using the keyboard | {sc_run_simple_kitten_text_url_hints}
|Pass current selection to program | {sc_pass_selection_to_program}
|Edit kitty config file| {sc_edit_config_file}
|===
== Controlling kitty from scripts
You can control kitty from the command line/scripts by sending it messages.
You can tell kitty to open/close/rename tabs and windows. You can even send
arbitrary input/text to any specified window. Messages can be sent using `kitty
@`. Note that you must set `allow_remote_control yes` in your
link:kitty/kitty.conf[kitty.conf] to use this feature. It even works over SSH
connections. This feature is best illustrated with a
link:remote-control.asciidoc[tutorial].
== The scrollback buffer
kitty supports scrolling back to view history, just like most terminals. You
can use either the <<scrolling-shortcuts,keyboard shortcuts>> or the mouse
scroll wheel to do so. However, kitty has an extra, neat feature. Sometimes you
need to explore the scrollback buffer in more detail, maybe search for some
scroll wheel to do so. However, kitty has an extra, neat feature. Sometimes
you need to explore the scrollback buffer in more detail, maybe search for some
text or refer to it side-by-side while typing in a follow-up command. kitty
allows you to do this by pressing the {sc_show_scrollback} key-combination,
which will open the scrollback buffer in a new window, using your favorite
pager program (which is `less` by default). You can then explore the scrollback
buffer using whatever program you normally use. Colors and text formatting are
preserved.
which will open the scrollback buffer in your favorite pager program (which is
`less` by default). Colors and text formatting are preserved. You can explore
the scrollback pager comfortably within the pager.
== Unicode input
You can input unicode characters by name, hex code, recently used and even an editable favorites list.
Press {sc_input_unicode_character} to start the unicode input widget, shown below.
image::unicode.png?raw=true[Unicode input widget, showing selection of unicode characters by name]
In Code mode, you enter a unicode character by typing in the hex code for the
character and pressing enter, for example, type in 2716 and press enter to get
✖. You can also choose a character from the list of recently used characters by
typing a leading period and then the two character index and pressing Enter.
In Name mode you instead type words from the character name and use the arrow
keys/tab to select the character from the displayed matches. You can also type
a leading period and the index for the match if you dont like to use arrow
keys.
== URL hints
kitty has a _hints mode_ to click URLs visible on the screen by using only the keyboard.
Press {sc_run_simple_kitten_text_url_hints} to activate hints mode, as shown below.
image::hints_mode.png?raw=true[URL hints mode]
== Miscellaneous features
You can double click to select a word and triple click to select a line. You can also
hold down `ctrl+shift` and click on a URL to open it in a browser.
* You can also hold down `ctrl+shift` and click on a URL to open it in a browser.
* You can double click to select a word and triple click to select a line.
* You can right click to extend a previous selection
== Layouts
Currently, there are two layouts available,
Currently, there are five layouts available,
* Stack -- Only a single maximized window is shown at a time
* Tall -- One window is shown full height on the left, the rest of the windows are shown one below the other on the right.
* Tall -- One window is shown full height on the left, the rest of the windows are shown one below the other on the right
* Grid -- All windows are shown in a grid
* Horizontal -- All windows are shown side-by-side
* Vertical -- All windows are shown one below the other
You can switch between layouts using the {sc_next_layout} key combination.
You can switch between layouts using the {sc_next_layout} key combination. You can
also create shortcuts to select particular layouts, and choose which layouts
you want to enable/disable, see link:kitty/kitty.conf[kitty.conf] for examples.
Writing a new layout only requires about thirty lines of code, so if there is
Writing a new layout only requires about fifty lines of code, so if there is
some layout you want, take a look at link:kitty/layout.py[layout.py] and submit
a pull request!
== Configuration
kitty is highly customizable, everything from keyboard shortcuts, to
painting frames-per-second. See the heavily commented
link:kitty/kitty.conf[default config file]. By default kitty looks for a
config file in the OS config directory (usually
`~/.config/kitty/kitty.conf` on Linux and
kitty is highly customizable, everything from keyboard shortcuts, to painting
frames-per-second. See the heavily commented link:kitty/kitty.conf[default
config file] for an overview of all customization possibilities.
By default kitty looks for a config file in the OS config directories (usually
`~/.config/kitty/kitty.conf` and additionally
`~/Library/Preferences/kitty/kitty.conf` on macOS) but you can pass a specific
path via the `--config` option.
path via the `--config` option or use the `KITTY_CONFIG_DIRECTORY` environment
variable. See the help for the `--config` option in `kitty --help` for full
details.
== Startup Sessions
@@ -254,11 +340,13 @@ command line flag. For example:
....
# Set the window layout for the current tab
layout tall
# Set the working directory for the current tab
# Set the working directory for windows in the current tab
cd ~
# Create a window and run the specified command in it
launch zsh
launch vim
# Set the title for the next window
title Chat with x
launch irssi --profile x
# Create a new tab (the part after new_tab is the optional tab name which will
@@ -292,6 +380,50 @@ come in handy for applications like powerline, without the need to use patched
fonts. See the various font related configuration directives in the
link:kitty/kitty.conf[config file].
== Performance
The main goals for kitty performance are user perceived latency while typing
and "smoothness" while scrolling as well as CPU usage. kitty tries hard to find
an optimum balance for these. To that end it keeps a cache of each rendered
glyph in video RAM so that font rendering is not a bottleneck. Interaction
with child programs takes place in a separate thread from rendering, to improve
smoothness.
There are two parameters you can tune to adjust the performance. ``repaint_delay``
and ``input_delay``. These control the artificial delays introduced into the
render loop to reduce CPU usage. See the link:kitty/kitty.conf[config file] for details.
See also the ``sync_to_monitor`` option to further decrease latency at the cost
of some link:https://en.wikipedia.org/wiki/Screen_tearing[tearing] while scrolling.
You can generate detailed per-function performance data using
link:https://github.com/gperftools/gperftools[gperftools]. Build kitty with
`make profile` which will create an executable called `kitty-profile`. Run
that and perform the task you want to analyse, for example, scrolling a large
file with `less`. After you quit, function call statistics will be printed to
`stdout` and you can use tools like *kcachegrind* for more detailed analysis.
Here are some CPU usage numbers for the task of scrolling a file continuously in less.
The CPU usage is for the terminal process and X together and is measured using htop.
The measurements are taken at the same font and window size for all terminals on a
`Intel(R) Core(TM) i7-4820K CPU @ 3.70GHz` CPU with a
`Advanced Micro Devices, Inc. [AMD/ATI] Cape Verde XT [Radeon HD 7770/8760 / R7 250X]` GPU.
|===
| Terminal | CPU usage (X + terminal)
| kitty | 6 - 8%
| xterm | 5 - 7% (but scrolling was extremely janky)
| termite | 10 - 13%
| urxvt | 12 - 14%
| gnome-terminal | 15 - 17%
| konsole | 29 - 31%
|===
As you can see, kitty uses much less CPU than all terminals, except xterm, but
its scrolling "smoothness" is much better than that of xterm (at least to my,
admittedly biased, eyes).
== Note for Linux/macOS packagers
While kitty does use python, it is not a traditional python package, so please do not install it in site-packages.
@@ -314,27 +446,95 @@ installs the terminfo file and `kitty` that installs the main program.
This allows users to install the terminfo file on servers into which they ssh,
without needing to install all of kitty.
You also need `tic` to compile the terminfo files, it is usually found in the development package of `ncurses`
This applies to creating packages for kitty for macOS package managers such as
brew or MacPorts as well.
== A tribute
While over the decades I am sure many people have contributed to the
development of the terminal emulator space, there is one individual in
particular I would like to thank. link:http://invisible-island.net[Thomas E.
Dickey], the creator of xterm. xterm is the most comprehensive and
feature-rich terminal emulator I have had the pleasure of using. As I worked on
kitty, I ran headlong into more and more gnarly corners of terminal behavior.
On all those occasions, either the excellent documentation at
link:http://invisible-island.net/xterm/ctlseqs/ctlseqs.html[xterm-ctlseqs] or
investigating the behavior and code of xterm or vttest were invaluable tools to
aid my understanding.
== Frequently Asked Questions
My achievements, if any, in developing kitty would not have been possible without
his prior work and the generous sharing of knowledge accumulated over decades.
=== Some special symbols are rendered small/truncated in kitty?
Thank you.
The number of cells a unicode character takes up are controlled by the unicode
standard. All characters are rendered in a single cell unless the unicode
standard says they should be rendered in two cells. When a symbol does not fit,
it will either be rescaled to be smaller or truncated (depending on how much
extra space it needs). This is often different from other terminals which just
let the character overflow into neighboring cells, which is fine if the
neighboring cell is empty, but looks terrible if it is not.
Some programs, like powerline, vim with fancy gutter symbols/status-bar, etc.
misuse unicode characters from the private use area to represent symbols. Often
these symbols are square and should be rendered in two cells. However, since
private use area symbols all have their width set to one in the unicode
standard, kitty renders them either smaller or truncated. The exception is if
these characters are followed by a space or empty cell in which case kitty
makes use of the extra cell to render them in two cells.
=== How do I build kitty.app on macOS?
Install `imagemagick`, `optipng` and `librsvg` using `brew` or similar (needed for the logo generation step).
And run:
```
make app
```
This `kitty.app` unlike the released one does not include its own copy of
python and the other dependencies. So if you ever un-install/upgrade those dependencies
you might have to rebuild the app.
Note that the released kitty.dmg includes all dependencies, unlike the
`kitty.app` built above and is built automatically by using the `kitty` branch of
link:https://github.com/kovidgoyal/build-calibre[build-calibre] however, that
is designed to run on Linux and is not for the faint of heart.
=== Using a color theme with a background color does not work well in vim?
First make sure you have not changed the TERM environment variable, it should
be `xterm-kitty`. vim uses *background color erase* even if the terminfo file
does not contain the `bce` capability. This is a bug in vim. You can work around
it by adding the following to your vimrc:
....
let &t_ut=''
....
See link:https://github.com/kovidgoyal/kitty/blob/master/protocol-extensions.asciidoc#setting-text-styles-colors-in-arbitrary-regions-of-the-screen[here]
for why kitty does not support background color erase.
=== I get errors about the terminal being unknown or opening the terminal failing when SSHing into a different computer?
This happens because the kitty terminfo files are not available on the server.
Either install kitty on the server, or simply copy over the terminfo files,
using:
....
ssh myserver mkdir -p \~/.terminfo
infocmp xterm-kitty | ssh myserver "cat > /tmp/kitty.terminfo"
ssh myserver tic -x -o \~/.terminfo /tmp/kitty.terminfo
....
Really, the correct solution for this is to convince the OpenSSH maintainers to
have ssh do this automatically when connecting to a server, so that all
terminals work transparently.
=== How do I specify command line options for kitty on macOS?
Apple does not want you to use command line options with GUI applications. To
workaround that limitation, kitty will read command line options from the file
`~/Library/Preferences/kitty/macos-launch-services-cmdline` when it is launched
from the GUI, i.e. by clicking the kitty application icon or using `open -a kitty`.
Note that this file is *only read* when running via the GUI.
You can, of course, also run kitty from a terminal with command line options, using:
`/Applications/kitty.app/Contents/MacOS/kitty`.
And within kitty itself, you can always run kitty using just `kitty` as it
cleverly adds itself to the PATH.
== Resources on terminal behavior
@@ -342,4 +542,4 @@ http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
https://en.wikipedia.org/wiki/C0_and_C1_control_codes
http://vt100.net/
https://vt100.net/

View File

@@ -2,6 +2,67 @@
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2015, Kovid Goyal <kovid at kovidgoyal.net>
import sys
from kitty.main import main
main()
def icat(args):
from kitty.icat import main
main(args)
def list_fonts(args):
from kitty.fonts.list import main
main(args)
def remote_control(args):
from kitty.remote_control import main
main(args)
def runpy(args):
sys.argv = ['kitty'] + args[2:]
exec(args[1])
def launch(args):
import runpy
sys.argv = args[1:]
runpy.run_path(args[1], run_name='__main__')
def namespaced(args):
func = namespaced_entry_points[args[1]]
func(args[1:])
entry_points = {
# These two are here for backwards compat
'icat': icat,
'list-fonts': list_fonts,
'runpy': runpy,
'launch': launch,
'@': remote_control,
'+': namespaced,
}
namespaced_entry_points = {k: v for k, v in entry_points.items() if k[0] not in '+@'}
def main():
first_arg = '' if len(sys.argv) < 2 else sys.argv[1]
func = entry_points.get(first_arg)
if func is None:
if first_arg.startswith('@'):
remote_control(['@', first_arg[1:]] + sys.argv[2:])
elif first_arg.startswith('+'):
namespaced(['+', first_arg[1:]] + sys.argv[2:])
else:
from kitty.main import main
main()
else:
func(sys.argv[1:])
if __name__ == '__main__':
main()

19
asan-launcher.c Normal file
View File

@@ -0,0 +1,19 @@
/*
* linux-launcher.c
* Copyright (C) 2017 Kovid Goyal <kovid at kovidgoyal.net>
*
* Distributed under terms of the GPL3 license.
*/
#include <Python.h>
#define MAX_ARGC 1024
int main(int argc, char *argv[]) {
wchar_t *argvw[MAX_ARGC + 1] = {0};
argvw[0] = L"kitty";
for (int i = 1; i < argc; i++) argvw[i] = Py_DecodeLocale(argv[i], NULL);
int ret = Py_Main(argc, argvw);
for (int i = 1; i < argc; i++) PyMem_RawFree(argvw[i]);
return ret;
}

View File

@@ -15,7 +15,7 @@ with open('terminfo/kitty.terminfo', 'w') as f:
f.write(generate_terminfo())
os.environ['TERMINFO'] = os.path.join(base, 'terminfo')
subprocess.check_call(['tic', 'terminfo/kitty.terminfo'])
subprocess.check_call(['tic', '-x', 'terminfo/kitty.terminfo'])
# On OS X tic puts the compiled database into a different directory
try:
os.mkdir('terminfo/78')

View File

@@ -1,2 +1,2 @@
#!/bin/bash
cloc --exclude-list-file <(echo -e 'kitty/wcwidth9.h\nkitty/unicode-data.h\nkitty/gl.h\nkitty/glfw.c\nkitty/glfw.h\nkitty/charsets.c\nkitty/key_encoding.py\nkitty/rgb.py') kitty
cloc --exclude-list-file <(echo -e 'kitty/wcwidth-std.h\nkitty/glfw.c\nkitty/keys.h\nkitty/charsets.c\nkitty/unicode-data.c\nkitty/key_encoding.py\nkitty/rgb.py\nkitty/gl.h\nkitty/gl-wrapper.h\nkitty/gl-wrapper.c\nkitty/khrplatform.h\nkitty/glfw-wrapper.h\nkitty/glfw-wrapper.c\nkitty/emoji.h\nkittens/unicode_input/names.h') kitty kittens

354
gen-wcwidth.py Executable file
View File

@@ -0,0 +1,354 @@
#!/usr/bin/env python3
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
import os
import sys
from collections import defaultdict
from contextlib import contextmanager
from datetime import date
from functools import partial
from html.entities import html5
from itertools import groupby
from operator import itemgetter
from urllib.request import urlopen
os.chdir(os.path.dirname(os.path.abspath(__file__)))
def get_data(fname, folder='UCD'):
url = f'https://www.unicode.org/Public/{folder}/latest/{fname}'
bn = os.path.basename(url)
local = os.path.join('/tmp', bn)
if os.path.exists(local):
data = open(local, 'rb').read()
else:
data = urlopen(url).read()
open(local, 'wb').write(data)
for line in data.decode('utf-8').splitlines():
line = line.strip()
if line and not line.startswith('#'):
yield line
# Map of class names to set of codepoints in class
class_maps = {}
name_map = {}
word_search_map = defaultdict(set)
marks = set()
not_assigned = set(range(0, sys.maxunicode))
def parse_ucd():
def add_word(w, c):
if c <= 32 or c == 127 or 128 <= c <= 159:
return
word_search_map[w.lower()].add(c)
first = None
for word, c in html5.items():
if len(c) == 1:
add_word(word.rstrip(';'), ord(c))
word_search_map['nnbsp'].add(0x202f)
for line in get_data('ucd/UnicodeData.txt'):
parts = [x.strip() for x in line.split(';')]
codepoint = int(parts[0], 16)
name = parts[1]
if name:
name_map[codepoint] = name
for word in name.lower().split():
add_word(word, codepoint)
category = parts[2]
s = class_maps.setdefault(category, set())
desc = parts[1]
codepoints = (codepoint,)
if first is None:
if desc.endswith(', First>'):
first = codepoint
continue
else:
codepoints = range(first, codepoint + 1)
first = None
for codepoint in codepoints:
s.add(codepoint)
not_assigned.discard(codepoint)
if category.startswith('M'):
marks.add(codepoint)
def split_two(line):
spec, rest = line.split(';', 1)
spec, rest = spec.strip(), rest.strip().split(' ', 1)[0].strip()
if '..' in spec:
chars = tuple(map(lambda x: int(x, 16), filter(None, spec.split('.'))))
chars = set(range(chars[0], chars[1] + 1))
else:
chars = {int(spec, 16)}
return chars, rest
all_emoji = set()
emoji_categories = {}
emoji_presentation_bases = set()
def parse_emoji():
for line in get_data('emoji-data.txt', 'emoji'):
chars, rest = split_two(line)
s = emoji_categories.setdefault(rest, set())
s.update(chars)
all_emoji.update(chars)
for line in get_data('emoji-variation-sequences.txt', 'emoji'):
base, var, *rest = line.split()
if base.startswith('#'):
continue
base = int(base, 16)
if var.upper() == 'FE0F':
emoji_presentation_bases.add(base)
doublewidth, ambiguous = set(), set()
def parse_eaw():
global doublewidth, ambiguous
seen = set()
for line in get_data('ucd/EastAsianWidth.txt'):
chars, eaw = split_two(line)
if eaw == 'A':
ambiguous |= chars
seen |= chars
elif eaw == 'W' or eaw == 'F':
doublewidth |= chars
seen |= chars
doublewidth |= set(range(0x3400, 0x4DBF + 1)) - seen
doublewidth |= set(range(0x4E00, 0x9FFF + 1)) - seen
doublewidth |= set(range(0xF900, 0xFAFF + 1)) - seen
doublewidth |= set(range(0x20000, 0x2FFFD + 1)) - seen
doublewidth |= set(range(0x30000, 0x3FFFD + 1)) - seen
def get_ranges(items):
items.sort()
for k, g in groupby(enumerate(items), lambda m: m[0]-m[1]):
group = tuple(map(itemgetter(1), g))
a, b = group[0], group[-1]
if a == b:
yield a
else:
yield a, b
def write_case(spec, p):
if isinstance(spec, tuple):
p('\t\tcase 0x{:x} ... 0x{:x}:'.format(*spec))
else:
p('\t\tcase 0x{:x}:'.format(spec))
@contextmanager
def create_header(path, include_data_types=True):
f = open(path, 'w')
p = partial(print, file=f)
p('// unicode data, built from the unicode standard on:', date.today())
p('// see gen-wcwidth.py')
if path.endswith('.h'):
p('#pragma once')
if include_data_types:
p('#include "data-types.h"\n')
p('START_ALLOW_CASE_RANGE')
p()
yield p
p()
if include_data_types:
p('END_ALLOW_CASE_RANGE')
f.close()
def gen_emoji():
with create_header('kitty/emoji.h') as p:
p('static inline bool\nis_emoji(char_type code) {')
p('\tswitch(code) {')
for spec in get_ranges(list(all_emoji)):
write_case(spec, p)
p('\t\t\treturn true;')
p('\t\tdefault: return false;')
p('\t}')
p('\treturn false;\n}')
p('static inline bool\nis_emoji_modifier(char_type code) {')
p('\tswitch(code) {')
for spec in get_ranges(list(emoji_categories['Emoji_Modifier'])):
write_case(spec, p)
p('\t\t\treturn true;')
p('\t\tdefault: return false;')
p('\t}')
p('\treturn false;\n}')
def category_test(name, p, classes, comment, static=False):
static = 'static inline ' if static else ''
chars = set()
for c in classes:
chars |= class_maps[c]
p(f'{static}bool\n{name}(char_type code) {{')
p(f'\t// {comment} ({len(chars)} codepoints)' + ' {{' '{')
p('\tswitch(code) {')
for spec in get_ranges(list(chars)):
write_case(spec, p)
p(f'\t\t\treturn true;')
p('\t} // }}}\n')
p('\treturn false;\n}\n')
def codepoint_to_mark_map(p, mark_map):
p('\tswitch(c) { // {{{')
rmap = {c: m for m, c in enumerate(mark_map)}
for spec in get_ranges(mark_map):
if isinstance(spec, tuple):
s = rmap[spec[0]]
p(f'\t\tcase {spec[0]} ... {spec[1]}: return {s} + c - {spec[0]};')
else:
p(f'\t\tcase {spec}: return {rmap[spec]};')
p('default: return 0;')
p('\t} // }}}')
return rmap
def classes_to_regex(classes):
chars = set()
for c in classes:
chars |= class_maps[c]
def as_string(codepoint):
if codepoint < 256:
return r'\x{:02x}'.format(codepoint)
if codepoint <= 0xffff:
return r'\u{:04x}'.format(codepoint)
return r'\U{:08x}'.format(codepoint)
for spec in get_ranges(list(chars)):
if isinstance(spec, tuple):
yield '{}-{}'.format(*map(as_string, (spec[0], spec[1])))
else:
yield as_string(spec)
def gen_ucd():
cz = {c for c in class_maps if c[0] in 'CZ'}
with create_header('kitty/unicode-data.c') as p:
p('#include "unicode-data.h"')
category_test('is_combining_char', p, {c for c in class_maps if c.startswith('M')}, 'M category (marks)')
category_test('is_ignored_char', p, 'Cc Cf Cs'.split(), 'Control characters (Cc Cf Cs)')
category_test('is_word_char', p, {c for c in class_maps if c[0] in 'LN'}, 'L and N categories')
category_test('is_CZ_category', p, cz, 'C and Z categories')
category_test('is_P_category', p, {c for c in class_maps if c[0] == 'P'}, 'P category (punctuation)')
mark_map = [0] + list(sorted(marks))
p('char_type codepoint_for_mark(combining_type m) {')
p(f'\tstatic char_type map[{len(mark_map)}] =', '{', ', '.join(map(str, mark_map)), '}; // {{{ mapping }}}')
p('\tif (m < arraysz(map)) return map[m];')
p('\treturn 0;')
p('}\n')
p('combining_type mark_for_codepoint(char_type c) {')
rmap = codepoint_to_mark_map(p, mark_map)
p('}\n')
if rmap[0xfe0e] != 1275:
raise ValueError('The mark for 0xfe0e has changed, you have to update VS15 to {} and VS16 to {} in unicode-data.h'.format(
rmap[0xfe0e], rmap[0xfe0f]
))
with open('kittens/url_hints/url_regex.py', 'w') as f:
f.write("url_delimiters = '{}' # noqa".format(''.join(classes_to_regex(cz))))
def gen_names():
words = tuple(sorted(word_search_map))
with create_header('kittens/unicode_input/names.h') as p:
cp_map = list(sorted(name_map))
p(f'static const char* name_map[{len(cp_map)}] = {{' ' // {{{')
for cp in cp_map:
w = name_map[cp].replace('"', '\\"')
p(f'\t"{w}",')
p("}; // }}}\n")
p(f'static const char* idx_to_word[{len(words)}] = ' '{ // {{{')
for s in words:
s = s.replace('"', '\\"')
p(f'\t"{s}",')
p("}; // }}}\n")
first_letters = {ord(w[0]) for w in words if ord(w[0]) < 256}
wmap = {w: i for i, w in enumerate(words)}
p(f'static const unsigned short* words_for_first_letter[256] = ' '{ // {{{')
for fl in range(0, 256):
if fl in first_letters:
winds = [str(wmap[w]) for w in words if w.startswith(chr(fl))]
p(f'\t(const unsigned short[{len(winds) + 1}]){{{len(winds)}, ', ', '.join(winds), '},')
else:
p('NULL,')
p("}; // }}}\n")
p(f'static const char_type* codepoints_for_word_idx[{len(words)}] = ' '{ // {{{')
for s in words:
cps = word_search_map[s]
a = ', '.join(map(str, cps))
p(f'\t(const char_type[{len(cps) + 1}]){{{len(cps)}, ', a, '},')
p("}; // }}}\n")
p('static char_type mark_for_codepoint(char_type c) {')
codepoint_to_mark_map(p, cp_map)
p('}\n')
p('static inline const char* name_for_codepoint(char_type cp) {')
p('\tchar_type m = mark_for_codepoint(cp); if (m == 0) return NULL;')
p('\treturn name_map[m];')
p('}\n')
def gen_wcwidth():
seen = set()
def add(p, comment, chars_, ret):
chars = chars_ - seen
seen.update(chars)
p(f'\t\t// {comment} ({len(chars)} codepoints)' + ' {{' '{')
for spec in get_ranges(list(chars)):
write_case(spec, p)
p(f'\t\t\treturn {ret};')
p('\t\t// }}}\n')
with create_header('kitty/wcwidth-std.h') as p:
p('static int\nwcwidth_std(int32_t code) {')
p('\tswitch(code) {')
non_printing = class_maps['Cc'] | class_maps['Cf'] | class_maps['Cs']
add(p, 'Marks', marks | {0}, 0)
add(p, 'Non-printing characters', non_printing, -1)
add(p, 'Private use', class_maps['Co'], -3)
add(p, 'Text Presentation', emoji_categories['Emoji'] - emoji_categories['Emoji_Presentation'], 1)
add(p, 'East Asian ambiguous width', ambiguous, -2)
add(p, 'East Asian double width', doublewidth, 2)
add(p, 'Emoji Presentation', emoji_categories['Emoji_Presentation'], 2)
add(p, 'Not assigned in the unicode character database', not_assigned, -1)
p('\t\tdefault: return 1;')
p('\t}')
p('\treturn 1;\n}')
p('static bool\nis_emoji_presentation_base(uint32_t code) {')
p('\tswitch(code) {')
for spec in get_ranges(list(emoji_presentation_bases)):
write_case(spec, p)
p('\t\t\treturn true;')
p('\t\tdefault: return false;')
p('\t}')
p('\treturn 1;\n}')
parse_ucd()
parse_emoji()
parse_eaw()
gen_ucd()
gen_wcwidth()
gen_emoji()
gen_names()

View File

@@ -1,57 +0,0 @@
#!/usr/bin/env python3
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
import unicodedata
import itertools
import sys
IGNORED_CATEGORIES = ('Cc', 'Cf', 'Cs')
def ranges(i):
for a, b in itertools.groupby(enumerate(i), lambda r: r[1] - r[0]):
b = list(b)
yield b[0][1], b[-1][1]
def generate_data(chars):
points, cranges = [], []
for l, r in ranges(chars):
if l == r:
points.append(l)
else:
cranges.append((l, r))
return points, cranges
def generate_predicate(name, chars):
points, cranges = generate_data(chars)
cranges = ['(0x%x %s ch && ch <= 0x%x)' % (l, '<' if l == 0 else '<=', r) for l, r in cranges]
points = ['(ch == 0x%x)' % p for p in points]
return '''
static inline bool %s(uint32_t ch) {
return %s || %s;
}
''' % (name, '||'.join(cranges), '||'.join(points))
def main():
combining_chars = []
igchars = []
for c in map(chr, range(sys.maxunicode + 1)):
if unicodedata.category(c) in IGNORED_CATEGORIES:
igchars.append(ord(c))
if unicodedata.combining(c):
combining_chars.append(ord(c))
cc = generate_predicate('is_combining_char', combining_chars)
ig = generate_predicate('is_ignored_char', igchars)
with open('kitty/unicode-data.h', 'w') as f:
print('#pragma once', file=f)
print(cc, file=f)
print(ig, file=f)
if __name__ == '__main__':
main()

62
glad/generate.py Executable file
View File

@@ -0,0 +1,62 @@
#!/usr/bin/env python3
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
import os
import re
import shlex
import shutil
import subprocess
cmdline = (
'glad --profile core --out-path {dest} --api gl=3.3 --generator {generator} --spec gl'
' --extensions GL_ARB_texture_storage,GL_ARB_copy_image,GL_ARB_multisample,GL_ARB_robustness,GL_KHR_debug'
)
def clean(x):
if os.path.exists(x):
shutil.rmtree(x)
def regenerate():
clean('out')
subprocess.check_call(
shlex.split(cmdline.format(dest='out', generator='c-debug'))
)
def export():
c = open('out/src/glad.c', 'rb').read().decode('utf-8')
functions = []
def sub(m):
functions.append(m.group(2))
return m.group()
c = re.sub(r'^([A-Z0-9]+) glad_debug_([a-zA-Z0-9]+) = glad_debug_impl_\2;$', sub, c, flags=re.M)
switch = ['glad_debug_{0} = glad_{0}'.format(f) for f in functions]
c = c.replace('<glad/glad.h>', '"gl-wrapper.h"', 1)
c = '#pragma GCC diagnostic ignored "-Wpedantic"\n' + c
c += '''
int
init_glad(GLADloadproc load, int debug) {
int ret = gladLoadGLLoader(load);
if (ret && !debug) {
SUB;
}
return ret;
}'''.replace('SUB', ';\n '.join(switch), 1)
open('../kitty/gl-wrapper.c', 'w').write(c)
raw = open('out/include/glad/glad.h').read()
raw = raw.replace('<KHR/khrplatform.h>', '"khrplatform.h"')
raw += '\nint init_glad(GLADloadproc, int);\n'
open('../kitty/gl-wrapper.h', 'w').write(raw)
shutil.copy2('out/include/KHR/khrplatform.h', '../kitty')
if __name__ == '__main__':
os.chdir(os.path.dirname(os.path.abspath(__file__)))
regenerate()
export()

374
glfw/cocoa_init.m Normal file
View File

@@ -0,0 +1,374 @@
//========================================================================
// GLFW 3.3 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <sys/param.h> // For MAXPATHLEN
// Change to our application bundle's resources directory, if present
//
static void changeToResourcesDirectory(void)
{
char resourcesPath[MAXPATHLEN];
CFBundleRef bundle = CFBundleGetMainBundle();
if (!bundle)
return;
CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle);
CFStringRef last = CFURLCopyLastPathComponent(resourcesURL);
if (CFStringCompare(CFSTR("Resources"), last, 0) != kCFCompareEqualTo)
{
CFRelease(last);
CFRelease(resourcesURL);
return;
}
CFRelease(last);
if (!CFURLGetFileSystemRepresentation(resourcesURL,
true,
(UInt8*) resourcesPath,
MAXPATHLEN))
{
CFRelease(resourcesURL);
return;
}
CFRelease(resourcesURL);
chdir(resourcesPath);
}
// Create key code translation tables
//
static void createKeyTables(void)
{
int scancode;
memset(_glfw.ns.keycodes, -1, sizeof(_glfw.ns.keycodes));
memset(_glfw.ns.scancodes, -1, sizeof(_glfw.ns.scancodes));
_glfw.ns.keycodes[0x1D] = GLFW_KEY_0;
_glfw.ns.keycodes[0x12] = GLFW_KEY_1;
_glfw.ns.keycodes[0x13] = GLFW_KEY_2;
_glfw.ns.keycodes[0x14] = GLFW_KEY_3;
_glfw.ns.keycodes[0x15] = GLFW_KEY_4;
_glfw.ns.keycodes[0x17] = GLFW_KEY_5;
_glfw.ns.keycodes[0x16] = GLFW_KEY_6;
_glfw.ns.keycodes[0x1A] = GLFW_KEY_7;
_glfw.ns.keycodes[0x1C] = GLFW_KEY_8;
_glfw.ns.keycodes[0x19] = GLFW_KEY_9;
_glfw.ns.keycodes[0x00] = GLFW_KEY_A;
_glfw.ns.keycodes[0x0B] = GLFW_KEY_B;
_glfw.ns.keycodes[0x08] = GLFW_KEY_C;
_glfw.ns.keycodes[0x02] = GLFW_KEY_D;
_glfw.ns.keycodes[0x0E] = GLFW_KEY_E;
_glfw.ns.keycodes[0x03] = GLFW_KEY_F;
_glfw.ns.keycodes[0x05] = GLFW_KEY_G;
_glfw.ns.keycodes[0x04] = GLFW_KEY_H;
_glfw.ns.keycodes[0x22] = GLFW_KEY_I;
_glfw.ns.keycodes[0x26] = GLFW_KEY_J;
_glfw.ns.keycodes[0x28] = GLFW_KEY_K;
_glfw.ns.keycodes[0x25] = GLFW_KEY_L;
_glfw.ns.keycodes[0x2E] = GLFW_KEY_M;
_glfw.ns.keycodes[0x2D] = GLFW_KEY_N;
_glfw.ns.keycodes[0x1F] = GLFW_KEY_O;
_glfw.ns.keycodes[0x23] = GLFW_KEY_P;
_glfw.ns.keycodes[0x0C] = GLFW_KEY_Q;
_glfw.ns.keycodes[0x0F] = GLFW_KEY_R;
_glfw.ns.keycodes[0x01] = GLFW_KEY_S;
_glfw.ns.keycodes[0x11] = GLFW_KEY_T;
_glfw.ns.keycodes[0x20] = GLFW_KEY_U;
_glfw.ns.keycodes[0x09] = GLFW_KEY_V;
_glfw.ns.keycodes[0x0D] = GLFW_KEY_W;
_glfw.ns.keycodes[0x07] = GLFW_KEY_X;
_glfw.ns.keycodes[0x10] = GLFW_KEY_Y;
_glfw.ns.keycodes[0x06] = GLFW_KEY_Z;
_glfw.ns.keycodes[0x27] = GLFW_KEY_APOSTROPHE;
_glfw.ns.keycodes[0x2A] = GLFW_KEY_BACKSLASH;
_glfw.ns.keycodes[0x2B] = GLFW_KEY_COMMA;
_glfw.ns.keycodes[0x18] = GLFW_KEY_EQUAL;
_glfw.ns.keycodes[0x32] = GLFW_KEY_GRAVE_ACCENT;
_glfw.ns.keycodes[0x21] = GLFW_KEY_LEFT_BRACKET;
_glfw.ns.keycodes[0x1B] = GLFW_KEY_MINUS;
_glfw.ns.keycodes[0x2F] = GLFW_KEY_PERIOD;
_glfw.ns.keycodes[0x1E] = GLFW_KEY_RIGHT_BRACKET;
_glfw.ns.keycodes[0x29] = GLFW_KEY_SEMICOLON;
_glfw.ns.keycodes[0x2C] = GLFW_KEY_SLASH;
_glfw.ns.keycodes[0x0A] = GLFW_KEY_WORLD_1;
_glfw.ns.keycodes[0x33] = GLFW_KEY_BACKSPACE;
_glfw.ns.keycodes[0x39] = GLFW_KEY_CAPS_LOCK;
_glfw.ns.keycodes[0x75] = GLFW_KEY_DELETE;
_glfw.ns.keycodes[0x7D] = GLFW_KEY_DOWN;
_glfw.ns.keycodes[0x77] = GLFW_KEY_END;
_glfw.ns.keycodes[0x24] = GLFW_KEY_ENTER;
_glfw.ns.keycodes[0x35] = GLFW_KEY_ESCAPE;
_glfw.ns.keycodes[0x7A] = GLFW_KEY_F1;
_glfw.ns.keycodes[0x78] = GLFW_KEY_F2;
_glfw.ns.keycodes[0x63] = GLFW_KEY_F3;
_glfw.ns.keycodes[0x76] = GLFW_KEY_F4;
_glfw.ns.keycodes[0x60] = GLFW_KEY_F5;
_glfw.ns.keycodes[0x61] = GLFW_KEY_F6;
_glfw.ns.keycodes[0x62] = GLFW_KEY_F7;
_glfw.ns.keycodes[0x64] = GLFW_KEY_F8;
_glfw.ns.keycodes[0x65] = GLFW_KEY_F9;
_glfw.ns.keycodes[0x6D] = GLFW_KEY_F10;
_glfw.ns.keycodes[0x67] = GLFW_KEY_F11;
_glfw.ns.keycodes[0x6F] = GLFW_KEY_F12;
_glfw.ns.keycodes[0x69] = GLFW_KEY_F13;
_glfw.ns.keycodes[0x6B] = GLFW_KEY_F14;
_glfw.ns.keycodes[0x71] = GLFW_KEY_F15;
_glfw.ns.keycodes[0x6A] = GLFW_KEY_F16;
_glfw.ns.keycodes[0x40] = GLFW_KEY_F17;
_glfw.ns.keycodes[0x4F] = GLFW_KEY_F18;
_glfw.ns.keycodes[0x50] = GLFW_KEY_F19;
_glfw.ns.keycodes[0x5A] = GLFW_KEY_F20;
_glfw.ns.keycodes[0x73] = GLFW_KEY_HOME;
_glfw.ns.keycodes[0x72] = GLFW_KEY_INSERT;
_glfw.ns.keycodes[0x7B] = GLFW_KEY_LEFT;
_glfw.ns.keycodes[0x3A] = GLFW_KEY_LEFT_ALT;
_glfw.ns.keycodes[0x3B] = GLFW_KEY_LEFT_CONTROL;
_glfw.ns.keycodes[0x38] = GLFW_KEY_LEFT_SHIFT;
_glfw.ns.keycodes[0x37] = GLFW_KEY_LEFT_SUPER;
_glfw.ns.keycodes[0x6E] = GLFW_KEY_MENU;
_glfw.ns.keycodes[0x47] = GLFW_KEY_NUM_LOCK;
_glfw.ns.keycodes[0x79] = GLFW_KEY_PAGE_DOWN;
_glfw.ns.keycodes[0x74] = GLFW_KEY_PAGE_UP;
_glfw.ns.keycodes[0x7C] = GLFW_KEY_RIGHT;
_glfw.ns.keycodes[0x3D] = GLFW_KEY_RIGHT_ALT;
_glfw.ns.keycodes[0x3E] = GLFW_KEY_RIGHT_CONTROL;
_glfw.ns.keycodes[0x3C] = GLFW_KEY_RIGHT_SHIFT;
_glfw.ns.keycodes[0x36] = GLFW_KEY_RIGHT_SUPER;
_glfw.ns.keycodes[0x31] = GLFW_KEY_SPACE;
_glfw.ns.keycodes[0x30] = GLFW_KEY_TAB;
_glfw.ns.keycodes[0x7E] = GLFW_KEY_UP;
_glfw.ns.keycodes[0x52] = GLFW_KEY_KP_0;
_glfw.ns.keycodes[0x53] = GLFW_KEY_KP_1;
_glfw.ns.keycodes[0x54] = GLFW_KEY_KP_2;
_glfw.ns.keycodes[0x55] = GLFW_KEY_KP_3;
_glfw.ns.keycodes[0x56] = GLFW_KEY_KP_4;
_glfw.ns.keycodes[0x57] = GLFW_KEY_KP_5;
_glfw.ns.keycodes[0x58] = GLFW_KEY_KP_6;
_glfw.ns.keycodes[0x59] = GLFW_KEY_KP_7;
_glfw.ns.keycodes[0x5B] = GLFW_KEY_KP_8;
_glfw.ns.keycodes[0x5C] = GLFW_KEY_KP_9;
_glfw.ns.keycodes[0x45] = GLFW_KEY_KP_ADD;
_glfw.ns.keycodes[0x41] = GLFW_KEY_KP_DECIMAL;
_glfw.ns.keycodes[0x4B] = GLFW_KEY_KP_DIVIDE;
_glfw.ns.keycodes[0x4C] = GLFW_KEY_KP_ENTER;
_glfw.ns.keycodes[0x51] = GLFW_KEY_KP_EQUAL;
_glfw.ns.keycodes[0x43] = GLFW_KEY_KP_MULTIPLY;
_glfw.ns.keycodes[0x4E] = GLFW_KEY_KP_SUBTRACT;
for (scancode = 0; scancode < 256; scancode++)
{
// Store the reverse translation for faster key name lookup
if (_glfw.ns.keycodes[scancode] >= 0)
_glfw.ns.scancodes[_glfw.ns.keycodes[scancode]] = scancode;
}
}
// Retrieve Unicode data for the current keyboard layout
//
static GLFWbool updateUnicodeDataNS(void)
{
if (_glfw.ns.inputSource)
{
CFRelease(_glfw.ns.inputSource);
_glfw.ns.inputSource = NULL;
_glfw.ns.unicodeData = nil;
}
_glfw.ns.inputSource = TISCopyCurrentKeyboardLayoutInputSource();
if (!_glfw.ns.inputSource)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Cocoa: Failed to retrieve keyboard layout input source");
return GLFW_FALSE;
}
_glfw.ns.unicodeData =
TISGetInputSourceProperty(_glfw.ns.inputSource,
kTISPropertyUnicodeKeyLayoutData);
if (!_glfw.ns.unicodeData)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Cocoa: Failed to retrieve keyboard layout Unicode data");
return GLFW_FALSE;
}
return GLFW_TRUE;
}
// Load HIToolbox.framework and the TIS symbols we need from it
//
static GLFWbool initializeTIS(void)
{
// This works only because Cocoa has already loaded it properly
_glfw.ns.tis.bundle =
CFBundleGetBundleWithIdentifier(CFSTR("com.apple.HIToolbox"));
if (!_glfw.ns.tis.bundle)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Cocoa: Failed to load HIToolbox.framework");
return GLFW_FALSE;
}
CFStringRef* kPropertyUnicodeKeyLayoutData =
CFBundleGetDataPointerForName(_glfw.ns.tis.bundle,
CFSTR("kTISPropertyUnicodeKeyLayoutData"));
_glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource =
CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
CFSTR("TISCopyCurrentKeyboardLayoutInputSource"));
_glfw.ns.tis.GetInputSourceProperty =
CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
CFSTR("TISGetInputSourceProperty"));
_glfw.ns.tis.GetKbdType =
CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
CFSTR("LMGetKbdType"));
if (!kPropertyUnicodeKeyLayoutData ||
!TISCopyCurrentKeyboardLayoutInputSource ||
!TISGetInputSourceProperty ||
!LMGetKbdType)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Cocoa: Failed to load TIS API symbols");
return GLFW_FALSE;
}
_glfw.ns.tis.kPropertyUnicodeKeyLayoutData =
*kPropertyUnicodeKeyLayoutData;
return updateUnicodeDataNS();
}
@interface GLFWLayoutListener : NSObject
@end
@implementation GLFWLayoutListener
- (void)selectedKeyboardInputSourceChanged:(NSObject* )object
{
updateUnicodeDataNS();
}
@end
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
int _glfwPlatformInit(void)
{
_glfw.ns.autoreleasePool = [[NSAutoreleasePool alloc] init];
if (_glfw.hints.init.ns.chdir)
changeToResourcesDirectory();
_glfw.ns.listener = [[GLFWLayoutListener alloc] init];
[[NSNotificationCenter defaultCenter]
addObserver:_glfw.ns.listener
selector:@selector(selectedKeyboardInputSourceChanged:)
name:NSTextInputContextKeyboardSelectionDidChangeNotification
object:nil];
createKeyTables();
_glfw.ns.eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
if (!_glfw.ns.eventSource)
return GLFW_FALSE;
CGEventSourceSetLocalEventsSuppressionInterval(_glfw.ns.eventSource, 0.0);
if (!initializeTIS())
return GLFW_FALSE;
_glfwInitTimerNS();
_glfwInitJoysticksNS();
_glfwPollMonitorsNS();
return GLFW_TRUE;
}
void _glfwPlatformTerminate(void)
{
if (_glfw.ns.inputSource)
{
CFRelease(_glfw.ns.inputSource);
_glfw.ns.inputSource = NULL;
_glfw.ns.unicodeData = nil;
}
if (_glfw.ns.eventSource)
{
CFRelease(_glfw.ns.eventSource);
_glfw.ns.eventSource = NULL;
}
if (_glfw.ns.delegate)
{
[NSApp setDelegate:nil];
[_glfw.ns.delegate release];
_glfw.ns.delegate = nil;
}
if (_glfw.ns.listener)
{
[[NSNotificationCenter defaultCenter]
removeObserver:_glfw.ns.listener
name:NSTextInputContextKeyboardSelectionDidChangeNotification
object:nil];
[[NSNotificationCenter defaultCenter]
removeObserver:_glfw.ns.listener];
[_glfw.ns.listener release];
_glfw.ns.listener = nil;
}
free(_glfw.ns.clipboardString);
_glfwTerminateNSGL();
_glfwTerminateJoysticksNS();
[_glfw.ns.autoreleasePool release];
_glfw.ns.autoreleasePool = nil;
}
const char* _glfwPlatformGetVersionString(void)
{
return _GLFW_VERSION_NUMBER " Cocoa NSGL"
#if defined(_GLFW_BUILD_DLL)
" dynamic"
#endif
;
}

50
glfw/cocoa_joystick.h vendored Normal file
View File

@@ -0,0 +1,50 @@
//========================================================================
// GLFW 3.3 Cocoa - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include <IOKit/IOKitLib.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/hid/IOHIDLib.h>
#include <IOKit/hid/IOHIDKeys.h>
#define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickNS ns
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE
#define _GLFW_PLATFORM_MAPPING_NAME "Mac OS X"
// Cocoa-specific per-joystick data
//
typedef struct _GLFWjoystickNS
{
IOHIDDeviceRef device;
CFMutableArrayRef axes;
CFMutableArrayRef buttons;
CFMutableArrayRef hats;
} _GLFWjoystickNS;
void _glfwInitJoysticksNS(void);
void _glfwTerminateJoysticksNS(void);

462
glfw/cocoa_joystick.m Normal file
View File

@@ -0,0 +1,462 @@
//========================================================================
// GLFW 3.3 Cocoa - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2016 Camilla Löwy <elmindreda@glfw.org>
// Copyright (c) 2012 Torsten Walluhn <tw@mad-cad.net>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include <mach/mach.h>
#include <mach/mach_error.h>
#include <CoreFoundation/CoreFoundation.h>
#include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h>
// Joystick element information
//
typedef struct _GLFWjoyelementNS
{
IOHIDElementRef native;
uint32_t usage;
int index;
long minimum;
long maximum;
} _GLFWjoyelementNS;
// Returns the value of the specified element of the specified joystick
//
static long getElementValue(_GLFWjoystick* js, _GLFWjoyelementNS* element)
{
IOHIDValueRef valueRef;
long value = 0;
if (js->ns.device)
{
if (IOHIDDeviceGetValue(js->ns.device,
element->native,
&valueRef) == kIOReturnSuccess)
{
value = IOHIDValueGetIntegerValue(valueRef);
}
}
return value;
}
// Comparison function for matching the SDL element order
//
static CFComparisonResult compareElements(const void* fp,
const void* sp,
void* user)
{
const _GLFWjoyelementNS* fe = fp;
const _GLFWjoyelementNS* se = sp;
if (fe->usage < se->usage)
return kCFCompareLessThan;
if (fe->usage > se->usage)
return kCFCompareGreaterThan;
if (fe->index < se->index)
return kCFCompareLessThan;
if (fe->index > se->index)
return kCFCompareGreaterThan;
return kCFCompareEqualTo;
}
// Removes the specified joystick
//
static void closeJoystick(_GLFWjoystick* js)
{
int i;
if (!js->present)
return;
for (i = 0; i < CFArrayGetCount(js->ns.axes); i++)
free((void*) CFArrayGetValueAtIndex(js->ns.axes, i));
CFRelease(js->ns.axes);
for (i = 0; i < CFArrayGetCount(js->ns.buttons); i++)
free((void*) CFArrayGetValueAtIndex(js->ns.buttons, i));
CFRelease(js->ns.buttons);
for (i = 0; i < CFArrayGetCount(js->ns.hats); i++)
free((void*) CFArrayGetValueAtIndex(js->ns.hats, i));
CFRelease(js->ns.hats);
_glfwFreeJoystick(js);
_glfwInputJoystick(js, GLFW_DISCONNECTED);
}
// Callback for user-initiated joystick addition
//
static void matchCallback(void* context,
IOReturn result,
void* sender,
IOHIDDeviceRef device)
{
int jid;
char name[256];
char guid[33];
CFIndex i;
CFTypeRef property;
uint32_t vendor = 0, product = 0, version = 0;
_GLFWjoystick* js;
CFMutableArrayRef axes, buttons, hats;
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
{
if (_glfw.joysticks[jid].ns.device == device)
return;
}
axes = CFArrayCreateMutable(NULL, 0, NULL);
buttons = CFArrayCreateMutable(NULL, 0, NULL);
hats = CFArrayCreateMutable(NULL, 0, NULL);
property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
if (property)
{
CFStringGetCString(property,
name,
sizeof(name),
kCFStringEncodingUTF8);
}
else
strncpy(name, "Unknown", sizeof(name));
property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey));
if (property)
CFNumberGetValue(property, kCFNumberSInt32Type, &vendor);
property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductIDKey));
if (property)
CFNumberGetValue(property, kCFNumberSInt32Type, &product);
property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVersionNumberKey));
if (property)
CFNumberGetValue(property, kCFNumberSInt32Type, &version);
// Generate a joystick GUID that matches the SDL 2.0.5+ one
if (vendor && product)
{
sprintf(guid, "03000000%02x%02x0000%02x%02x0000%02x%02x0000",
(uint8_t) vendor, (uint8_t) (vendor >> 8),
(uint8_t) product, (uint8_t) (product >> 8),
(uint8_t) version, (uint8_t) (version >> 8));
}
else
{
sprintf(guid, "05000000%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x00",
name[0], name[1], name[2], name[3],
name[4], name[5], name[6], name[7],
name[8], name[9], name[10]);
}
CFArrayRef elements =
IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone);
for (i = 0; i < CFArrayGetCount(elements); i++)
{
IOHIDElementRef native = (IOHIDElementRef)
CFArrayGetValueAtIndex(elements, i);
if (CFGetTypeID(native) != IOHIDElementGetTypeID())
continue;
const IOHIDElementType type = IOHIDElementGetType(native);
if ((type != kIOHIDElementTypeInput_Axis) &&
(type != kIOHIDElementTypeInput_Button) &&
(type != kIOHIDElementTypeInput_Misc))
{
continue;
}
CFMutableArrayRef target = NULL;
const uint32_t usage = IOHIDElementGetUsage(native);
const uint32_t page = IOHIDElementGetUsagePage(native);
if (page == kHIDPage_GenericDesktop)
{
switch (usage)
{
case kHIDUsage_GD_X:
case kHIDUsage_GD_Y:
case kHIDUsage_GD_Z:
case kHIDUsage_GD_Rx:
case kHIDUsage_GD_Ry:
case kHIDUsage_GD_Rz:
case kHIDUsage_GD_Slider:
case kHIDUsage_GD_Dial:
case kHIDUsage_GD_Wheel:
target = axes;
break;
case kHIDUsage_GD_Hatswitch:
target = hats;
break;
}
}
else if (page == kHIDPage_Button)
target = buttons;
if (target)
{
_GLFWjoyelementNS* element = calloc(1, sizeof(_GLFWjoyelementNS));
element->native = native;
element->usage = usage;
element->index = (int) CFArrayGetCount(target);
element->minimum = IOHIDElementGetLogicalMin(native);
element->maximum = IOHIDElementGetLogicalMax(native);
CFArrayAppendValue(target, element);
}
}
CFRelease(elements);
CFArraySortValues(axes, CFRangeMake(0, CFArrayGetCount(axes)),
compareElements, NULL);
CFArraySortValues(buttons, CFRangeMake(0, CFArrayGetCount(buttons)),
compareElements, NULL);
CFArraySortValues(hats, CFRangeMake(0, CFArrayGetCount(hats)),
compareElements, NULL);
js = _glfwAllocJoystick(name, guid,
(int) CFArrayGetCount(axes),
(int) CFArrayGetCount(buttons),
(int) CFArrayGetCount(hats));
js->ns.device = device;
js->ns.axes = axes;
js->ns.buttons = buttons;
js->ns.hats = hats;
_glfwInputJoystick(js, GLFW_CONNECTED);
}
// Callback for user-initiated joystick removal
//
static void removeCallback(void* context,
IOReturn result,
void* sender,
IOHIDDeviceRef device)
{
int jid;
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
{
if (_glfw.joysticks[jid].ns.device == device)
{
closeJoystick(_glfw.joysticks + jid);
break;
}
}
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
// Initialize joystick interface
//
void _glfwInitJoysticksNS(void)
{
CFMutableArrayRef matching;
const long usages[] =
{
kHIDUsage_GD_Joystick,
kHIDUsage_GD_GamePad,
kHIDUsage_GD_MultiAxisController
};
_glfw.ns.hidManager = IOHIDManagerCreate(kCFAllocatorDefault,
kIOHIDOptionsTypeNone);
matching = CFArrayCreateMutable(kCFAllocatorDefault,
0,
&kCFTypeArrayCallBacks);
if (!matching)
{
_glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to create array");
return;
}
for (int i = 0; i < sizeof(usages) / sizeof(long); i++)
{
const long page = kHIDPage_GenericDesktop;
CFMutableDictionaryRef dict =
CFDictionaryCreateMutable(kCFAllocatorDefault,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (!dict)
continue;
CFNumberRef pageRef = CFNumberCreate(kCFAllocatorDefault,
kCFNumberLongType,
&page);
CFNumberRef usageRef = CFNumberCreate(kCFAllocatorDefault,
kCFNumberLongType,
&usages[i]);
if (pageRef && usageRef)
{
CFDictionarySetValue(dict,
CFSTR(kIOHIDDeviceUsagePageKey),
pageRef);
CFDictionarySetValue(dict,
CFSTR(kIOHIDDeviceUsageKey),
usageRef);
CFArrayAppendValue(matching, dict);
}
if (pageRef)
CFRelease(pageRef);
if (usageRef)
CFRelease(usageRef);
CFRelease(dict);
}
IOHIDManagerSetDeviceMatchingMultiple(_glfw.ns.hidManager, matching);
CFRelease(matching);
IOHIDManagerRegisterDeviceMatchingCallback(_glfw.ns.hidManager,
&matchCallback, NULL);
IOHIDManagerRegisterDeviceRemovalCallback(_glfw.ns.hidManager,
&removeCallback, NULL);
IOHIDManagerScheduleWithRunLoop(_glfw.ns.hidManager,
CFRunLoopGetMain(),
kCFRunLoopDefaultMode);
IOHIDManagerOpen(_glfw.ns.hidManager, kIOHIDOptionsTypeNone);
// Execute the run loop once in order to register any initially-attached
// joysticks
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false);
}
// Close all opened joystick handles
//
void _glfwTerminateJoysticksNS(void)
{
int jid;
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
closeJoystick(_glfw.joysticks + jid);
CFRelease(_glfw.ns.hidManager);
_glfw.ns.hidManager = NULL;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode)
{
if (mode & _GLFW_POLL_AXES)
{
CFIndex i;
for (i = 0; i < CFArrayGetCount(js->ns.axes); i++)
{
_GLFWjoyelementNS* axis = (_GLFWjoyelementNS*)
CFArrayGetValueAtIndex(js->ns.axes, i);
const long raw = getElementValue(js, axis);
// Perform auto calibration
if (raw < axis->minimum)
axis->minimum = raw;
if (raw > axis->maximum)
axis->maximum = raw;
const long delta = axis->maximum - axis->minimum;
if (delta == 0)
_glfwInputJoystickAxis(js, (int) i, 0.f);
else
{
const float value = (2.f * (raw - axis->minimum) / delta) - 1.f;
_glfwInputJoystickAxis(js, (int) i, value);
}
}
}
if (mode & _GLFW_POLL_BUTTONS)
{
CFIndex i;
for (i = 0; i < CFArrayGetCount(js->ns.buttons); i++)
{
_GLFWjoyelementNS* button = (_GLFWjoyelementNS*)
CFArrayGetValueAtIndex(js->ns.buttons, i);
const char value = getElementValue(js, button) - button->minimum;
_glfwInputJoystickButton(js, (int) i, value);
}
for (i = 0; i < CFArrayGetCount(js->ns.hats); i++)
{
const int states[9] =
{
GLFW_HAT_UP,
GLFW_HAT_RIGHT_UP,
GLFW_HAT_RIGHT,
GLFW_HAT_RIGHT_DOWN,
GLFW_HAT_DOWN,
GLFW_HAT_LEFT_DOWN,
GLFW_HAT_LEFT,
GLFW_HAT_LEFT_UP,
GLFW_HAT_CENTERED
};
_GLFWjoyelementNS* hat = (_GLFWjoyelementNS*)
CFArrayGetValueAtIndex(js->ns.hats, i);
long state = getElementValue(js, hat) - hat->minimum;
if (state < 0 || state > 8)
state = 8;
_glfwInputJoystickHat(js, (int) i, states[state]);
}
}
return js->present;
}
void _glfwPlatformUpdateGamepadGUID(char* guid)
{
if ((strncmp(guid + 4, "000000000000", 12) == 0) &&
(strncmp(guid + 20, "000000000000", 12) == 0))
{
char original[33];
strcpy(original, guid);
sprintf(guid, "03000000%.4s0000%.4s000000000000",
original, original + 16);
}
}

526
glfw/cocoa_monitor.m Normal file
View File

@@ -0,0 +1,526 @@
//========================================================================
// GLFW 3.3 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <stdlib.h>
#include <limits.h>
#include <IOKit/graphics/IOGraphicsLib.h>
#include <CoreVideo/CVBase.h>
#include <CoreVideo/CVDisplayLink.h>
#include <ApplicationServices/ApplicationServices.h>
// Get the name of the specified display, or NULL
//
static char* getDisplayName(CGDirectDisplayID displayID)
{
io_iterator_t it;
io_service_t service;
CFDictionaryRef info;
if (IOServiceGetMatchingServices(kIOMasterPortDefault,
IOServiceMatching("IODisplayConnect"),
&it) != 0)
{
// This may happen if a desktop Mac is running headless
return NULL;
}
while ((service = IOIteratorNext(it)) != 0)
{
info = IODisplayCreateInfoDictionary(service,
kIODisplayOnlyPreferredName);
CFNumberRef vendorIDRef =
CFDictionaryGetValue(info, CFSTR(kDisplayVendorID));
CFNumberRef productIDRef =
CFDictionaryGetValue(info, CFSTR(kDisplayProductID));
if (!vendorIDRef || !productIDRef)
{
CFRelease(info);
continue;
}
unsigned int vendorID, productID;
CFNumberGetValue(vendorIDRef, kCFNumberIntType, &vendorID);
CFNumberGetValue(productIDRef, kCFNumberIntType, &productID);
if (CGDisplayVendorNumber(displayID) == vendorID &&
CGDisplayModelNumber(displayID) == productID)
{
// Info dictionary is used and freed below
break;
}
CFRelease(info);
}
IOObjectRelease(it);
if (!service)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Cocoa: Failed to find service port for display");
return NULL;
}
CFDictionaryRef names =
CFDictionaryGetValue(info, CFSTR(kDisplayProductName));
CFStringRef nameRef;
if (!names || !CFDictionaryGetValueIfPresent(names, CFSTR("en_US"),
(const void**) &nameRef))
{
// This may happen if a desktop Mac is running headless
CFRelease(info);
return NULL;
}
const CFIndex size =
CFStringGetMaximumSizeForEncoding(CFStringGetLength(nameRef),
kCFStringEncodingUTF8);
char* name = calloc(size + 1, 1);
CFStringGetCString(nameRef, name, size, kCFStringEncodingUTF8);
CFRelease(info);
return name;
}
// Check whether the display mode should be included in enumeration
//
static GLFWbool modeIsGood(CGDisplayModeRef mode)
{
uint32_t flags = CGDisplayModeGetIOFlags(mode);
if (!(flags & kDisplayModeValidFlag) || !(flags & kDisplayModeSafeFlag))
return GLFW_FALSE;
if (flags & kDisplayModeInterlacedFlag)
return GLFW_FALSE;
if (flags & kDisplayModeStretchedFlag)
return GLFW_FALSE;
#if MAC_OS_X_VERSION_MAX_ALLOWED <= 101100
CFStringRef format = CGDisplayModeCopyPixelEncoding(mode);
if (CFStringCompare(format, CFSTR(IO16BitDirectPixels), 0) &&
CFStringCompare(format, CFSTR(IO32BitDirectPixels), 0))
{
CFRelease(format);
return GLFW_FALSE;
}
CFRelease(format);
#endif /* MAC_OS_X_VERSION_MAX_ALLOWED */
return GLFW_TRUE;
}
// Convert Core Graphics display mode to GLFW video mode
//
static GLFWvidmode vidmodeFromCGDisplayMode(CGDisplayModeRef mode,
CVDisplayLinkRef link)
{
GLFWvidmode result;
result.width = (int) CGDisplayModeGetWidth(mode);
result.height = (int) CGDisplayModeGetHeight(mode);
result.refreshRate = (int) CGDisplayModeGetRefreshRate(mode);
if (result.refreshRate == 0)
{
const CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link);
if (!(time.flags & kCVTimeIsIndefinite))
result.refreshRate = (int) (time.timeScale / (double) time.timeValue);
}
#if MAC_OS_X_VERSION_MAX_ALLOWED <= 101100
CFStringRef format = CGDisplayModeCopyPixelEncoding(mode);
if (CFStringCompare(format, CFSTR(IO16BitDirectPixels), 0) == 0)
{
result.redBits = 5;
result.greenBits = 5;
result.blueBits = 5;
}
else
#endif /* MAC_OS_X_VERSION_MAX_ALLOWED */
{
result.redBits = 8;
result.greenBits = 8;
result.blueBits = 8;
}
#if MAC_OS_X_VERSION_MAX_ALLOWED <= 101100
CFRelease(format);
#endif /* MAC_OS_X_VERSION_MAX_ALLOWED */
return result;
}
// Starts reservation for display fading
//
static CGDisplayFadeReservationToken beginFadeReservation(void)
{
CGDisplayFadeReservationToken token = kCGDisplayFadeReservationInvalidToken;
if (CGAcquireDisplayFadeReservation(5, &token) == kCGErrorSuccess)
{
CGDisplayFade(token, 0.3,
kCGDisplayBlendNormal,
kCGDisplayBlendSolidColor,
0.0, 0.0, 0.0,
TRUE);
}
return token;
}
// Ends reservation for display fading
//
static void endFadeReservation(CGDisplayFadeReservationToken token)
{
if (token != kCGDisplayFadeReservationInvalidToken)
{
CGDisplayFade(token, 0.5,
kCGDisplayBlendSolidColor,
kCGDisplayBlendNormal,
0.0, 0.0, 0.0,
FALSE);
CGReleaseDisplayFadeReservation(token);
}
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
// Poll for changes in the set of connected monitors
//
void _glfwPollMonitorsNS(void)
{
uint32_t i, j, displayCount, disconnectedCount;
CGDirectDisplayID* displays;
_GLFWmonitor** disconnected = NULL;
CGGetOnlineDisplayList(0, NULL, &displayCount);
displays = calloc(displayCount, sizeof(CGDirectDisplayID));
CGGetOnlineDisplayList(displayCount, displays, &displayCount);
for (i = 0; i < _glfw.monitorCount; i++)
_glfw.monitors[i]->ns.screen = nil;
disconnectedCount = _glfw.monitorCount;
if (disconnectedCount)
{
disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*));
memcpy(disconnected,
_glfw.monitors,
_glfw.monitorCount * sizeof(_GLFWmonitor*));
}
for (i = 0; i < displayCount; i++)
{
_GLFWmonitor* monitor;
const uint32_t unitNumber = CGDisplayUnitNumber(displays[i]);
if (CGDisplayIsAsleep(displays[i]))
continue;
for (j = 0; j < disconnectedCount; j++)
{
// HACK: Compare unit numbers instead of display IDs to work around
// display replacement on machines with automatic graphics
// switching
if (disconnected[j] && disconnected[j]->ns.unitNumber == unitNumber)
{
disconnected[j] = NULL;
break;
}
}
const CGSize size = CGDisplayScreenSize(displays[i]);
char* name = getDisplayName(displays[i]);
if (!name)
name = _glfw_strdup("Unknown");
monitor = _glfwAllocMonitor(name, size.width, size.height);
monitor->ns.displayID = displays[i];
monitor->ns.unitNumber = unitNumber;
free(name);
_glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST);
}
for (i = 0; i < disconnectedCount; i++)
{
if (disconnected[i])
_glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0);
}
free(disconnected);
free(displays);
}
// Change the current video mode
//
void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired)
{
CFArrayRef modes;
CFIndex count, i;
CVDisplayLinkRef link;
CGDisplayModeRef native = NULL;
GLFWvidmode current;
const GLFWvidmode* best;
best = _glfwChooseVideoMode(monitor, desired);
_glfwPlatformGetVideoMode(monitor, &current);
if (_glfwCompareVideoModes(&current, best) == 0)
return;
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
count = CFArrayGetCount(modes);
for (i = 0; i < count; i++)
{
CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i);
if (!modeIsGood(dm))
continue;
const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link);
if (_glfwCompareVideoModes(best, &mode) == 0)
{
native = dm;
break;
}
}
if (native)
{
if (monitor->ns.previousMode == NULL)
monitor->ns.previousMode = CGDisplayCopyDisplayMode(monitor->ns.displayID);
CGDisplayFadeReservationToken token = beginFadeReservation();
CGDisplaySetDisplayMode(monitor->ns.displayID, native, NULL);
endFadeReservation(token);
}
CFRelease(modes);
CVDisplayLinkRelease(link);
}
// Restore the previously saved (original) video mode
//
void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor)
{
if (monitor->ns.previousMode)
{
CGDisplayFadeReservationToken token = beginFadeReservation();
CGDisplaySetDisplayMode(monitor->ns.displayID,
monitor->ns.previousMode, NULL);
endFadeReservation(token);
CGDisplayModeRelease(monitor->ns.previousMode);
monitor->ns.previousMode = NULL;
}
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
{
}
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
{
const CGRect bounds = CGDisplayBounds(monitor->ns.displayID);
if (xpos)
*xpos = (int) bounds.origin.x;
if (ypos)
*ypos = (int) bounds.origin.y;
}
void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
float* xscale, float* yscale)
{
if (!monitor->ns.screen)
{
NSUInteger i;
NSArray* screens = [NSScreen screens];
for (i = 0; i < [screens count]; i++)
{
NSScreen* screen = [screens objectAtIndex:i];
NSNumber* displayID =
[[screen deviceDescription] objectForKey:@"NSScreenNumber"];
// HACK: Compare unit numbers instead of display IDs to work around
// display replacement on machines with automatic graphics
// switching
if (monitor->ns.unitNumber ==
CGDisplayUnitNumber([displayID unsignedIntValue]))
{
monitor->ns.screen = screen;
break;
}
}
if (i == [screens count])
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Cocoa: Failed to find a screen for monitor");
return;
}
}
const NSRect points = [monitor->ns.screen frame];
const NSRect pixels = [monitor->ns.screen convertRectToBacking:points];
if (xscale)
*xscale = (float) (pixels.size.width / points.size.width);
if (yscale)
*yscale = (float) (pixels.size.height / points.size.height);
}
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
{
CFArrayRef modes;
CFIndex found, i, j;
GLFWvidmode* result;
CVDisplayLinkRef link;
*count = 0;
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
found = CFArrayGetCount(modes);
result = calloc(found, sizeof(GLFWvidmode));
for (i = 0; i < found; i++)
{
CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i);
if (!modeIsGood(dm))
continue;
const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link);
for (j = 0; j < *count; j++)
{
if (_glfwCompareVideoModes(result + j, &mode) == 0)
break;
}
// Skip duplicate modes
if (i < *count)
continue;
(*count)++;
result[*count - 1] = mode;
}
CFRelease(modes);
CVDisplayLinkRelease(link);
return result;
}
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode *mode)
{
CGDisplayModeRef displayMode;
CVDisplayLinkRef link;
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
displayMode = CGDisplayCopyDisplayMode(monitor->ns.displayID);
*mode = vidmodeFromCGDisplayMode(displayMode, link);
CGDisplayModeRelease(displayMode);
CVDisplayLinkRelease(link);
}
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{
uint32_t i, size = CGDisplayGammaTableCapacity(monitor->ns.displayID);
CGGammaValue* values = calloc(size * 3, sizeof(CGGammaValue));
CGGetDisplayTransferByTable(monitor->ns.displayID,
size,
values,
values + size,
values + size * 2,
&size);
_glfwAllocGammaArrays(ramp, size);
for (i = 0; i < size; i++)
{
ramp->red[i] = (unsigned short) (values[i] * 65535);
ramp->green[i] = (unsigned short) (values[i + size] * 65535);
ramp->blue[i] = (unsigned short) (values[i + size * 2] * 65535);
}
free(values);
}
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
{
int i;
CGGammaValue* values = calloc(ramp->size * 3, sizeof(CGGammaValue));
for (i = 0; i < ramp->size; i++)
{
values[i] = ramp->red[i] / 65535.f;
values[i + ramp->size] = ramp->green[i] / 65535.f;
values[i + ramp->size * 2] = ramp->blue[i] / 65535.f;
}
CGSetDisplayTransferByTable(monitor->ns.displayID,
ramp->size,
values,
values + ramp->size,
values + ramp->size * 2);
free(values);
}
//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////
//////////////////////////////////////////////////////////////////////////
GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* handle)
{
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
_GLFW_REQUIRE_INIT_OR_RETURN(kCGNullDirectDisplay);
return monitor->ns.displayID;
}

169
glfw/cocoa_platform.h vendored Normal file
View File

@@ -0,0 +1,169 @@
//========================================================================
// GLFW 3.3 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include <stdint.h>
#include <dlfcn.h>
#if defined(__OBJC__)
#import <Carbon/Carbon.h>
#import <Cocoa/Cocoa.h>
#else
#include <Carbon/Carbon.h>
#include <ApplicationServices/ApplicationServices.h>
typedef void* id;
#endif
typedef VkFlags VkMacOSSurfaceCreateFlagsMVK;
typedef struct VkMacOSSurfaceCreateInfoMVK
{
VkStructureType sType;
const void* pNext;
VkMacOSSurfaceCreateFlagsMVK flags;
const void* pView;
} VkMacOSSurfaceCreateInfoMVK;
typedef VkResult (APIENTRY *PFN_vkCreateMacOSSurfaceMVK)(VkInstance,const VkMacOSSurfaceCreateInfoMVK*,const VkAllocationCallbacks*,VkSurfaceKHR*);
#include "posix_thread.h"
#include "cocoa_joystick.h"
#include "nsgl_context.h"
#include "egl_context.h"
#include "osmesa_context.h"
#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
#define _glfw_dlclose(handle) dlclose(handle)
#define _glfw_dlsym(handle, name) dlsym(handle, name)
#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->ns.view)
#define _GLFW_EGL_NATIVE_DISPLAY EGL_DEFAULT_DISPLAY
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNS ns
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryNS ns
#define _GLFW_PLATFORM_LIBRARY_TIMER_STATE _GLFWtimerNS ns
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorNS ns
#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorNS ns
// HIToolbox.framework pointer typedefs
#define kTISPropertyUnicodeKeyLayoutData _glfw.ns.tis.kPropertyUnicodeKeyLayoutData
typedef TISInputSourceRef (*PFN_TISCopyCurrentKeyboardLayoutInputSource)(void);
#define TISCopyCurrentKeyboardLayoutInputSource _glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource
typedef void* (*PFN_TISGetInputSourceProperty)(TISInputSourceRef,CFStringRef);
#define TISGetInputSourceProperty _glfw.ns.tis.GetInputSourceProperty
typedef UInt8 (*PFN_LMGetKbdType)(void);
#define LMGetKbdType _glfw.ns.tis.GetKbdType
// Cocoa-specific per-window data
//
typedef struct _GLFWwindowNS
{
id object;
id delegate;
id view;
id layer;
GLFWbool maximized;
// Cached window properties to filter out duplicate events
int width, height;
int fbWidth, fbHeight;
float xscale, yscale;
// The total sum of the distances the cursor has been warped
// since the last cursor motion event was processed
// This is kept to counteract Cocoa doing the same internally
double cursorWarpDeltaX, cursorWarpDeltaY;
} _GLFWwindowNS;
// Cocoa-specific global data
//
typedef struct _GLFWlibraryNS
{
CGEventSourceRef eventSource;
id delegate;
id autoreleasePool;
GLFWbool cursorHidden;
TISInputSourceRef inputSource;
IOHIDManagerRef hidManager;
id unicodeData;
id listener;
char keyName[64];
short int keycodes[256];
short int scancodes[GLFW_KEY_LAST + 1];
char* clipboardString;
CGPoint cascadePoint;
// Where to place the cursor when re-enabled
double restoreCursorPosX, restoreCursorPosY;
// The window whose disabled cursor mode is active
_GLFWwindow* disabledCursorWindow;
struct {
CFBundleRef bundle;
PFN_TISCopyCurrentKeyboardLayoutInputSource CopyCurrentKeyboardLayoutInputSource;
PFN_TISGetInputSourceProperty GetInputSourceProperty;
PFN_LMGetKbdType GetKbdType;
CFStringRef kPropertyUnicodeKeyLayoutData;
} tis;
} _GLFWlibraryNS;
// Cocoa-specific per-monitor data
//
typedef struct _GLFWmonitorNS
{
CGDirectDisplayID displayID;
CGDisplayModeRef previousMode;
uint32_t unitNumber;
id screen;
} _GLFWmonitorNS;
// Cocoa-specific per-cursor data
//
typedef struct _GLFWcursorNS
{
id object;
} _GLFWcursorNS;
// Cocoa-specific global timer data
//
typedef struct _GLFWtimerNS
{
uint64_t frequency;
} _GLFWtimerNS;
void _glfwInitTimerNS(void);
void _glfwPollMonitorsNS(void);
void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired);
void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor);

60
glfw/cocoa_time.c vendored Normal file
View File

@@ -0,0 +1,60 @@
//========================================================================
// GLFW 3.3 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <mach/mach_time.h>
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
// Initialise timer
//
void _glfwInitTimerNS(void)
{
mach_timebase_info_data_t info;
mach_timebase_info(&info);
_glfw.timer.ns.frequency = (info.denom * 1e9) / info.numer;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
uint64_t _glfwPlatformGetTimerValue(void)
{
return mach_absolute_time();
}
uint64_t _glfwPlatformGetTimerFrequency(void)
{
return _glfw.timer.ns.frequency;
}

1908
glfw/cocoa_window.m Normal file

File diff suppressed because it is too large Load Diff

758
glfw/context.c vendored Normal file
View File

@@ -0,0 +1,758 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <stdio.h>
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
// Checks whether the desired context attributes are valid
//
// This function checks things like whether the specified client API version
// exists and whether all relevant options have supported and non-conflicting
// values
//
GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
{
if (ctxconfig->share)
{
if (ctxconfig->client == GLFW_NO_API ||
ctxconfig->share->context.client == GLFW_NO_API)
{
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
return GLFW_FALSE;
}
}
if (ctxconfig->source != GLFW_NATIVE_CONTEXT_API &&
ctxconfig->source != GLFW_EGL_CONTEXT_API &&
ctxconfig->source != GLFW_OSMESA_CONTEXT_API)
{
_glfwInputError(GLFW_INVALID_ENUM,
"Invalid context creation API 0x%08X",
ctxconfig->source);
return GLFW_FALSE;
}
if (ctxconfig->client != GLFW_NO_API &&
ctxconfig->client != GLFW_OPENGL_API &&
ctxconfig->client != GLFW_OPENGL_ES_API)
{
_glfwInputError(GLFW_INVALID_ENUM,
"Invalid client API 0x%08X",
ctxconfig->client);
return GLFW_FALSE;
}
if (ctxconfig->client == GLFW_OPENGL_API)
{
if ((ctxconfig->major < 1 || ctxconfig->minor < 0) ||
(ctxconfig->major == 1 && ctxconfig->minor > 5) ||
(ctxconfig->major == 2 && ctxconfig->minor > 1) ||
(ctxconfig->major == 3 && ctxconfig->minor > 3))
{
// OpenGL 1.0 is the smallest valid version
// OpenGL 1.x series ended with version 1.5
// OpenGL 2.x series ended with version 2.1
// OpenGL 3.x series ended with version 3.3
// For now, let everything else through
_glfwInputError(GLFW_INVALID_VALUE,
"Invalid OpenGL version %i.%i",
ctxconfig->major, ctxconfig->minor);
return GLFW_FALSE;
}
if (ctxconfig->profile)
{
if (ctxconfig->profile != GLFW_OPENGL_CORE_PROFILE &&
ctxconfig->profile != GLFW_OPENGL_COMPAT_PROFILE)
{
_glfwInputError(GLFW_INVALID_ENUM,
"Invalid OpenGL profile 0x%08X",
ctxconfig->profile);
return GLFW_FALSE;
}
if (ctxconfig->major <= 2 ||
(ctxconfig->major == 3 && ctxconfig->minor < 2))
{
// Desktop OpenGL context profiles are only defined for version 3.2
// and above
_glfwInputError(GLFW_INVALID_VALUE,
"Context profiles are only defined for OpenGL version 3.2 and above");
return GLFW_FALSE;
}
}
if (ctxconfig->forward && ctxconfig->major <= 2)
{
// Forward-compatible contexts are only defined for OpenGL version 3.0 and above
_glfwInputError(GLFW_INVALID_VALUE,
"Forward-compatibility is only defined for OpenGL version 3.0 and above");
return GLFW_FALSE;
}
}
else if (ctxconfig->client == GLFW_OPENGL_ES_API)
{
if (ctxconfig->major < 1 || ctxconfig->minor < 0 ||
(ctxconfig->major == 1 && ctxconfig->minor > 1) ||
(ctxconfig->major == 2 && ctxconfig->minor > 0))
{
// OpenGL ES 1.0 is the smallest valid version
// OpenGL ES 1.x series ended with version 1.1
// OpenGL ES 2.x series ended with version 2.0
// For now, let everything else through
_glfwInputError(GLFW_INVALID_VALUE,
"Invalid OpenGL ES version %i.%i",
ctxconfig->major, ctxconfig->minor);
return GLFW_FALSE;
}
}
if (ctxconfig->robustness)
{
if (ctxconfig->robustness != GLFW_NO_RESET_NOTIFICATION &&
ctxconfig->robustness != GLFW_LOSE_CONTEXT_ON_RESET)
{
_glfwInputError(GLFW_INVALID_ENUM,
"Invalid context robustness mode 0x%08X",
ctxconfig->robustness);
return GLFW_FALSE;
}
}
if (ctxconfig->release)
{
if (ctxconfig->release != GLFW_RELEASE_BEHAVIOR_NONE &&
ctxconfig->release != GLFW_RELEASE_BEHAVIOR_FLUSH)
{
_glfwInputError(GLFW_INVALID_ENUM,
"Invalid context release behavior 0x%08X",
ctxconfig->release);
return GLFW_FALSE;
}
}
return GLFW_TRUE;
}
// Chooses the framebuffer config that best matches the desired one
//
const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired,
const _GLFWfbconfig* alternatives,
unsigned int count)
{
unsigned int i;
unsigned int missing, leastMissing = UINT_MAX;
unsigned int colorDiff, leastColorDiff = UINT_MAX;
unsigned int extraDiff, leastExtraDiff = UINT_MAX;
const _GLFWfbconfig* current;
const _GLFWfbconfig* closest = NULL;
for (i = 0; i < count; i++)
{
current = alternatives + i;
if (desired->stereo > 0 && current->stereo == 0)
{
// Stereo is a hard constraint
continue;
}
if (desired->doublebuffer != current->doublebuffer)
{
// Double buffering is a hard constraint
continue;
}
// Count number of missing buffers
{
missing = 0;
if (desired->alphaBits > 0 && current->alphaBits == 0)
missing++;
if (desired->depthBits > 0 && current->depthBits == 0)
missing++;
if (desired->stencilBits > 0 && current->stencilBits == 0)
missing++;
if (desired->auxBuffers > 0 &&
current->auxBuffers < desired->auxBuffers)
{
missing += desired->auxBuffers - current->auxBuffers;
}
if (desired->samples > 0 && current->samples == 0)
{
// Technically, several multisampling buffers could be
// involved, but that's a lower level implementation detail and
// not important to us here, so we count them as one
missing++;
}
if (desired->transparent != current->transparent)
missing++;
}
// These polynomials make many small channel size differences matter
// less than one large channel size difference
// Calculate color channel size difference value
{
colorDiff = 0;
if (desired->redBits != GLFW_DONT_CARE)
{
colorDiff += (desired->redBits - current->redBits) *
(desired->redBits - current->redBits);
}
if (desired->greenBits != GLFW_DONT_CARE)
{
colorDiff += (desired->greenBits - current->greenBits) *
(desired->greenBits - current->greenBits);
}
if (desired->blueBits != GLFW_DONT_CARE)
{
colorDiff += (desired->blueBits - current->blueBits) *
(desired->blueBits - current->blueBits);
}
}
// Calculate non-color channel size difference value
{
extraDiff = 0;
if (desired->alphaBits != GLFW_DONT_CARE)
{
extraDiff += (desired->alphaBits - current->alphaBits) *
(desired->alphaBits - current->alphaBits);
}
if (desired->depthBits != GLFW_DONT_CARE)
{
extraDiff += (desired->depthBits - current->depthBits) *
(desired->depthBits - current->depthBits);
}
if (desired->stencilBits != GLFW_DONT_CARE)
{
extraDiff += (desired->stencilBits - current->stencilBits) *
(desired->stencilBits - current->stencilBits);
}
if (desired->accumRedBits != GLFW_DONT_CARE)
{
extraDiff += (desired->accumRedBits - current->accumRedBits) *
(desired->accumRedBits - current->accumRedBits);
}
if (desired->accumGreenBits != GLFW_DONT_CARE)
{
extraDiff += (desired->accumGreenBits - current->accumGreenBits) *
(desired->accumGreenBits - current->accumGreenBits);
}
if (desired->accumBlueBits != GLFW_DONT_CARE)
{
extraDiff += (desired->accumBlueBits - current->accumBlueBits) *
(desired->accumBlueBits - current->accumBlueBits);
}
if (desired->accumAlphaBits != GLFW_DONT_CARE)
{
extraDiff += (desired->accumAlphaBits - current->accumAlphaBits) *
(desired->accumAlphaBits - current->accumAlphaBits);
}
if (desired->samples != GLFW_DONT_CARE)
{
extraDiff += (desired->samples - current->samples) *
(desired->samples - current->samples);
}
if (desired->sRGB && !current->sRGB)
extraDiff++;
}
// Figure out if the current one is better than the best one found so far
// Least number of missing buffers is the most important heuristic,
// then color buffer size match and lastly size match for other buffers
if (missing < leastMissing)
closest = current;
else if (missing == leastMissing)
{
if ((colorDiff < leastColorDiff) ||
(colorDiff == leastColorDiff && extraDiff < leastExtraDiff))
{
closest = current;
}
}
if (current == closest)
{
leastMissing = missing;
leastColorDiff = colorDiff;
leastExtraDiff = extraDiff;
}
}
return closest;
}
// Retrieves the attributes of the current context
//
GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig)
{
int i;
_GLFWwindow* previous;
const char* version;
const char* prefixes[] =
{
"OpenGL ES-CM ",
"OpenGL ES-CL ",
"OpenGL ES ",
NULL
};
window->context.source = ctxconfig->source;
window->context.client = GLFW_OPENGL_API;
previous = _glfwPlatformGetTls(&_glfw.contextSlot);;
glfwMakeContextCurrent((GLFWwindow*) window);
window->context.GetIntegerv = (PFNGLGETINTEGERVPROC)
window->context.getProcAddress("glGetIntegerv");
window->context.GetString = (PFNGLGETSTRINGPROC)
window->context.getProcAddress("glGetString");
if (!window->context.GetIntegerv || !window->context.GetString)
{
_glfwInputError(GLFW_PLATFORM_ERROR, "Entry point retrieval is broken");
glfwMakeContextCurrent((GLFWwindow*) previous);
return GLFW_FALSE;
}
version = (const char*) window->context.GetString(GL_VERSION);
if (!version)
{
if (ctxconfig->client == GLFW_OPENGL_API)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"OpenGL version string retrieval is broken");
}
else
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"OpenGL ES version string retrieval is broken");
}
glfwMakeContextCurrent((GLFWwindow*) previous);
return GLFW_FALSE;
}
for (i = 0; prefixes[i]; i++)
{
const size_t length = strlen(prefixes[i]);
if (strncmp(version, prefixes[i], length) == 0)
{
version += length;
window->context.client = GLFW_OPENGL_ES_API;
break;
}
}
if (!sscanf(version, "%d.%d.%d",
&window->context.major,
&window->context.minor,
&window->context.revision))
{
if (window->context.client == GLFW_OPENGL_API)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"No version found in OpenGL version string");
}
else
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"No version found in OpenGL ES version string");
}
glfwMakeContextCurrent((GLFWwindow*) previous);
return GLFW_FALSE;
}
if (window->context.major < ctxconfig->major ||
(window->context.major == ctxconfig->major &&
window->context.minor < ctxconfig->minor))
{
// The desired OpenGL version is greater than the actual version
// This only happens if the machine lacks {GLX|WGL}_ARB_create_context
// /and/ the user has requested an OpenGL version greater than 1.0
// For API consistency, we emulate the behavior of the
// {GLX|WGL}_ARB_create_context extension and fail here
if (window->context.client == GLFW_OPENGL_API)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"Requested OpenGL version %i.%i, got version %i.%i",
ctxconfig->major, ctxconfig->minor,
window->context.major, window->context.minor);
}
else
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"Requested OpenGL ES version %i.%i, got version %i.%i",
ctxconfig->major, ctxconfig->minor,
window->context.major, window->context.minor);
}
glfwMakeContextCurrent((GLFWwindow*) previous);
return GLFW_FALSE;
}
if (window->context.major >= 3)
{
// OpenGL 3.0+ uses a different function for extension string retrieval
// We cache it here instead of in glfwExtensionSupported mostly to alert
// users as early as possible that their build may be broken
window->context.GetStringi = (PFNGLGETSTRINGIPROC)
window->context.getProcAddress("glGetStringi");
if (!window->context.GetStringi)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Entry point retrieval is broken");
glfwMakeContextCurrent((GLFWwindow*) previous);
return GLFW_FALSE;
}
}
if (window->context.client == GLFW_OPENGL_API)
{
// Read back context flags (OpenGL 3.0 and above)
if (window->context.major >= 3)
{
GLint flags;
window->context.GetIntegerv(GL_CONTEXT_FLAGS, &flags);
if (flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT)
window->context.forward = GLFW_TRUE;
if (flags & GL_CONTEXT_FLAG_DEBUG_BIT)
window->context.debug = GLFW_TRUE;
else if (glfwExtensionSupported("GL_ARB_debug_output") &&
ctxconfig->debug)
{
// HACK: This is a workaround for older drivers (pre KHR_debug)
// not setting the debug bit in the context flags for
// debug contexts
window->context.debug = GLFW_TRUE;
}
if (flags & GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR)
window->context.noerror = GLFW_TRUE;
}
// Read back OpenGL context profile (OpenGL 3.2 and above)
if (window->context.major >= 4 ||
(window->context.major == 3 && window->context.minor >= 2))
{
GLint mask;
window->context.GetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask);
if (mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
window->context.profile = GLFW_OPENGL_COMPAT_PROFILE;
else if (mask & GL_CONTEXT_CORE_PROFILE_BIT)
window->context.profile = GLFW_OPENGL_CORE_PROFILE;
else if (glfwExtensionSupported("GL_ARB_compatibility"))
{
// HACK: This is a workaround for the compatibility profile bit
// not being set in the context flags if an OpenGL 3.2+
// context was created without having requested a specific
// version
window->context.profile = GLFW_OPENGL_COMPAT_PROFILE;
}
}
// Read back robustness strategy
if (glfwExtensionSupported("GL_ARB_robustness"))
{
// NOTE: We avoid using the context flags for detection, as they are
// only present from 3.0 while the extension applies from 1.1
GLint strategy;
window->context.GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB,
&strategy);
if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB)
window->context.robustness = GLFW_LOSE_CONTEXT_ON_RESET;
else if (strategy == GL_NO_RESET_NOTIFICATION_ARB)
window->context.robustness = GLFW_NO_RESET_NOTIFICATION;
}
}
else
{
// Read back robustness strategy
if (glfwExtensionSupported("GL_EXT_robustness"))
{
// NOTE: The values of these constants match those of the OpenGL ARB
// one, so we can reuse them here
GLint strategy;
window->context.GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB,
&strategy);
if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB)
window->context.robustness = GLFW_LOSE_CONTEXT_ON_RESET;
else if (strategy == GL_NO_RESET_NOTIFICATION_ARB)
window->context.robustness = GLFW_NO_RESET_NOTIFICATION;
}
}
if (glfwExtensionSupported("GL_KHR_context_flush_control"))
{
GLint behavior;
window->context.GetIntegerv(GL_CONTEXT_RELEASE_BEHAVIOR, &behavior);
if (behavior == GL_NONE)
window->context.release = GLFW_RELEASE_BEHAVIOR_NONE;
else if (behavior == GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH)
window->context.release = GLFW_RELEASE_BEHAVIOR_FLUSH;
}
// Clearing the front buffer to black to avoid garbage pixels left over from
// previous uses of our bit of VRAM
{
PFNGLCLEARPROC glClear = (PFNGLCLEARPROC)
window->context.getProcAddress("glClear");
glClear(GL_COLOR_BUFFER_BIT);
window->context.swapBuffers(window);
}
glfwMakeContextCurrent((GLFWwindow*) previous);
return GLFW_TRUE;
}
// Searches an extension string for the specified extension
//
GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions)
{
const char* start = extensions;
for (;;)
{
const char* where;
const char* terminator;
where = strstr(start, string);
if (!where)
return GLFW_FALSE;
terminator = where + strlen(string);
if (where == start || *(where - 1) == ' ')
{
if (*terminator == ' ' || *terminator == '\0')
break;
}
start = terminator;
}
return GLFW_TRUE;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW public API //////
//////////////////////////////////////////////////////////////////////////
GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
_GLFWwindow* previous = _glfwPlatformGetTls(&_glfw.contextSlot);
_GLFW_REQUIRE_INIT();
if (window && window->context.client == GLFW_NO_API)
{
_glfwInputError(GLFW_NO_WINDOW_CONTEXT,
"Cannot make current with a window that has no OpenGL or OpenGL ES context");
return;
}
if (previous)
{
if (!window || window->context.source != previous->context.source)
previous->context.makeCurrent(NULL);
}
if (window)
window->context.makeCurrent(window);
}
GLFWAPI GLFWwindow* glfwGetCurrentContext(void)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
return _glfwPlatformGetTls(&_glfw.contextSlot);
}
GLFWAPI void glfwSwapBuffers(GLFWwindow* handle)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
_GLFW_REQUIRE_INIT();
if (window->context.client == GLFW_NO_API)
{
_glfwInputError(GLFW_NO_WINDOW_CONTEXT,
"Cannot swap buffers of a window that has no OpenGL or OpenGL ES context");
return;
}
window->context.swapBuffers(window);
}
GLFWAPI void glfwSwapInterval(int interval)
{
_GLFWwindow* window;
_GLFW_REQUIRE_INIT();
window = _glfwPlatformGetTls(&_glfw.contextSlot);
if (!window)
{
_glfwInputError(GLFW_NO_CURRENT_CONTEXT,
"Cannot set swap interval without a current OpenGL or OpenGL ES context");
return;
}
window->context.swapInterval(interval);
}
GLFWAPI int glfwExtensionSupported(const char* extension)
{
_GLFWwindow* window;
assert(extension != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
window = _glfwPlatformGetTls(&_glfw.contextSlot);
if (!window)
{
_glfwInputError(GLFW_NO_CURRENT_CONTEXT,
"Cannot query extension without a current OpenGL or OpenGL ES context");
return GLFW_FALSE;
}
if (*extension == '\0')
{
_glfwInputError(GLFW_INVALID_VALUE, "Extension name cannot be an empty string");
return GLFW_FALSE;
}
if (window->context.major >= 3)
{
int i;
GLint count;
// Check if extension is in the modern OpenGL extensions string list
window->context.GetIntegerv(GL_NUM_EXTENSIONS, &count);
for (i = 0; i < count; i++)
{
const char* en = (const char*)
window->context.GetStringi(GL_EXTENSIONS, i);
if (!en)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Extension string retrieval is broken");
return GLFW_FALSE;
}
if (strcmp(en, extension) == 0)
return GLFW_TRUE;
}
}
else
{
// Check if extension is in the old style OpenGL extensions string
const char* extensions = (const char*)
window->context.GetString(GL_EXTENSIONS);
if (!extensions)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Extension string retrieval is broken");
return GLFW_FALSE;
}
if (_glfwStringInExtensionString(extension, extensions))
return GLFW_TRUE;
}
// Check if extension is in the platform-specific string
return window->context.extensionSupported(extension);
}
GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname)
{
_GLFWwindow* window;
assert(procname != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
window = _glfwPlatformGetTls(&_glfw.contextSlot);
if (!window)
{
_glfwInputError(GLFW_NO_CURRENT_CONTEXT,
"Cannot query entry point without a current OpenGL or OpenGL ES context");
return NULL;
}
return window->context.getProcAddress(procname);
}

786
glfw/egl_context.c vendored Normal file
View File

@@ -0,0 +1,786 @@
//========================================================================
// GLFW 3.3 EGL - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
// Return a description of the specified EGL error
//
static const char* getEGLErrorString(EGLint error)
{
switch (error)
{
case EGL_SUCCESS:
return "Success";
case EGL_NOT_INITIALIZED:
return "EGL is not or could not be initialized";
case EGL_BAD_ACCESS:
return "EGL cannot access a requested resource";
case EGL_BAD_ALLOC:
return "EGL failed to allocate resources for the requested operation";
case EGL_BAD_ATTRIBUTE:
return "An unrecognized attribute or attribute value was passed in the attribute list";
case EGL_BAD_CONTEXT:
return "An EGLContext argument does not name a valid EGL rendering context";
case EGL_BAD_CONFIG:
return "An EGLConfig argument does not name a valid EGL frame buffer configuration";
case EGL_BAD_CURRENT_SURFACE:
return "The current surface of the calling thread is a window, pixel buffer or pixmap that is no longer valid";
case EGL_BAD_DISPLAY:
return "An EGLDisplay argument does not name a valid EGL display connection";
case EGL_BAD_SURFACE:
return "An EGLSurface argument does not name a valid surface configured for GL rendering";
case EGL_BAD_MATCH:
return "Arguments are inconsistent";
case EGL_BAD_PARAMETER:
return "One or more argument values are invalid";
case EGL_BAD_NATIVE_PIXMAP:
return "A NativePixmapType argument does not refer to a valid native pixmap";
case EGL_BAD_NATIVE_WINDOW:
return "A NativeWindowType argument does not refer to a valid native window";
case EGL_CONTEXT_LOST:
return "The application must destroy all contexts and reinitialise";
default:
return "ERROR: UNKNOWN EGL ERROR";
}
}
// Returns the specified attribute of the specified EGLConfig
//
static int getEGLConfigAttrib(EGLConfig config, int attrib)
{
int value;
eglGetConfigAttrib(_glfw.egl.display, config, attrib, &value);
return value;
}
// Return the EGLConfig most closely matching the specified hints
//
static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* desired,
EGLConfig* result)
{
EGLConfig* nativeConfigs;
_GLFWfbconfig* usableConfigs;
const _GLFWfbconfig* closest;
int i, nativeCount, usableCount;
eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount);
if (!nativeCount)
{
_glfwInputError(GLFW_API_UNAVAILABLE, "EGL: No EGLConfigs returned");
return GLFW_FALSE;
}
nativeConfigs = calloc(nativeCount, sizeof(EGLConfig));
eglGetConfigs(_glfw.egl.display, nativeConfigs, nativeCount, &nativeCount);
usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig));
usableCount = 0;
for (i = 0; i < nativeCount; i++)
{
const EGLConfig n = nativeConfigs[i];
_GLFWfbconfig* u = usableConfigs + usableCount;
// Only consider RGB(A) EGLConfigs
if (getEGLConfigAttrib(n, EGL_COLOR_BUFFER_TYPE) != EGL_RGB_BUFFER)
continue;
// Only consider window EGLConfigs
if (!(getEGLConfigAttrib(n, EGL_SURFACE_TYPE) & EGL_WINDOW_BIT))
continue;
#if defined(_GLFW_X11)
XVisualInfo vi = {0};
// Only consider EGLConfigs with associated Visuals
vi.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID);
if (!vi.visualid)
continue;
if (desired->transparent)
{
int count;
XVisualInfo* vis = XGetVisualInfo(_glfw.x11.display,
VisualIDMask, &vi,
&count);
if (vis)
{
u->transparent = _glfwIsVisualTransparentX11(vis[0].visual);
XFree(vis);
}
}
#endif // _GLFW_X11
if (ctxconfig->client == GLFW_OPENGL_ES_API)
{
if (ctxconfig->major == 1)
{
if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES_BIT))
continue;
}
else
{
if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT))
continue;
}
}
else if (ctxconfig->client == GLFW_OPENGL_API)
{
if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_BIT))
continue;
}
u->redBits = getEGLConfigAttrib(n, EGL_RED_SIZE);
u->greenBits = getEGLConfigAttrib(n, EGL_GREEN_SIZE);
u->blueBits = getEGLConfigAttrib(n, EGL_BLUE_SIZE);
u->alphaBits = getEGLConfigAttrib(n, EGL_ALPHA_SIZE);
u->depthBits = getEGLConfigAttrib(n, EGL_DEPTH_SIZE);
u->stencilBits = getEGLConfigAttrib(n, EGL_STENCIL_SIZE);
u->samples = getEGLConfigAttrib(n, EGL_SAMPLES);
u->doublebuffer = GLFW_TRUE;
u->handle = (uintptr_t) n;
usableCount++;
}
closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);
if (closest)
*result = (EGLConfig) closest->handle;
free(nativeConfigs);
free(usableConfigs);
return closest != NULL;
}
static void makeContextCurrentEGL(_GLFWwindow* window)
{
if (window)
{
if (!eglMakeCurrent(_glfw.egl.display,
window->context.egl.surface,
window->context.egl.surface,
window->context.egl.handle))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"EGL: Failed to make context current: %s",
getEGLErrorString(eglGetError()));
return;
}
}
else
{
if (!eglMakeCurrent(_glfw.egl.display,
EGL_NO_SURFACE,
EGL_NO_SURFACE,
EGL_NO_CONTEXT))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"EGL: Failed to clear current context: %s",
getEGLErrorString(eglGetError()));
return;
}
}
_glfwPlatformSetTls(&_glfw.contextSlot, window);
}
static void swapBuffersEGL(_GLFWwindow* window)
{
if (window != _glfwPlatformGetTls(&_glfw.contextSlot))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"EGL: The context must be current on the calling thread when swapping buffers");
return;
}
eglSwapBuffers(_glfw.egl.display, window->context.egl.surface);
}
static void swapIntervalEGL(int interval)
{
eglSwapInterval(_glfw.egl.display, interval);
}
static int extensionSupportedEGL(const char* extension)
{
const char* extensions = eglQueryString(_glfw.egl.display, EGL_EXTENSIONS);
if (extensions)
{
if (_glfwStringInExtensionString(extension, extensions))
return GLFW_TRUE;
}
return GLFW_FALSE;
}
static GLFWglproc getProcAddressEGL(const char* procname)
{
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
if (window->context.egl.client)
{
GLFWglproc proc = (GLFWglproc) _glfw_dlsym(window->context.egl.client,
procname);
if (proc)
return proc;
}
return eglGetProcAddress(procname);
}
static void destroyContextEGL(_GLFWwindow* window)
{
#if defined(_GLFW_X11)
// NOTE: Do not unload libGL.so.1 while the X11 display is still open,
// as it will make XCloseDisplay segfault
if (window->context.client != GLFW_OPENGL_API)
#endif // _GLFW_X11
{
if (window->context.egl.client)
{
_glfw_dlclose(window->context.egl.client);
window->context.egl.client = NULL;
}
}
if (window->context.egl.surface)
{
eglDestroySurface(_glfw.egl.display, window->context.egl.surface);
window->context.egl.surface = EGL_NO_SURFACE;
}
if (window->context.egl.handle)
{
eglDestroyContext(_glfw.egl.display, window->context.egl.handle);
window->context.egl.handle = EGL_NO_CONTEXT;
}
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
// Initialize EGL
//
GLFWbool _glfwInitEGL(void)
{
int i;
const char* sonames[] =
{
#if defined(_GLFW_EGL_LIBRARY)
_GLFW_EGL_LIBRARY,
#elif defined(_GLFW_WIN32)
"libEGL.dll",
"EGL.dll",
#elif defined(_GLFW_COCOA)
"libEGL.dylib",
#elif defined(__CYGWIN__)
"libEGL-1.so",
#else
"libEGL.so.1",
#endif
NULL
};
if (_glfw.egl.handle)
return GLFW_TRUE;
for (i = 0; sonames[i]; i++)
{
_glfw.egl.handle = _glfw_dlopen(sonames[i]);
if (_glfw.egl.handle)
break;
}
if (!_glfw.egl.handle)
{
_glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Library not found");
return GLFW_FALSE;
}
_glfw.egl.prefix = (strncmp(sonames[i], "lib", 3) == 0);
_glfw.egl.GetConfigAttrib = (PFN_eglGetConfigAttrib)
_glfw_dlsym(_glfw.egl.handle, "eglGetConfigAttrib");
_glfw.egl.GetConfigs = (PFN_eglGetConfigs)
_glfw_dlsym(_glfw.egl.handle, "eglGetConfigs");
_glfw.egl.GetDisplay = (PFN_eglGetDisplay)
_glfw_dlsym(_glfw.egl.handle, "eglGetDisplay");
_glfw.egl.GetError = (PFN_eglGetError)
_glfw_dlsym(_glfw.egl.handle, "eglGetError");
_glfw.egl.Initialize = (PFN_eglInitialize)
_glfw_dlsym(_glfw.egl.handle, "eglInitialize");
_glfw.egl.Terminate = (PFN_eglTerminate)
_glfw_dlsym(_glfw.egl.handle, "eglTerminate");
_glfw.egl.BindAPI = (PFN_eglBindAPI)
_glfw_dlsym(_glfw.egl.handle, "eglBindAPI");
_glfw.egl.CreateContext = (PFN_eglCreateContext)
_glfw_dlsym(_glfw.egl.handle, "eglCreateContext");
_glfw.egl.DestroySurface = (PFN_eglDestroySurface)
_glfw_dlsym(_glfw.egl.handle, "eglDestroySurface");
_glfw.egl.DestroyContext = (PFN_eglDestroyContext)
_glfw_dlsym(_glfw.egl.handle, "eglDestroyContext");
_glfw.egl.CreateWindowSurface = (PFN_eglCreateWindowSurface)
_glfw_dlsym(_glfw.egl.handle, "eglCreateWindowSurface");
_glfw.egl.MakeCurrent = (PFN_eglMakeCurrent)
_glfw_dlsym(_glfw.egl.handle, "eglMakeCurrent");
_glfw.egl.SwapBuffers = (PFN_eglSwapBuffers)
_glfw_dlsym(_glfw.egl.handle, "eglSwapBuffers");
_glfw.egl.SwapInterval = (PFN_eglSwapInterval)
_glfw_dlsym(_glfw.egl.handle, "eglSwapInterval");
_glfw.egl.QueryString = (PFN_eglQueryString)
_glfw_dlsym(_glfw.egl.handle, "eglQueryString");
_glfw.egl.GetProcAddress = (PFN_eglGetProcAddress)
_glfw_dlsym(_glfw.egl.handle, "eglGetProcAddress");
if (!_glfw.egl.GetConfigAttrib ||
!_glfw.egl.GetConfigs ||
!_glfw.egl.GetDisplay ||
!_glfw.egl.GetError ||
!_glfw.egl.Initialize ||
!_glfw.egl.Terminate ||
!_glfw.egl.BindAPI ||
!_glfw.egl.CreateContext ||
!_glfw.egl.DestroySurface ||
!_glfw.egl.DestroyContext ||
!_glfw.egl.CreateWindowSurface ||
!_glfw.egl.MakeCurrent ||
!_glfw.egl.SwapBuffers ||
!_glfw.egl.SwapInterval ||
!_glfw.egl.QueryString ||
!_glfw.egl.GetProcAddress)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"EGL: Failed to load required entry points");
_glfwTerminateEGL();
return GLFW_FALSE;
}
_glfw.egl.display = eglGetDisplay(_GLFW_EGL_NATIVE_DISPLAY);
if (_glfw.egl.display == EGL_NO_DISPLAY)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"EGL: Failed to get EGL display: %s",
getEGLErrorString(eglGetError()));
_glfwTerminateEGL();
return GLFW_FALSE;
}
if (!eglInitialize(_glfw.egl.display, &_glfw.egl.major, &_glfw.egl.minor))
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"EGL: Failed to initialize EGL: %s",
getEGLErrorString(eglGetError()));
_glfwTerminateEGL();
return GLFW_FALSE;
}
_glfw.egl.KHR_create_context =
extensionSupportedEGL("EGL_KHR_create_context");
_glfw.egl.KHR_create_context_no_error =
extensionSupportedEGL("EGL_KHR_create_context_no_error");
_glfw.egl.KHR_gl_colorspace =
extensionSupportedEGL("EGL_KHR_gl_colorspace");
_glfw.egl.KHR_get_all_proc_addresses =
extensionSupportedEGL("EGL_KHR_get_all_proc_addresses");
_glfw.egl.KHR_context_flush_control =
extensionSupportedEGL("EGL_KHR_context_flush_control");
return GLFW_TRUE;
}
// Terminate EGL
//
void _glfwTerminateEGL(void)
{
if (_glfw.egl.display)
{
eglTerminate(_glfw.egl.display);
_glfw.egl.display = EGL_NO_DISPLAY;
}
if (_glfw.egl.handle)
{
_glfw_dlclose(_glfw.egl.handle);
_glfw.egl.handle = NULL;
}
}
#define setAttrib(a, v) \
{ \
assert((size_t) (index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
attribs[index++] = a; \
attribs[index++] = v; \
}
// Create the OpenGL or OpenGL ES context
//
GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
EGLint attribs[40];
EGLConfig config;
EGLContext share = NULL;
int index = 0;
if (!_glfw.egl.display)
{
_glfwInputError(GLFW_API_UNAVAILABLE, "EGL: API not available");
return GLFW_FALSE;
}
if (ctxconfig->share)
share = ctxconfig->share->context.egl.handle;
if (!chooseEGLConfig(ctxconfig, fbconfig, &config))
{
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
"EGL: Failed to find a suitable EGLConfig");
return GLFW_FALSE;
}
if (ctxconfig->client == GLFW_OPENGL_ES_API)
{
if (!eglBindAPI(EGL_OPENGL_ES_API))
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"EGL: Failed to bind OpenGL ES: %s",
getEGLErrorString(eglGetError()));
return GLFW_FALSE;
}
}
else
{
if (!eglBindAPI(EGL_OPENGL_API))
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"EGL: Failed to bind OpenGL: %s",
getEGLErrorString(eglGetError()));
return GLFW_FALSE;
}
}
if (_glfw.egl.KHR_create_context)
{
int mask = 0, flags = 0;
if (ctxconfig->client == GLFW_OPENGL_API)
{
if (ctxconfig->forward)
flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
mask |= EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
mask |= EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR;
}
if (ctxconfig->debug)
flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
if (ctxconfig->robustness)
{
if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
{
setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR,
EGL_NO_RESET_NOTIFICATION_KHR);
}
else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
{
setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR,
EGL_LOSE_CONTEXT_ON_RESET_KHR);
}
flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
}
if (ctxconfig->noerror)
{
if (_glfw.egl.KHR_create_context_no_error)
setAttrib(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE);
}
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
{
setAttrib(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major);
setAttrib(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor);
}
if (mask)
setAttrib(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask);
if (flags)
setAttrib(EGL_CONTEXT_FLAGS_KHR, flags);
}
else
{
if (ctxconfig->client == GLFW_OPENGL_ES_API)
setAttrib(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major);
}
if (_glfw.egl.KHR_context_flush_control)
{
if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE)
{
setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR,
EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR);
}
else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH)
{
setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR,
EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR);
}
}
setAttrib(EGL_NONE, EGL_NONE);
window->context.egl.handle = eglCreateContext(_glfw.egl.display,
config, share, attribs);
if (window->context.egl.handle == EGL_NO_CONTEXT)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"EGL: Failed to create context: %s",
getEGLErrorString(eglGetError()));
return GLFW_FALSE;
}
// Set up attributes for surface creation
{
int index = 0;
if (fbconfig->sRGB)
{
if (_glfw.egl.KHR_gl_colorspace)
setAttrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR);
}
setAttrib(EGL_NONE, EGL_NONE);
}
window->context.egl.surface =
eglCreateWindowSurface(_glfw.egl.display,
config,
_GLFW_EGL_NATIVE_WINDOW,
attribs);
if (window->context.egl.surface == EGL_NO_SURFACE)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"EGL: Failed to create window surface: %s",
getEGLErrorString(eglGetError()));
return GLFW_FALSE;
}
window->context.egl.config = config;
// Load the appropriate client library
if (!_glfw.egl.KHR_get_all_proc_addresses)
{
int i;
const char** sonames;
const char* es1sonames[] =
{
#if defined(_GLFW_GLESV1_LIBRARY)
_GLFW_GLESV1_LIBRARY,
#elif defined(_GLFW_WIN32)
"GLESv1_CM.dll",
"libGLES_CM.dll",
#elif defined(_GLFW_COCOA)
"libGLESv1_CM.dylib",
#else
"libGLESv1_CM.so.1",
"libGLES_CM.so.1",
#endif
NULL
};
const char* es2sonames[] =
{
#if defined(_GLFW_GLESV2_LIBRARY)
_GLFW_GLESV2_LIBRARY,
#elif defined(_GLFW_WIN32)
"GLESv2.dll",
"libGLESv2.dll",
#elif defined(_GLFW_COCOA)
"libGLESv2.dylib",
#elif defined(__CYGWIN__)
"libGLESv2-2.so",
#else
"libGLESv2.so.2",
#endif
NULL
};
const char* glsonames[] =
{
#if defined(_GLFW_OPENGL_LIBRARY)
_GLFW_OPENGL_LIBRARY,
#elif defined(_GLFW_WIN32)
#elif defined(_GLFW_COCOA)
#else
"libGL.so.1",
#endif
NULL
};
if (ctxconfig->client == GLFW_OPENGL_ES_API)
{
if (ctxconfig->major == 1)
sonames = es1sonames;
else
sonames = es2sonames;
}
else
sonames = glsonames;
for (i = 0; sonames[i]; i++)
{
// HACK: Match presence of lib prefix to increase chance of finding
// a matching pair in the jungle that is Win32 EGL/GLES
if (_glfw.egl.prefix != (strncmp(sonames[i], "lib", 3) == 0))
continue;
window->context.egl.client = _glfw_dlopen(sonames[i]);
if (window->context.egl.client)
break;
}
if (!window->context.egl.client)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"EGL: Failed to load client library");
return GLFW_FALSE;
}
}
window->context.makeCurrent = makeContextCurrentEGL;
window->context.swapBuffers = swapBuffersEGL;
window->context.swapInterval = swapIntervalEGL;
window->context.extensionSupported = extensionSupportedEGL;
window->context.getProcAddress = getProcAddressEGL;
window->context.destroy = destroyContextEGL;
return GLFW_TRUE;
}
#undef setAttrib
// Returns the Visual and depth of the chosen EGLConfig
//
#if defined(_GLFW_X11)
GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig,
Visual** visual, int* depth)
{
XVisualInfo* result;
XVisualInfo desired;
EGLConfig native;
EGLint visualID = 0, count = 0;
const long vimask = VisualScreenMask | VisualIDMask;
if (!chooseEGLConfig(ctxconfig, fbconfig, &native))
{
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
"EGL: Failed to find a suitable EGLConfig");
return GLFW_FALSE;
}
eglGetConfigAttrib(_glfw.egl.display, native,
EGL_NATIVE_VISUAL_ID, &visualID);
desired.screen = _glfw.x11.screen;
desired.visualid = visualID;
result = XGetVisualInfo(_glfw.x11.display, vimask, &desired, &count);
if (!result)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"EGL: Failed to retrieve Visual for EGLConfig");
return GLFW_FALSE;
}
*visual = result->visual;
*depth = result->depth;
XFree(result);
return GLFW_TRUE;
}
#endif // _GLFW_X11
//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////
//////////////////////////////////////////////////////////////////////////
GLFWAPI EGLDisplay glfwGetEGLDisplay(void)
{
_GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_DISPLAY);
return _glfw.egl.display;
}
GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* handle)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
_GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_CONTEXT);
if (window->context.client == GLFW_NO_API)
{
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
return EGL_NO_CONTEXT;
}
return window->context.egl.handle;
}
GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* handle)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
_GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_SURFACE);
if (window->context.client == GLFW_NO_API)
{
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
return EGL_NO_SURFACE;
}
return window->context.egl.surface;
}

219
glfw/egl_context.h vendored Normal file
View File

@@ -0,0 +1,219 @@
//========================================================================
// GLFW 3.3 EGL - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#if defined(_GLFW_USE_EGLPLATFORM_H)
#include <EGL/eglplatform.h>
#elif defined(_GLFW_WIN32)
#define EGLAPIENTRY __stdcall
typedef HDC EGLNativeDisplayType;
typedef HWND EGLNativeWindowType;
#elif defined(_GLFW_COCOA)
#define EGLAPIENTRY
typedef void* EGLNativeDisplayType;
typedef id EGLNativeWindowType;
#elif defined(_GLFW_X11)
#define EGLAPIENTRY
typedef Display* EGLNativeDisplayType;
typedef Window EGLNativeWindowType;
#elif defined(_GLFW_WAYLAND)
#define EGLAPIENTRY
typedef struct wl_display* EGLNativeDisplayType;
typedef struct wl_egl_window* EGLNativeWindowType;
#elif defined(_GLFW_MIR)
#define EGLAPIENTRY
typedef MirEGLNativeDisplayType EGLNativeDisplayType;
typedef MirEGLNativeWindowType EGLNativeWindowType;
#else
#error "No supported EGL platform selected"
#endif
#define EGL_SUCCESS 0x3000
#define EGL_NOT_INITIALIZED 0x3001
#define EGL_BAD_ACCESS 0x3002
#define EGL_BAD_ALLOC 0x3003
#define EGL_BAD_ATTRIBUTE 0x3004
#define EGL_BAD_CONFIG 0x3005
#define EGL_BAD_CONTEXT 0x3006
#define EGL_BAD_CURRENT_SURFACE 0x3007
#define EGL_BAD_DISPLAY 0x3008
#define EGL_BAD_MATCH 0x3009
#define EGL_BAD_NATIVE_PIXMAP 0x300a
#define EGL_BAD_NATIVE_WINDOW 0x300b
#define EGL_BAD_PARAMETER 0x300c
#define EGL_BAD_SURFACE 0x300d
#define EGL_CONTEXT_LOST 0x300e
#define EGL_COLOR_BUFFER_TYPE 0x303f
#define EGL_RGB_BUFFER 0x308e
#define EGL_SURFACE_TYPE 0x3033
#define EGL_WINDOW_BIT 0x0004
#define EGL_RENDERABLE_TYPE 0x3040
#define EGL_OPENGL_ES_BIT 0x0001
#define EGL_OPENGL_ES2_BIT 0x0004
#define EGL_OPENGL_BIT 0x0008
#define EGL_ALPHA_SIZE 0x3021
#define EGL_BLUE_SIZE 0x3022
#define EGL_GREEN_SIZE 0x3023
#define EGL_RED_SIZE 0x3024
#define EGL_DEPTH_SIZE 0x3025
#define EGL_STENCIL_SIZE 0x3026
#define EGL_SAMPLES 0x3031
#define EGL_OPENGL_ES_API 0x30a0
#define EGL_OPENGL_API 0x30a2
#define EGL_NONE 0x3038
#define EGL_EXTENSIONS 0x3055
#define EGL_CONTEXT_CLIENT_VERSION 0x3098
#define EGL_NATIVE_VISUAL_ID 0x302e
#define EGL_NO_SURFACE ((EGLSurface) 0)
#define EGL_NO_DISPLAY ((EGLDisplay) 0)
#define EGL_NO_CONTEXT ((EGLContext) 0)
#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType) 0)
#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002
#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001
#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002
#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001
#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31bd
#define EGL_NO_RESET_NOTIFICATION_KHR 0x31be
#define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31bf
#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004
#define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098
#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30fb
#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30fd
#define EGL_CONTEXT_FLAGS_KHR 0x30fc
#define EGL_CONTEXT_OPENGL_NO_ERROR_KHR 0x31b3
#define EGL_GL_COLORSPACE_KHR 0x309d
#define EGL_GL_COLORSPACE_SRGB_KHR 0x3089
#define EGL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x2097
#define EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR 0
#define EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x2098
typedef int EGLint;
typedef unsigned int EGLBoolean;
typedef unsigned int EGLenum;
typedef void* EGLConfig;
typedef void* EGLContext;
typedef void* EGLDisplay;
typedef void* EGLSurface;
// EGL function pointer typedefs
typedef EGLBoolean (EGLAPIENTRY * PFN_eglGetConfigAttrib)(EGLDisplay,EGLConfig,EGLint,EGLint*);
typedef EGLBoolean (EGLAPIENTRY * PFN_eglGetConfigs)(EGLDisplay,EGLConfig*,EGLint,EGLint*);
typedef EGLDisplay (EGLAPIENTRY * PFN_eglGetDisplay)(EGLNativeDisplayType);
typedef EGLint (EGLAPIENTRY * PFN_eglGetError)(void);
typedef EGLBoolean (EGLAPIENTRY * PFN_eglInitialize)(EGLDisplay,EGLint*,EGLint*);
typedef EGLBoolean (EGLAPIENTRY * PFN_eglTerminate)(EGLDisplay);
typedef EGLBoolean (EGLAPIENTRY * PFN_eglBindAPI)(EGLenum);
typedef EGLContext (EGLAPIENTRY * PFN_eglCreateContext)(EGLDisplay,EGLConfig,EGLContext,const EGLint*);
typedef EGLBoolean (EGLAPIENTRY * PFN_eglDestroySurface)(EGLDisplay,EGLSurface);
typedef EGLBoolean (EGLAPIENTRY * PFN_eglDestroyContext)(EGLDisplay,EGLContext);
typedef EGLSurface (EGLAPIENTRY * PFN_eglCreateWindowSurface)(EGLDisplay,EGLConfig,EGLNativeWindowType,const EGLint*);
typedef EGLBoolean (EGLAPIENTRY * PFN_eglMakeCurrent)(EGLDisplay,EGLSurface,EGLSurface,EGLContext);
typedef EGLBoolean (EGLAPIENTRY * PFN_eglSwapBuffers)(EGLDisplay,EGLSurface);
typedef EGLBoolean (EGLAPIENTRY * PFN_eglSwapInterval)(EGLDisplay,EGLint);
typedef const char* (EGLAPIENTRY * PFN_eglQueryString)(EGLDisplay,EGLint);
typedef GLFWglproc (EGLAPIENTRY * PFN_eglGetProcAddress)(const char*);
#define eglGetConfigAttrib _glfw.egl.GetConfigAttrib
#define eglGetConfigs _glfw.egl.GetConfigs
#define eglGetDisplay _glfw.egl.GetDisplay
#define eglGetError _glfw.egl.GetError
#define eglInitialize _glfw.egl.Initialize
#define eglTerminate _glfw.egl.Terminate
#define eglBindAPI _glfw.egl.BindAPI
#define eglCreateContext _glfw.egl.CreateContext
#define eglDestroySurface _glfw.egl.DestroySurface
#define eglDestroyContext _glfw.egl.DestroyContext
#define eglCreateWindowSurface _glfw.egl.CreateWindowSurface
#define eglMakeCurrent _glfw.egl.MakeCurrent
#define eglSwapBuffers _glfw.egl.SwapBuffers
#define eglSwapInterval _glfw.egl.SwapInterval
#define eglQueryString _glfw.egl.QueryString
#define eglGetProcAddress _glfw.egl.GetProcAddress
#define _GLFW_EGL_CONTEXT_STATE _GLFWcontextEGL egl
#define _GLFW_EGL_LIBRARY_CONTEXT_STATE _GLFWlibraryEGL egl
// EGL-specific per-context data
//
typedef struct _GLFWcontextEGL
{
EGLConfig config;
EGLContext handle;
EGLSurface surface;
void* client;
} _GLFWcontextEGL;
// EGL-specific global data
//
typedef struct _GLFWlibraryEGL
{
EGLDisplay display;
EGLint major, minor;
GLFWbool prefix;
GLFWbool KHR_create_context;
GLFWbool KHR_create_context_no_error;
GLFWbool KHR_gl_colorspace;
GLFWbool KHR_get_all_proc_addresses;
GLFWbool KHR_context_flush_control;
void* handle;
PFN_eglGetConfigAttrib GetConfigAttrib;
PFN_eglGetConfigs GetConfigs;
PFN_eglGetDisplay GetDisplay;
PFN_eglGetError GetError;
PFN_eglInitialize Initialize;
PFN_eglTerminate Terminate;
PFN_eglBindAPI BindAPI;
PFN_eglCreateContext CreateContext;
PFN_eglDestroySurface DestroySurface;
PFN_eglDestroyContext DestroyContext;
PFN_eglCreateWindowSurface CreateWindowSurface;
PFN_eglMakeCurrent MakeCurrent;
PFN_eglSwapBuffers SwapBuffers;
PFN_eglSwapInterval SwapInterval;
PFN_eglQueryString QueryString;
PFN_eglGetProcAddress GetProcAddress;
} _GLFWlibraryEGL;
GLFWbool _glfwInitEGL(void);
void _glfwTerminateEGL(void);
GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig);
#if defined(_GLFW_X11)
GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig,
Visual** visual, int* depth);
#endif /*_GLFW_X11*/

283
glfw/glfw.py Executable file
View File

@@ -0,0 +1,283 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
import json
import os
import re
import shutil
import sys
_plat = sys.platform.lower()
is_macos = 'darwin' in _plat
is_freebsd = 'freebsd' in _plat
is_netbsd = 'netbsd' in _plat
is_dragonflybsd = 'dragonfly' in _plat
is_bsd = is_freebsd or is_netbsd or is_dragonflybsd
base = os.path.dirname(os.path.abspath(__file__))
def wayland_protocol_file_name(base, ext='c'):
base = os.path.basename(base).rpartition('.')[0]
return 'wayland-{}-client-protocol.{}'.format(base, ext)
def init_env(env, pkg_config, at_least_version, module='x11'):
ans = env.copy()
ans.cflags = [
x for x in ans.cflags
if x not in '-Wpedantic -Wextra -pedantic-errors'.split()
]
if not is_macos:
ans.cflags.append('-pthread')
ans.ldpaths.append('-pthread')
ans.cflags.append('-fpic')
ans.cflags.append('-D_GLFW_' + module.upper())
ans.cflags.append('-D_GLFW_BUILD_DLL')
if is_macos:
ans.ldpaths.extend(
"-framework Cocoa -framework IOKit -framework CoreFoundation -framework CoreVideo".
split()
)
else:
ans.ldpaths.extend('-lrt -lm -ldl'.split())
sinfo = json.load(open(os.path.join(base, 'source-info.json')))
ans.sources = sinfo['common']['sources'] + sinfo[module]['sources']
ans.all_headers = [x for x in os.listdir(base) if x.endswith('.h')]
if module == 'x11':
for dep in 'x11 xrandr xinerama xcursor xkbcommon xkbcommon-x11'.split():
ans.cflags.extend(pkg_config(dep, '--cflags-only-I'))
ans.ldpaths.extend(pkg_config(dep, '--libs'))
elif module == 'cocoa':
for f in 'Cocoa IOKit CoreFoundation CoreVideo'.split():
ans.ldpaths.extend(('-framework', f))
elif module == 'wayland':
at_least_version('wayland-protocols', *sinfo['wayland_protocols'])
ans.wayland_packagedir = os.path.abspath(pkg_config('wayland-protocols', '--variable=pkgdatadir')[0])
ans.wayland_scanner = os.path.abspath(pkg_config('wayland-scanner', '--variable=wayland_scanner')[0])
ans.wayland_protocols = tuple(sinfo[module]['protocols'])
for p in ans.wayland_protocols:
ans.sources.append(wayland_protocol_file_name(p))
ans.all_headers.append(wayland_protocol_file_name(p, 'h'))
for dep in 'wayland-egl wayland-client wayland-cursor xkbcommon'.split():
ans.cflags.extend(pkg_config(dep, '--cflags-only-I'))
ans.ldpaths.extend(pkg_config(dep, '--libs'))
return ans
def build_wayland_protocols(env, run_tool, emphasis, newer, dest_dir):
for protocol in env.wayland_protocols:
src = os.path.join(env.wayland_packagedir, protocol)
if not os.path.exists(src):
raise SystemExit('The wayland-protocols package on your system is missing the {} protocol definition file'.format(protocol))
for ext in 'hc':
dest = wayland_protocol_file_name(src, ext)
dest = os.path.join(dest_dir, dest)
if newer(dest, src):
q = 'client-header' if ext == 'h' else 'code'
run_tool([env.wayland_scanner, q, src, dest],
desc='Generating {} ...'.format(emphasis(os.path.basename(dest))))
def collect_source_information():
raw = open('src/CMakeLists.txt').read()
mraw = open('CMakeLists.txt').read()
def extract_sources(group, start_pos=0):
for which in 'HEADERS SOURCES'.split():
yield which.lower(), filter(
lambda x: x[0] not in '"$',
re.search(
r'{0}_{1}\s+([^)]+?)[)]'.format(group, which),
raw[start_pos:]
).group(1).strip().split()
)
wayland_protocols = re.search('WaylandProtocols\s+(\S+)\s+', mraw).group(1)
wayland_protocols = list(map(int, wayland_protocols.split('.')))
ans = {
'common': dict(extract_sources('common')),
'wayland_protocols': wayland_protocols,
}
joystick = 'null' if is_bsd else 'linux'
for group in 'cocoa win32 x11 wayland osmesa'.split():
m = re.search('_GLFW_' + group.upper(), raw)
ans[group] = dict(extract_sources('glfw', m.start()))
if group in ('x11', 'wayland'):
ans[group]['headers'].append('{}_joystick.h'.format(joystick))
ans[group]['sources'].append('{}_joystick.c'.format(joystick))
if group == 'wayland':
ans[group]['protocols'] = p = []
for m in re.finditer(r'WAYLAND_PROTOCOLS_PKGDATADIR\}/(.+?)"?$', raw, flags=re.M):
p.append(m.group(1))
return ans
def patch_in_file(path, pfunc):
with open(path, 'r+') as f:
raw = f.read()
nraw = pfunc(raw)
if raw == nraw:
raise SystemExit('Patching of {} failed'.format(path))
f.seek(0), f.truncate()
f.write(nraw)
class Arg:
def __init__(self, decl):
self.type, self.name = decl.rsplit(' ', 1)
self.type = self.type.strip()
self.name = self.name.strip()
while self.name.startswith('*'):
self.name = self.name[1:]
self.type = self.type + '*'
def __repr__(self):
return 'Arg({}, {})'.format(self.type, self.name)
class Function:
def __init__(self, declaration, check_fail=True):
self.check_fail = check_fail
m = re.match(
r'(.+?)\s+(glfw[A-Z][a-zA-Z0-9]+)[(](.+)[)]$', declaration
)
if m is None:
raise SystemExit('Failed to parse ' + repr(declaration))
self.restype = m.group(1).strip()
self.name = m.group(2)
args = m.group(3).strip().split(',')
args = [x.strip() for x in args]
self.args = []
for a in args:
if a == 'void':
continue
self.args.append(Arg(a))
def declaration(self):
return 'typedef {restype} (*{name}_func)({args});\n{name}_func {name}_impl;\n#define {name} {name}_impl'.format(
restype=self.restype,
name=self.name,
args=', '.join(a.type for a in self.args)
)
def load(self):
ans = '*(void **) (&{name}_impl) = dlsym(handle, "{name}");'.format(
name=self.name
)
if self.check_fail:
ans += '\n if ({name}_impl == NULL) fail("Failed to load glfw function {name} with error: %s", dlerror());'.format(
name=self.name
)
return ans
def generate_wrappers(glfw_header, glfw_native_header):
src = open(glfw_header).read()
functions = []
first = None
for m in re.finditer(r'^GLFWAPI\s+(.+[)]);\s*$', src, flags=re.MULTILINE):
if first is None:
first = m.start()
decl = m.group(1)
if 'VkInstance' in decl:
continue
functions.append(Function(decl))
for line in '''\
void* glfwGetCocoaWindow(GLFWwindow* window)
uint32_t glfwGetCocoaMonitor(GLFWmonitor* monitor)
void* glfwGetX11Display(void)
int32_t glfwGetX11Window(GLFWwindow* window)
void glfwSetX11SelectionString(const char* string)
const char* glfwGetX11SelectionString(void)
'''.splitlines():
if line:
functions.append(Function(line.strip(), check_fail=False))
declarations = [f.declaration() for f in functions]
p = src.find(' * GLFW API tokens')
p = src.find('*/', p)
preamble = src[p + 2:first]
header = '''\
#pragma once
#include <stddef.h>
#include <stdint.h>
{}
{}
const char* load_glfw(const char* path);
'''.format(preamble, '\n\n'.join(declarations))
with open('../kitty/glfw-wrapper.h', 'w') as f:
f.write(header)
code = '''
#include <dlfcn.h>
#include "data-types.h"
#include "glfw-wrapper.h"
static void* handle = NULL;
#define fail(msg, ...) { snprintf(buf, sizeof(buf), msg, __VA_ARGS__); return buf; }
const char*
load_glfw(const char* path) {
static char buf[2048];
handle = dlopen(path, RTLD_LAZY);
if (handle == NULL) fail("Failed to dlopen %s with error: %s", path, dlerror());
dlerror();
LOAD
return NULL;
}
void
unload_glfw() {
if (handle) { dlclose(handle); handle = NULL; }
}
'''.replace('LOAD', '\n\n '.join(f.load() for f in functions))
with open('../kitty/glfw-wrapper.c', 'w') as f:
f.write(code)
def main():
os.chdir(sys.argv[-1])
sinfo = collect_source_information()
files_to_copy = set()
for x in sinfo.values():
if isinstance(x, dict):
headers, sources = x['headers'], x['sources']
for name in headers + sources:
files_to_copy.add(os.path.abspath(os.path.join('src', name)))
glfw_header = os.path.abspath('include/GLFW/glfw3.h')
glfw_native_header = os.path.abspath('include/GLFW/glfw3native.h')
os.chdir(base)
for x in os.listdir('.'):
if x.rpartition('.') in ('c', 'h'):
os.unlink(x)
for src in files_to_copy:
shutil.copy2(src, '.')
shutil.copy2(glfw_header, '.')
patch_in_file('internal.h', lambda x: x.replace('../include/GLFW/', ''))
patch_in_file('cocoa_window.m', lambda x: re.sub(
r'[(]void[)]loadMainMenu.+?}', '(void)loadMainMenu\n{ // removed by Kovid as it generated compiler warnings \n}\n', x, flags=re.DOTALL))
json.dump(
sinfo,
open('source-info.json', 'w'),
indent=2,
ensure_ascii=False,
sort_keys=True
)
generate_wrappers(glfw_header, glfw_native_header)
if __name__ == '__main__':
main()

5544
glfw/glfw3.h vendored Normal file

File diff suppressed because it is too large Load Diff

698
glfw/glx_context.c vendored Normal file
View File

@@ -0,0 +1,698 @@
//========================================================================
// GLFW 3.3 GLX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#ifndef GLXBadProfileARB
#define GLXBadProfileARB 13
#endif
// Returns the specified attribute of the specified GLXFBConfig
//
static int getGLXFBConfigAttrib(GLXFBConfig fbconfig, int attrib)
{
int value;
glXGetFBConfigAttrib(_glfw.x11.display, fbconfig, attrib, &value);
return value;
}
// Return the GLXFBConfig most closely matching the specified hints
//
static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired,
GLXFBConfig* result)
{
GLXFBConfig* nativeConfigs;
_GLFWfbconfig* usableConfigs;
const _GLFWfbconfig* closest;
int i, nativeCount, usableCount;
const char* vendor;
GLFWbool trustWindowBit = GLFW_TRUE;
// HACK: This is a (hopefully temporary) workaround for Chromium
// (VirtualBox GL) not setting the window bit on any GLXFBConfigs
vendor = glXGetClientString(_glfw.x11.display, GLX_VENDOR);
if (vendor && strcmp(vendor, "Chromium") == 0)
trustWindowBit = GLFW_FALSE;
nativeConfigs =
glXGetFBConfigs(_glfw.x11.display, _glfw.x11.screen, &nativeCount);
if (!nativeConfigs || !nativeCount)
{
_glfwInputError(GLFW_API_UNAVAILABLE, "GLX: No GLXFBConfigs returned");
return GLFW_FALSE;
}
usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig));
usableCount = 0;
for (i = 0; i < nativeCount; i++)
{
const GLXFBConfig n = nativeConfigs[i];
_GLFWfbconfig* u = usableConfigs + usableCount;
// Only consider RGBA GLXFBConfigs
if (!(getGLXFBConfigAttrib(n, GLX_RENDER_TYPE) & GLX_RGBA_BIT))
continue;
// Only consider window GLXFBConfigs
if (!(getGLXFBConfigAttrib(n, GLX_DRAWABLE_TYPE) & GLX_WINDOW_BIT))
{
if (trustWindowBit)
continue;
}
if (desired->transparent)
{
XVisualInfo* vi = glXGetVisualFromFBConfig(_glfw.x11.display, n);
if (vi)
{
u->transparent = _glfwIsVisualTransparentX11(vi->visual);
XFree(vi);
}
}
u->redBits = getGLXFBConfigAttrib(n, GLX_RED_SIZE);
u->greenBits = getGLXFBConfigAttrib(n, GLX_GREEN_SIZE);
u->blueBits = getGLXFBConfigAttrib(n, GLX_BLUE_SIZE);
u->alphaBits = getGLXFBConfigAttrib(n, GLX_ALPHA_SIZE);
u->depthBits = getGLXFBConfigAttrib(n, GLX_DEPTH_SIZE);
u->stencilBits = getGLXFBConfigAttrib(n, GLX_STENCIL_SIZE);
u->accumRedBits = getGLXFBConfigAttrib(n, GLX_ACCUM_RED_SIZE);
u->accumGreenBits = getGLXFBConfigAttrib(n, GLX_ACCUM_GREEN_SIZE);
u->accumBlueBits = getGLXFBConfigAttrib(n, GLX_ACCUM_BLUE_SIZE);
u->accumAlphaBits = getGLXFBConfigAttrib(n, GLX_ACCUM_ALPHA_SIZE);
u->auxBuffers = getGLXFBConfigAttrib(n, GLX_AUX_BUFFERS);
if (getGLXFBConfigAttrib(n, GLX_STEREO))
u->stereo = GLFW_TRUE;
if (getGLXFBConfigAttrib(n, GLX_DOUBLEBUFFER))
u->doublebuffer = GLFW_TRUE;
if (_glfw.glx.ARB_multisample)
u->samples = getGLXFBConfigAttrib(n, GLX_SAMPLES);
if (_glfw.glx.ARB_framebuffer_sRGB || _glfw.glx.EXT_framebuffer_sRGB)
u->sRGB = getGLXFBConfigAttrib(n, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB);
u->handle = (uintptr_t) n;
usableCount++;
}
closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);
if (closest)
*result = (GLXFBConfig) closest->handle;
XFree(nativeConfigs);
free(usableConfigs);
return closest != NULL;
}
// Create the OpenGL context using legacy API
//
static GLXContext createLegacyContextGLX(_GLFWwindow* window,
GLXFBConfig fbconfig,
GLXContext share)
{
return glXCreateNewContext(_glfw.x11.display,
fbconfig,
GLX_RGBA_TYPE,
share,
True);
}
static void makeContextCurrentGLX(_GLFWwindow* window)
{
if (window)
{
if (!glXMakeCurrent(_glfw.x11.display,
window->context.glx.window,
window->context.glx.handle))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"GLX: Failed to make context current");
return;
}
}
else
{
if (!glXMakeCurrent(_glfw.x11.display, None, NULL))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"GLX: Failed to clear current context");
return;
}
}
_glfwPlatformSetTls(&_glfw.contextSlot, window);
}
static void swapBuffersGLX(_GLFWwindow* window)
{
glXSwapBuffers(_glfw.x11.display, window->context.glx.window);
}
static void swapIntervalGLX(int interval)
{
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
if (_glfw.glx.EXT_swap_control)
{
_glfw.glx.SwapIntervalEXT(_glfw.x11.display,
window->context.glx.window,
interval);
}
else if (_glfw.glx.MESA_swap_control)
_glfw.glx.SwapIntervalMESA(interval);
else if (_glfw.glx.SGI_swap_control)
{
if (interval > 0)
_glfw.glx.SwapIntervalSGI(interval);
}
}
static int extensionSupportedGLX(const char* extension)
{
const char* extensions =
glXQueryExtensionsString(_glfw.x11.display, _glfw.x11.screen);
if (extensions)
{
if (_glfwStringInExtensionString(extension, extensions))
return GLFW_TRUE;
}
return GLFW_FALSE;
}
static GLFWglproc getProcAddressGLX(const char* procname)
{
if (_glfw.glx.GetProcAddress)
return _glfw.glx.GetProcAddress((const GLubyte*) procname);
else if (_glfw.glx.GetProcAddressARB)
return _glfw.glx.GetProcAddressARB((const GLubyte*) procname);
else
return _glfw_dlsym(_glfw.glx.handle, procname);
}
// Destroy the OpenGL context
//
static void destroyContextGLX(_GLFWwindow* window)
{
if (window->context.glx.window)
{
glXDestroyWindow(_glfw.x11.display, window->context.glx.window);
window->context.glx.window = None;
}
if (window->context.glx.handle)
{
glXDestroyContext(_glfw.x11.display, window->context.glx.handle);
window->context.glx.handle = NULL;
}
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
// Initialize GLX
//
GLFWbool _glfwInitGLX(void)
{
int i;
const char* sonames[] =
{
#if defined(_GLFW_GLX_LIBRARY)
_GLFW_GLX_LIBRARY,
#elif defined(__CYGWIN__)
"libGL-1.so",
#else
"libGL.so.1",
"libGL.so",
#endif
NULL
};
if (_glfw.glx.handle)
return GLFW_TRUE;
for (i = 0; sonames[i]; i++)
{
_glfw.glx.handle = _glfw_dlopen(sonames[i]);
if (_glfw.glx.handle)
break;
}
if (!_glfw.glx.handle)
{
_glfwInputError(GLFW_API_UNAVAILABLE, "GLX: Failed to load GLX");
return GLFW_FALSE;
}
_glfw.glx.GetFBConfigs =
_glfw_dlsym(_glfw.glx.handle, "glXGetFBConfigs");
_glfw.glx.GetFBConfigAttrib =
_glfw_dlsym(_glfw.glx.handle, "glXGetFBConfigAttrib");
_glfw.glx.GetClientString =
_glfw_dlsym(_glfw.glx.handle, "glXGetClientString");
_glfw.glx.QueryExtension =
_glfw_dlsym(_glfw.glx.handle, "glXQueryExtension");
_glfw.glx.QueryVersion =
_glfw_dlsym(_glfw.glx.handle, "glXQueryVersion");
_glfw.glx.DestroyContext =
_glfw_dlsym(_glfw.glx.handle, "glXDestroyContext");
_glfw.glx.MakeCurrent =
_glfw_dlsym(_glfw.glx.handle, "glXMakeCurrent");
_glfw.glx.SwapBuffers =
_glfw_dlsym(_glfw.glx.handle, "glXSwapBuffers");
_glfw.glx.QueryExtensionsString =
_glfw_dlsym(_glfw.glx.handle, "glXQueryExtensionsString");
_glfw.glx.CreateNewContext =
_glfw_dlsym(_glfw.glx.handle, "glXCreateNewContext");
_glfw.glx.CreateWindow =
_glfw_dlsym(_glfw.glx.handle, "glXCreateWindow");
_glfw.glx.DestroyWindow =
_glfw_dlsym(_glfw.glx.handle, "glXDestroyWindow");
_glfw.glx.GetProcAddress =
_glfw_dlsym(_glfw.glx.handle, "glXGetProcAddress");
_glfw.glx.GetProcAddressARB =
_glfw_dlsym(_glfw.glx.handle, "glXGetProcAddressARB");
_glfw.glx.GetVisualFromFBConfig =
_glfw_dlsym(_glfw.glx.handle, "glXGetVisualFromFBConfig");
if (!_glfw.glx.GetFBConfigs ||
!_glfw.glx.GetFBConfigAttrib ||
!_glfw.glx.GetClientString ||
!_glfw.glx.QueryExtension ||
!_glfw.glx.QueryVersion ||
!_glfw.glx.DestroyContext ||
!_glfw.glx.MakeCurrent ||
!_glfw.glx.SwapBuffers ||
!_glfw.glx.QueryExtensionsString ||
!_glfw.glx.CreateNewContext ||
!_glfw.glx.CreateWindow ||
!_glfw.glx.DestroyWindow ||
!_glfw.glx.GetProcAddress ||
!_glfw.glx.GetProcAddressARB ||
!_glfw.glx.GetVisualFromFBConfig)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"GLX: Failed to load required entry points");
return GLFW_FALSE;
}
if (!glXQueryExtension(_glfw.x11.display,
&_glfw.glx.errorBase,
&_glfw.glx.eventBase))
{
_glfwInputError(GLFW_API_UNAVAILABLE, "GLX: GLX extension not found");
return GLFW_FALSE;
}
if (!glXQueryVersion(_glfw.x11.display, &_glfw.glx.major, &_glfw.glx.minor))
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"GLX: Failed to query GLX version");
return GLFW_FALSE;
}
if (_glfw.glx.major == 1 && _glfw.glx.minor < 3)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"GLX: GLX version 1.3 is required");
return GLFW_FALSE;
}
if (extensionSupportedGLX("GLX_EXT_swap_control"))
{
_glfw.glx.SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)
getProcAddressGLX("glXSwapIntervalEXT");
if (_glfw.glx.SwapIntervalEXT)
_glfw.glx.EXT_swap_control = GLFW_TRUE;
}
if (extensionSupportedGLX("GLX_SGI_swap_control"))
{
_glfw.glx.SwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)
getProcAddressGLX("glXSwapIntervalSGI");
if (_glfw.glx.SwapIntervalSGI)
_glfw.glx.SGI_swap_control = GLFW_TRUE;
}
if (extensionSupportedGLX("GLX_MESA_swap_control"))
{
_glfw.glx.SwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC)
getProcAddressGLX("glXSwapIntervalMESA");
if (_glfw.glx.SwapIntervalMESA)
_glfw.glx.MESA_swap_control = GLFW_TRUE;
}
if (extensionSupportedGLX("GLX_ARB_multisample"))
_glfw.glx.ARB_multisample = GLFW_TRUE;
if (extensionSupportedGLX("GLX_ARB_framebuffer_sRGB"))
_glfw.glx.ARB_framebuffer_sRGB = GLFW_TRUE;
if (extensionSupportedGLX("GLX_EXT_framebuffer_sRGB"))
_glfw.glx.EXT_framebuffer_sRGB = GLFW_TRUE;
if (extensionSupportedGLX("GLX_ARB_create_context"))
{
_glfw.glx.CreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)
getProcAddressGLX("glXCreateContextAttribsARB");
if (_glfw.glx.CreateContextAttribsARB)
_glfw.glx.ARB_create_context = GLFW_TRUE;
}
if (extensionSupportedGLX("GLX_ARB_create_context_robustness"))
_glfw.glx.ARB_create_context_robustness = GLFW_TRUE;
if (extensionSupportedGLX("GLX_ARB_create_context_profile"))
_glfw.glx.ARB_create_context_profile = GLFW_TRUE;
if (extensionSupportedGLX("GLX_EXT_create_context_es2_profile"))
_glfw.glx.EXT_create_context_es2_profile = GLFW_TRUE;
if (extensionSupportedGLX("GLX_ARB_create_context_no_error"))
_glfw.glx.ARB_create_context_no_error = GLFW_TRUE;
if (extensionSupportedGLX("GLX_ARB_context_flush_control"))
_glfw.glx.ARB_context_flush_control = GLFW_TRUE;
return GLFW_TRUE;
}
// Terminate GLX
//
void _glfwTerminateGLX(void)
{
// NOTE: This function must not call any X11 functions, as it is called
// after XCloseDisplay (see _glfwPlatformTerminate for details)
if (_glfw.glx.handle)
{
_glfw_dlclose(_glfw.glx.handle);
_glfw.glx.handle = NULL;
}
}
#define setAttrib(a, v) \
{ \
assert((size_t) (index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
attribs[index++] = a; \
attribs[index++] = v; \
}
// Create the OpenGL or OpenGL ES context
//
GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
int attribs[40];
GLXFBConfig native = NULL;
GLXContext share = NULL;
if (ctxconfig->share)
share = ctxconfig->share->context.glx.handle;
if (!chooseGLXFBConfig(fbconfig, &native))
{
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
"GLX: Failed to find a suitable GLXFBConfig");
return GLFW_FALSE;
}
if (ctxconfig->client == GLFW_OPENGL_ES_API)
{
if (!_glfw.glx.ARB_create_context ||
!_glfw.glx.ARB_create_context_profile ||
!_glfw.glx.EXT_create_context_es2_profile)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"GLX: OpenGL ES requested but GLX_EXT_create_context_es2_profile is unavailable");
return GLFW_FALSE;
}
}
if (ctxconfig->forward)
{
if (!_glfw.glx.ARB_create_context)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"GLX: Forward compatibility requested but GLX_ARB_create_context_profile is unavailable");
return GLFW_FALSE;
}
}
if (ctxconfig->profile)
{
if (!_glfw.glx.ARB_create_context ||
!_glfw.glx.ARB_create_context_profile)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"GLX: An OpenGL profile requested but GLX_ARB_create_context_profile is unavailable");
return GLFW_FALSE;
}
}
_glfwGrabErrorHandlerX11();
if (_glfw.glx.ARB_create_context)
{
int index = 0, mask = 0, flags = 0;
if (ctxconfig->client == GLFW_OPENGL_API)
{
if (ctxconfig->forward)
flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
mask |= GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
}
else
mask |= GLX_CONTEXT_ES2_PROFILE_BIT_EXT;
if (ctxconfig->debug)
flags |= GLX_CONTEXT_DEBUG_BIT_ARB;
if (ctxconfig->robustness)
{
if (_glfw.glx.ARB_create_context_robustness)
{
if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
{
setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
GLX_NO_RESET_NOTIFICATION_ARB);
}
else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
{
setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
GLX_LOSE_CONTEXT_ON_RESET_ARB);
}
flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB;
}
}
if (ctxconfig->release)
{
if (_glfw.glx.ARB_context_flush_control)
{
if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE)
{
setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB,
GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB);
}
else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH)
{
setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB,
GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB);
}
}
}
if (ctxconfig->noerror)
{
if (_glfw.glx.ARB_create_context_no_error)
setAttrib(GLX_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE);
}
// NOTE: Only request an explicitly versioned context when necessary, as
// explicitly requesting version 1.0 does not always return the
// highest version supported by the driver
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
{
setAttrib(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major);
setAttrib(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor);
}
if (mask)
setAttrib(GLX_CONTEXT_PROFILE_MASK_ARB, mask);
if (flags)
setAttrib(GLX_CONTEXT_FLAGS_ARB, flags);
setAttrib(None, None);
window->context.glx.handle =
_glfw.glx.CreateContextAttribsARB(_glfw.x11.display,
native,
share,
True,
attribs);
// HACK: This is a fallback for broken versions of the Mesa
// implementation of GLX_ARB_create_context_profile that fail
// default 1.0 context creation with a GLXBadProfileARB error in
// violation of the extension spec
if (!window->context.glx.handle)
{
if (_glfw.x11.errorCode == _glfw.glx.errorBase + GLXBadProfileARB &&
ctxconfig->client == GLFW_OPENGL_API &&
ctxconfig->profile == GLFW_OPENGL_ANY_PROFILE &&
ctxconfig->forward == GLFW_FALSE)
{
window->context.glx.handle =
createLegacyContextGLX(window, native, share);
}
}
}
else
{
window->context.glx.handle =
createLegacyContextGLX(window, native, share);
}
_glfwReleaseErrorHandlerX11();
if (!window->context.glx.handle)
{
_glfwInputErrorX11(GLFW_VERSION_UNAVAILABLE, "GLX: Failed to create context");
return GLFW_FALSE;
}
window->context.glx.window =
glXCreateWindow(_glfw.x11.display, native, window->x11.handle, NULL);
if (!window->context.glx.window)
{
_glfwInputError(GLFW_PLATFORM_ERROR, "GLX: Failed to create window");
return GLFW_FALSE;
}
window->context.makeCurrent = makeContextCurrentGLX;
window->context.swapBuffers = swapBuffersGLX;
window->context.swapInterval = swapIntervalGLX;
window->context.extensionSupported = extensionSupportedGLX;
window->context.getProcAddress = getProcAddressGLX;
window->context.destroy = destroyContextGLX;
return GLFW_TRUE;
}
#undef setAttrib
// Returns the Visual and depth of the chosen GLXFBConfig
//
GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig,
Visual** visual, int* depth)
{
GLXFBConfig native;
XVisualInfo* result;
if (!chooseGLXFBConfig(fbconfig, &native))
{
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
"GLX: Failed to find a suitable GLXFBConfig");
return GLFW_FALSE;
}
result = glXGetVisualFromFBConfig(_glfw.x11.display, native);
if (!result)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"GLX: Failed to retrieve Visual for GLXFBConfig");
return GLFW_FALSE;
}
*visual = result->visual;
*depth = result->depth;
XFree(result);
return GLFW_TRUE;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////
//////////////////////////////////////////////////////////////////////////
GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* handle)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (window->context.client == GLFW_NO_API)
{
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
return NULL;
}
return window->context.glx.handle;
}
GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* handle)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
_GLFW_REQUIRE_INIT_OR_RETURN(None);
if (window->context.client == GLFW_NO_API)
{
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
return None;
}
return window->context.glx.window;
}

181
glfw/glx_context.h vendored Normal file
View File

@@ -0,0 +1,181 @@
//========================================================================
// GLFW 3.3 GLX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#define GLX_VENDOR 1
#define GLX_RGBA_BIT 0x00000001
#define GLX_WINDOW_BIT 0x00000001
#define GLX_DRAWABLE_TYPE 0x8010
#define GLX_RENDER_TYPE 0x8011
#define GLX_RGBA_TYPE 0x8014
#define GLX_DOUBLEBUFFER 5
#define GLX_STEREO 6
#define GLX_AUX_BUFFERS 7
#define GLX_RED_SIZE 8
#define GLX_GREEN_SIZE 9
#define GLX_BLUE_SIZE 10
#define GLX_ALPHA_SIZE 11
#define GLX_DEPTH_SIZE 12
#define GLX_STENCIL_SIZE 13
#define GLX_ACCUM_RED_SIZE 14
#define GLX_ACCUM_GREEN_SIZE 15
#define GLX_ACCUM_BLUE_SIZE 16
#define GLX_ACCUM_ALPHA_SIZE 17
#define GLX_SAMPLES 0x186a1
#define GLX_VISUAL_ID 0x800b
#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20b2
#define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001
#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126
#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
#define GLX_CONTEXT_FLAGS_ARB 0x2094
#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
#define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252
#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
#define GLX_NO_RESET_NOTIFICATION_ARB 0x8261
#define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
#define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0
#define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
#define GLX_CONTEXT_OPENGL_NO_ERROR_ARB 0x31b3
typedef XID GLXWindow;
typedef XID GLXDrawable;
typedef struct __GLXFBConfig* GLXFBConfig;
typedef struct __GLXcontext* GLXContext;
typedef void (*__GLXextproc)(void);
typedef int (*PFNGLXGETFBCONFIGATTRIBPROC)(Display*,GLXFBConfig,int,int*);
typedef const char* (*PFNGLXGETCLIENTSTRINGPROC)(Display*,int);
typedef Bool (*PFNGLXQUERYEXTENSIONPROC)(Display*,int*,int*);
typedef Bool (*PFNGLXQUERYVERSIONPROC)(Display*,int*,int*);
typedef void (*PFNGLXDESTROYCONTEXTPROC)(Display*,GLXContext);
typedef Bool (*PFNGLXMAKECURRENTPROC)(Display*,GLXDrawable,GLXContext);
typedef void (*PFNGLXSWAPBUFFERSPROC)(Display*,GLXDrawable);
typedef const char* (*PFNGLXQUERYEXTENSIONSSTRINGPROC)(Display*,int);
typedef GLXFBConfig* (*PFNGLXGETFBCONFIGSPROC)(Display*,int,int*);
typedef GLXContext (*PFNGLXCREATENEWCONTEXTPROC)(Display*,GLXFBConfig,int,GLXContext,Bool);
typedef __GLXextproc (* PFNGLXGETPROCADDRESSPROC)(const GLubyte *procName);
typedef void (*PFNGLXSWAPINTERVALEXTPROC)(Display*,GLXDrawable,int);
typedef XVisualInfo* (*PFNGLXGETVISUALFROMFBCONFIGPROC)(Display*,GLXFBConfig);
typedef GLXWindow (*PFNGLXCREATEWINDOWPROC)(Display*,GLXFBConfig,Window,const int*);
typedef void (*PFNGLXDESTROYWINDOWPROC)(Display*,GLXWindow);
typedef int (*PFNGLXSWAPINTERVALMESAPROC)(int);
typedef int (*PFNGLXSWAPINTERVALSGIPROC)(int);
typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSARBPROC)(Display*,GLXFBConfig,GLXContext,Bool,const int*);
// libGL.so function pointer typedefs
#define glXGetFBConfigs _glfw.glx.GetFBConfigs
#define glXGetFBConfigAttrib _glfw.glx.GetFBConfigAttrib
#define glXGetClientString _glfw.glx.GetClientString
#define glXQueryExtension _glfw.glx.QueryExtension
#define glXQueryVersion _glfw.glx.QueryVersion
#define glXDestroyContext _glfw.glx.DestroyContext
#define glXMakeCurrent _glfw.glx.MakeCurrent
#define glXSwapBuffers _glfw.glx.SwapBuffers
#define glXQueryExtensionsString _glfw.glx.QueryExtensionsString
#define glXCreateNewContext _glfw.glx.CreateNewContext
#define glXGetVisualFromFBConfig _glfw.glx.GetVisualFromFBConfig
#define glXCreateWindow _glfw.glx.CreateWindow
#define glXDestroyWindow _glfw.glx.DestroyWindow
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextGLX glx
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryGLX glx
// GLX-specific per-context data
//
typedef struct _GLFWcontextGLX
{
GLXContext handle;
GLXWindow window;
} _GLFWcontextGLX;
// GLX-specific global data
//
typedef struct _GLFWlibraryGLX
{
int major, minor;
int eventBase;
int errorBase;
// dlopen handle for libGL.so.1
void* handle;
// GLX 1.3 functions
PFNGLXGETFBCONFIGSPROC GetFBConfigs;
PFNGLXGETFBCONFIGATTRIBPROC GetFBConfigAttrib;
PFNGLXGETCLIENTSTRINGPROC GetClientString;
PFNGLXQUERYEXTENSIONPROC QueryExtension;
PFNGLXQUERYVERSIONPROC QueryVersion;
PFNGLXDESTROYCONTEXTPROC DestroyContext;
PFNGLXMAKECURRENTPROC MakeCurrent;
PFNGLXSWAPBUFFERSPROC SwapBuffers;
PFNGLXQUERYEXTENSIONSSTRINGPROC QueryExtensionsString;
PFNGLXCREATENEWCONTEXTPROC CreateNewContext;
PFNGLXGETVISUALFROMFBCONFIGPROC GetVisualFromFBConfig;
PFNGLXCREATEWINDOWPROC CreateWindow;
PFNGLXDESTROYWINDOWPROC DestroyWindow;
// GLX 1.4 and extension functions
PFNGLXGETPROCADDRESSPROC GetProcAddress;
PFNGLXGETPROCADDRESSPROC GetProcAddressARB;
PFNGLXSWAPINTERVALSGIPROC SwapIntervalSGI;
PFNGLXSWAPINTERVALEXTPROC SwapIntervalEXT;
PFNGLXSWAPINTERVALMESAPROC SwapIntervalMESA;
PFNGLXCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB;
GLFWbool SGI_swap_control;
GLFWbool EXT_swap_control;
GLFWbool MESA_swap_control;
GLFWbool ARB_multisample;
GLFWbool ARB_framebuffer_sRGB;
GLFWbool EXT_framebuffer_sRGB;
GLFWbool ARB_create_context;
GLFWbool ARB_create_context_profile;
GLFWbool ARB_create_context_robustness;
GLFWbool EXT_create_context_es2_profile;
GLFWbool ARB_create_context_no_error;
GLFWbool ARB_context_flush_control;
} _GLFWlibraryGLX;
GLFWbool _glfwInitGLX(void);
void _glfwTerminateGLX(void);
GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig);
void _glfwDestroyContextGLX(_GLFWwindow* window);
GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig,
Visual** visual, int* depth);

322
glfw/init.c vendored Normal file
View File

@@ -0,0 +1,322 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include "mappings.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
// The global variables below comprise all mutable global data in GLFW
//
// Any other global variable is a bug
// Global state shared between compilation units of GLFW
//
_GLFWlibrary _glfw = { GLFW_FALSE };
// These are outside of _glfw so they can be used before initialization and
// after termination
//
static _GLFWerror _glfwMainThreadError;
static GLFWerrorfun _glfwErrorCallback;
static _GLFWinitconfig _glfwInitHints =
{
GLFW_TRUE, // hat buttons
{
GLFW_TRUE, // macOS menu bar
GLFW_TRUE // macOS bundle chdir
}
};
// Returns a generic string representation of the specified error
//
static const char* getErrorString(int code)
{
switch (code)
{
case GLFW_NOT_INITIALIZED:
return "The GLFW library is not initialized";
case GLFW_NO_CURRENT_CONTEXT:
return "There is no current context";
case GLFW_INVALID_ENUM:
return "Invalid argument for enum parameter";
case GLFW_INVALID_VALUE:
return "Invalid value for parameter";
case GLFW_OUT_OF_MEMORY:
return "Out of memory";
case GLFW_API_UNAVAILABLE:
return "The requested API is unavailable";
case GLFW_VERSION_UNAVAILABLE:
return "The requested API version is unavailable";
case GLFW_PLATFORM_ERROR:
return "An undocumented platform-specific error occurred";
case GLFW_FORMAT_UNAVAILABLE:
return "The requested format is unavailable";
case GLFW_NO_WINDOW_CONTEXT:
return "The specified window has no context";
default:
return "ERROR: UNKNOWN GLFW ERROR";
}
}
// Terminate the library
//
static void terminate(void)
{
int i;
memset(&_glfw.callbacks, 0, sizeof(_glfw.callbacks));
while (_glfw.windowListHead)
glfwDestroyWindow((GLFWwindow*) _glfw.windowListHead);
while (_glfw.cursorListHead)
glfwDestroyCursor((GLFWcursor*) _glfw.cursorListHead);
for (i = 0; i < _glfw.monitorCount; i++)
{
_GLFWmonitor* monitor = _glfw.monitors[i];
if (monitor->originalRamp.size)
_glfwPlatformSetGammaRamp(monitor, &monitor->originalRamp);
_glfwFreeMonitor(monitor);
}
free(_glfw.monitors);
_glfw.monitors = NULL;
_glfw.monitorCount = 0;
free(_glfw.mappings);
_glfw.mappings = NULL;
_glfw.mappingCount = 0;
_glfwTerminateVulkan();
_glfwPlatformTerminate();
_glfw.initialized = GLFW_FALSE;
while (_glfw.errorListHead)
{
_GLFWerror* error = _glfw.errorListHead;
_glfw.errorListHead = error->next;
free(error);
}
_glfwPlatformDestroyTls(&_glfw.contextSlot);
_glfwPlatformDestroyTls(&_glfw.errorSlot);
_glfwPlatformDestroyMutex(&_glfw.errorLock);
memset(&_glfw, 0, sizeof(_glfw));
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
char* _glfw_strdup(const char* source)
{
const size_t length = strlen(source);
char* result = calloc(length + 1, 1);
strcpy(result, source);
return result;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW event API //////
//////////////////////////////////////////////////////////////////////////
// Notifies shared code of an error
//
void _glfwInputError(int code, const char* format, ...)
{
_GLFWerror* error;
char description[_GLFW_MESSAGE_SIZE];
if (format)
{
va_list vl;
va_start(vl, format);
vsnprintf(description, sizeof(description), format, vl);
va_end(vl);
description[sizeof(description) - 1] = '\0';
}
else
strcpy(description, getErrorString(code));
if (_glfw.initialized)
{
error = _glfwPlatformGetTls(&_glfw.errorSlot);
if (!error)
{
error = calloc(1, sizeof(_GLFWerror));
_glfwPlatformSetTls(&_glfw.errorSlot, error);
_glfwPlatformLockMutex(&_glfw.errorLock);
error->next = _glfw.errorListHead;
_glfw.errorListHead = error;
_glfwPlatformUnlockMutex(&_glfw.errorLock);
}
}
else
error = &_glfwMainThreadError;
error->code = code;
strcpy(error->description, description);
if (_glfwErrorCallback)
_glfwErrorCallback(code, description);
}
//////////////////////////////////////////////////////////////////////////
////// GLFW public API //////
//////////////////////////////////////////////////////////////////////////
GLFWAPI int glfwInit(void)
{
if (_glfw.initialized)
return GLFW_TRUE;
memset(&_glfw, 0, sizeof(_glfw));
_glfw.hints.init = _glfwInitHints;
if (!_glfwPlatformInit())
{
terminate();
return GLFW_FALSE;
}
if (!_glfwPlatformCreateMutex(&_glfw.errorLock) ||
!_glfwPlatformCreateTls(&_glfw.errorSlot) ||
!_glfwPlatformCreateTls(&_glfw.contextSlot))
{
terminate();
return GLFW_FALSE;
}
_glfwPlatformSetTls(&_glfw.errorSlot, &_glfwMainThreadError);
_glfw.initialized = GLFW_TRUE;
_glfw.timer.offset = _glfwPlatformGetTimerValue();
glfwDefaultWindowHints();
{
int i;
for (i = 0; _glfwDefaultMappings[i]; i++)
{
if (!glfwUpdateGamepadMappings(_glfwDefaultMappings[i]))
{
terminate();
return GLFW_FALSE;
}
}
}
return GLFW_TRUE;
}
GLFWAPI void glfwTerminate(void)
{
if (!_glfw.initialized)
return;
terminate();
}
GLFWAPI void glfwInitHint(int hint, int value)
{
switch (hint)
{
case GLFW_JOYSTICK_HAT_BUTTONS:
_glfwInitHints.hatButtons = value;
return;
case GLFW_COCOA_CHDIR_RESOURCES:
_glfwInitHints.ns.chdir = value;
return;
case GLFW_COCOA_MENUBAR:
_glfwInitHints.ns.menubar = value;
return;
}
_glfwInputError(GLFW_INVALID_ENUM,
"Invalid init hint 0x%08X", hint);
}
GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev)
{
if (major != NULL)
*major = GLFW_VERSION_MAJOR;
if (minor != NULL)
*minor = GLFW_VERSION_MINOR;
if (rev != NULL)
*rev = GLFW_VERSION_REVISION;
}
GLFWAPI const char* glfwGetVersionString(void)
{
return _glfwPlatformGetVersionString();
}
GLFWAPI int glfwGetError(const char** description)
{
_GLFWerror* error;
int code = GLFW_NO_ERROR;
if (description)
*description = NULL;
if (_glfw.initialized)
error = _glfwPlatformGetTls(&_glfw.errorSlot);
else
error = &_glfwMainThreadError;
if (error)
{
code = error->code;
error->code = GLFW_NO_ERROR;
if (description && code)
*description = error->description;
}
return code;
}
GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun)
{
_GLFW_SWAP_POINTERS(_glfwErrorCallback, cbfun);
return cbfun;
}

1308
glfw/input.c vendored Normal file

File diff suppressed because it is too large Load Diff

771
glfw/internal.h vendored Normal file
View File

@@ -0,0 +1,771 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#pragma once
#if defined(_GLFW_USE_CONFIG_H)
#include "glfw_config.h"
#endif
#if defined(GLFW_INCLUDE_GLCOREARB) || \
defined(GLFW_INCLUDE_ES1) || \
defined(GLFW_INCLUDE_ES2) || \
defined(GLFW_INCLUDE_ES3) || \
defined(GLFW_INCLUDE_ES31) || \
defined(GLFW_INCLUDE_ES32) || \
defined(GLFW_INCLUDE_NONE) || \
defined(GLFW_INCLUDE_GLEXT) || \
defined(GLFW_INCLUDE_GLU) || \
defined(GLFW_INCLUDE_VULKAN) || \
defined(GLFW_DLL)
#error "You must not define any header option macros when compiling GLFW"
#endif
#define GLFW_INCLUDE_NONE
#include "glfw3.h"
#define _GLFW_INSERT_FIRST 0
#define _GLFW_INSERT_LAST 1
#define _GLFW_POLL_PRESENCE 0
#define _GLFW_POLL_AXES 1
#define _GLFW_POLL_BUTTONS 2
#define _GLFW_POLL_ALL (_GLFW_POLL_AXES | _GLFW_POLL_BUTTONS)
#define _GLFW_MESSAGE_SIZE 1024
typedef int GLFWbool;
typedef struct _GLFWerror _GLFWerror;
typedef struct _GLFWinitconfig _GLFWinitconfig;
typedef struct _GLFWwndconfig _GLFWwndconfig;
typedef struct _GLFWctxconfig _GLFWctxconfig;
typedef struct _GLFWfbconfig _GLFWfbconfig;
typedef struct _GLFWcontext _GLFWcontext;
typedef struct _GLFWwindow _GLFWwindow;
typedef struct _GLFWlibrary _GLFWlibrary;
typedef struct _GLFWmonitor _GLFWmonitor;
typedef struct _GLFWcursor _GLFWcursor;
typedef struct _GLFWmapelement _GLFWmapelement;
typedef struct _GLFWmapping _GLFWmapping;
typedef struct _GLFWjoystick _GLFWjoystick;
typedef struct _GLFWtls _GLFWtls;
typedef struct _GLFWmutex _GLFWmutex;
typedef void (* _GLFWmakecontextcurrentfun)(_GLFWwindow*);
typedef void (* _GLFWswapbuffersfun)(_GLFWwindow*);
typedef void (* _GLFWswapintervalfun)(int);
typedef int (* _GLFWextensionsupportedfun)(const char*);
typedef GLFWglproc (* _GLFWgetprocaddressfun)(const char*);
typedef void (* _GLFWdestroycontextfun)(_GLFWwindow*);
#define GL_VERSION 0x1f02
#define GL_NONE 0
#define GL_COLOR_BUFFER_BIT 0x00004000
#define GL_UNSIGNED_BYTE 0x1401
#define GL_EXTENSIONS 0x1f03
#define GL_NUM_EXTENSIONS 0x821d
#define GL_CONTEXT_FLAGS 0x821e
#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001
#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
#define GL_CONTEXT_PROFILE_MASK 0x9126
#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001
#define GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
#define GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252
#define GL_NO_RESET_NOTIFICATION_ARB 0x8261
#define GL_CONTEXT_RELEASE_BEHAVIOR 0x82fb
#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82fc
#define GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR 0x00000008
typedef int GLint;
typedef unsigned int GLuint;
typedef unsigned int GLenum;
typedef unsigned int GLbitfield;
typedef unsigned char GLubyte;
typedef void (APIENTRY * PFNGLCLEARPROC)(GLbitfield);
typedef const GLubyte* (APIENTRY * PFNGLGETSTRINGPROC)(GLenum);
typedef void (APIENTRY * PFNGLGETINTEGERVPROC)(GLenum,GLint*);
typedef const GLubyte* (APIENTRY * PFNGLGETSTRINGIPROC)(GLenum,GLuint);
#define VK_NULL_HANDLE 0
typedef void* VkInstance;
typedef void* VkPhysicalDevice;
typedef uint64_t VkSurfaceKHR;
typedef uint32_t VkFlags;
typedef uint32_t VkBool32;
typedef enum VkStructureType
{
VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000,
VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000,
VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000,
VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR = 1000007000,
VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000,
VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000,
VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF
} VkStructureType;
typedef enum VkResult
{
VK_SUCCESS = 0,
VK_NOT_READY = 1,
VK_TIMEOUT = 2,
VK_EVENT_SET = 3,
VK_EVENT_RESET = 4,
VK_INCOMPLETE = 5,
VK_ERROR_OUT_OF_HOST_MEMORY = -1,
VK_ERROR_OUT_OF_DEVICE_MEMORY = -2,
VK_ERROR_INITIALIZATION_FAILED = -3,
VK_ERROR_DEVICE_LOST = -4,
VK_ERROR_MEMORY_MAP_FAILED = -5,
VK_ERROR_LAYER_NOT_PRESENT = -6,
VK_ERROR_EXTENSION_NOT_PRESENT = -7,
VK_ERROR_FEATURE_NOT_PRESENT = -8,
VK_ERROR_INCOMPATIBLE_DRIVER = -9,
VK_ERROR_TOO_MANY_OBJECTS = -10,
VK_ERROR_FORMAT_NOT_SUPPORTED = -11,
VK_ERROR_SURFACE_LOST_KHR = -1000000000,
VK_SUBOPTIMAL_KHR = 1000001003,
VK_ERROR_OUT_OF_DATE_KHR = -1000001004,
VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001,
VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001,
VK_ERROR_VALIDATION_FAILED_EXT = -1000011001,
VK_RESULT_MAX_ENUM = 0x7FFFFFFF
} VkResult;
typedef struct VkAllocationCallbacks VkAllocationCallbacks;
typedef struct VkExtensionProperties
{
char extensionName[256];
uint32_t specVersion;
} VkExtensionProperties;
typedef void (APIENTRY * PFN_vkVoidFunction)(void);
#if defined(_GLFW_VULKAN_STATIC)
PFN_vkVoidFunction vkGetInstanceProcAddr(VkInstance,const char*);
VkResult vkEnumerateInstanceExtensionProperties(const char*,uint32_t*,VkExtensionProperties*);
#else
typedef PFN_vkVoidFunction (APIENTRY * PFN_vkGetInstanceProcAddr)(VkInstance,const char*);
typedef VkResult (APIENTRY * PFN_vkEnumerateInstanceExtensionProperties)(const char*,uint32_t*,VkExtensionProperties*);
#define vkEnumerateInstanceExtensionProperties _glfw.vk.EnumerateInstanceExtensionProperties
#define vkGetInstanceProcAddr _glfw.vk.GetInstanceProcAddr
#endif
#if defined(_GLFW_COCOA)
#include "cocoa_platform.h"
#elif defined(_GLFW_WIN32)
#include "win32_platform.h"
#elif defined(_GLFW_X11)
#include "x11_platform.h"
#elif defined(_GLFW_WAYLAND)
#include "wl_platform.h"
#elif defined(_GLFW_MIR)
#include "mir_platform.h"
#elif defined(_GLFW_OSMESA)
#include "null_platform.h"
#else
#error "No supported window creation API selected"
#endif
// Constructs a version number string from the public header macros
#define _GLFW_CONCAT_VERSION(m, n, r) #m "." #n "." #r
#define _GLFW_MAKE_VERSION(m, n, r) _GLFW_CONCAT_VERSION(m, n, r)
#define _GLFW_VERSION_NUMBER _GLFW_MAKE_VERSION(GLFW_VERSION_MAJOR, \
GLFW_VERSION_MINOR, \
GLFW_VERSION_REVISION)
// Checks for whether the library has been initialized
#define _GLFW_REQUIRE_INIT() \
if (!_glfw.initialized) \
{ \
_glfwInputError(GLFW_NOT_INITIALIZED, NULL); \
return; \
}
#define _GLFW_REQUIRE_INIT_OR_RETURN(x) \
if (!_glfw.initialized) \
{ \
_glfwInputError(GLFW_NOT_INITIALIZED, NULL); \
return x; \
}
// Swaps the provided pointers
#define _GLFW_SWAP_POINTERS(x, y) \
{ \
void* t; \
t = x; \
x = y; \
y = t; \
}
// Per-thread error structure
//
struct _GLFWerror
{
_GLFWerror* next;
int code;
char description[_GLFW_MESSAGE_SIZE];
};
// Initialization configuration
//
// Parameters relating to the initialization of the library
//
struct _GLFWinitconfig
{
GLFWbool hatButtons;
struct {
GLFWbool menubar;
GLFWbool chdir;
} ns;
};
// Window configuration
//
// Parameters relating to the creation of the window but not directly related
// to the framebuffer. This is used to pass window creation parameters from
// shared code to the platform API.
//
struct _GLFWwndconfig
{
int width;
int height;
const char* title;
GLFWbool resizable;
GLFWbool visible;
GLFWbool decorated;
GLFWbool focused;
GLFWbool autoIconify;
GLFWbool floating;
GLFWbool maximized;
GLFWbool centerCursor;
struct {
GLFWbool retina;
char frameName[256];
} ns;
struct {
char className[256];
char instanceName[256];
} x11;
};
// Context configuration
//
// Parameters relating to the creation of the context but not directly related
// to the framebuffer. This is used to pass context creation parameters from
// shared code to the platform API.
//
struct _GLFWctxconfig
{
int client;
int source;
int major;
int minor;
GLFWbool forward;
GLFWbool debug;
GLFWbool noerror;
int profile;
int robustness;
int release;
_GLFWwindow* share;
struct {
GLFWbool offline;
} nsgl;
};
// Framebuffer configuration
//
// This describes buffers and their sizes. It also contains
// a platform-specific ID used to map back to the backend API object.
//
// It is used to pass framebuffer parameters from shared code to the platform
// API and also to enumerate and select available framebuffer configs.
//
struct _GLFWfbconfig
{
int redBits;
int greenBits;
int blueBits;
int alphaBits;
int depthBits;
int stencilBits;
int accumRedBits;
int accumGreenBits;
int accumBlueBits;
int accumAlphaBits;
int auxBuffers;
GLFWbool stereo;
int samples;
GLFWbool sRGB;
GLFWbool doublebuffer;
GLFWbool transparent;
uintptr_t handle;
};
// Context structure
//
struct _GLFWcontext
{
int client;
int source;
int major, minor, revision;
GLFWbool forward, debug, noerror;
int profile;
int robustness;
int release;
PFNGLGETSTRINGIPROC GetStringi;
PFNGLGETINTEGERVPROC GetIntegerv;
PFNGLGETSTRINGPROC GetString;
_GLFWmakecontextcurrentfun makeCurrent;
_GLFWswapbuffersfun swapBuffers;
_GLFWswapintervalfun swapInterval;
_GLFWextensionsupportedfun extensionSupported;
_GLFWgetprocaddressfun getProcAddress;
_GLFWdestroycontextfun destroy;
// This is defined in the context API's context.h
_GLFW_PLATFORM_CONTEXT_STATE;
// This is defined in egl_context.h
_GLFW_EGL_CONTEXT_STATE;
// This is defined in osmesa_context.h
_GLFW_OSMESA_CONTEXT_STATE;
};
// Window and context structure
//
struct _GLFWwindow
{
struct _GLFWwindow* next;
// Window settings and state
GLFWbool resizable;
GLFWbool decorated;
GLFWbool autoIconify;
GLFWbool floating;
GLFWbool shouldClose;
void* userPointer;
GLFWvidmode videoMode;
_GLFWmonitor* monitor;
_GLFWcursor* cursor;
int minwidth, minheight;
int maxwidth, maxheight;
int numer, denom;
GLFWbool stickyKeys;
GLFWbool stickyMouseButtons;
GLFWbool lockKeyMods;
int cursorMode;
char mouseButtons[GLFW_MOUSE_BUTTON_LAST + 1];
char keys[GLFW_KEY_LAST + 1];
// Virtual cursor position when cursor is disabled
double virtualCursorPosX, virtualCursorPosY;
_GLFWcontext context;
struct {
GLFWwindowposfun pos;
GLFWwindowsizefun size;
GLFWwindowclosefun close;
GLFWwindowrefreshfun refresh;
GLFWwindowfocusfun focus;
GLFWwindowiconifyfun iconify;
GLFWwindowmaximizefun maximize;
GLFWframebuffersizefun fbsize;
GLFWwindowcontentscalefun scale;
GLFWmousebuttonfun mouseButton;
GLFWcursorposfun cursorPos;
GLFWcursorenterfun cursorEnter;
GLFWscrollfun scroll;
GLFWkeyfun key;
GLFWcharfun character;
GLFWcharmodsfun charmods;
GLFWdropfun drop;
} callbacks;
// This is defined in the window API's platform.h
_GLFW_PLATFORM_WINDOW_STATE;
};
// Monitor structure
//
struct _GLFWmonitor
{
char* name;
void* userPointer;
// Physical dimensions in millimeters.
int widthMM, heightMM;
// The window whose video mode is current on this monitor
_GLFWwindow* window;
GLFWvidmode* modes;
int modeCount;
GLFWvidmode currentMode;
GLFWgammaramp originalRamp;
GLFWgammaramp currentRamp;
// This is defined in the window API's platform.h
_GLFW_PLATFORM_MONITOR_STATE;
};
// Cursor structure
//
struct _GLFWcursor
{
_GLFWcursor* next;
// This is defined in the window API's platform.h
_GLFW_PLATFORM_CURSOR_STATE;
};
// Gamepad mapping element structure
//
struct _GLFWmapelement
{
uint8_t type;
uint8_t index;
int8_t axisScale;
int8_t axisOffset;
};
// Gamepad mapping structure
//
struct _GLFWmapping
{
char name[128];
char guid[33];
_GLFWmapelement buttons[15];
_GLFWmapelement axes[6];
};
// Joystick structure
//
struct _GLFWjoystick
{
GLFWbool present;
float* axes;
int axisCount;
unsigned char* buttons;
int buttonCount;
unsigned char* hats;
int hatCount;
char* name;
void* userPointer;
char guid[33];
_GLFWmapping* mapping;
// This is defined in the joystick API's joystick.h
_GLFW_PLATFORM_JOYSTICK_STATE;
};
// Thread local storage structure
//
struct _GLFWtls
{
// This is defined in the platform's thread.h
_GLFW_PLATFORM_TLS_STATE;
};
// Mutex structure
//
struct _GLFWmutex
{
// This is defined in the platform's thread.h
_GLFW_PLATFORM_MUTEX_STATE;
};
// Library global data
//
struct _GLFWlibrary
{
GLFWbool initialized;
struct {
_GLFWinitconfig init;
_GLFWfbconfig framebuffer;
_GLFWwndconfig window;
_GLFWctxconfig context;
int refreshRate;
} hints;
_GLFWerror* errorListHead;
_GLFWcursor* cursorListHead;
_GLFWwindow* windowListHead;
_GLFWmonitor** monitors;
int monitorCount;
_GLFWjoystick joysticks[GLFW_JOYSTICK_LAST + 1];
_GLFWmapping* mappings;
int mappingCount;
_GLFWtls errorSlot;
_GLFWtls contextSlot;
_GLFWmutex errorLock;
struct {
uint64_t offset;
// This is defined in the platform's time.h
_GLFW_PLATFORM_LIBRARY_TIMER_STATE;
} timer;
struct {
GLFWbool available;
void* handle;
char* extensions[2];
#if !defined(_GLFW_VULKAN_STATIC)
PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties;
PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
#endif
GLFWbool KHR_surface;
#if defined(_GLFW_WIN32)
GLFWbool KHR_win32_surface;
#elif defined(_GLFW_COCOA)
GLFWbool MVK_macos_surface;
#elif defined(_GLFW_X11)
GLFWbool KHR_xlib_surface;
GLFWbool KHR_xcb_surface;
#elif defined(_GLFW_WAYLAND)
GLFWbool KHR_wayland_surface;
#elif defined(_GLFW_MIR)
GLFWbool KHR_mir_surface;
#endif
} vk;
struct {
GLFWmonitorfun monitor;
GLFWjoystickfun joystick;
} callbacks;
// This is defined in the window API's platform.h
_GLFW_PLATFORM_LIBRARY_WINDOW_STATE;
// This is defined in the context API's context.h
_GLFW_PLATFORM_LIBRARY_CONTEXT_STATE;
// This is defined in the platform's joystick.h
_GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE;
// This is defined in egl_context.h
_GLFW_EGL_LIBRARY_CONTEXT_STATE;
// This is defined in osmesa_context.h
_GLFW_OSMESA_LIBRARY_CONTEXT_STATE;
};
// Global state shared between compilation units of GLFW
//
extern _GLFWlibrary _glfw;
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
int _glfwPlatformInit(void);
void _glfwPlatformTerminate(void);
const char* _glfwPlatformGetVersionString(void);
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos);
void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos);
void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode);
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
const GLFWimage* image, int xhot, int yhot);
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape);
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor);
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor);
const char* _glfwPlatformGetScancodeName(int scancode);
int _glfwPlatformGetKeyScancode(int key);
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor);
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos);
void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
float* xscale, float* yscale);
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count);
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode);
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp);
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp);
void _glfwPlatformSetClipboardString(const char* string);
const char* _glfwPlatformGetClipboardString(void);
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode);
void _glfwPlatformUpdateGamepadGUID(char* guid);
uint64_t _glfwPlatformGetTimerValue(void);
uint64_t _glfwPlatformGetTimerFrequency(void);
int _glfwPlatformCreateWindow(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig);
void _glfwPlatformDestroyWindow(_GLFWwindow* window);
void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title);
void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
int count, const GLFWimage* images);
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos);
void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos);
void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height);
void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height);
void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
int minwidth, int minheight,
int maxwidth, int maxheight);
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom);
void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height);
void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
int* left, int* top,
int* right, int* bottom);
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
float* xscale, float* yscale);
void _glfwPlatformIconifyWindow(_GLFWwindow* window);
void _glfwPlatformRestoreWindow(_GLFWwindow* window);
void _glfwPlatformMaximizeWindow(_GLFWwindow* window);
void _glfwPlatformShowWindow(_GLFWwindow* window);
void _glfwPlatformHideWindow(_GLFWwindow* window);
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window);
int _glfwPlatformWindowBell(_GLFWwindow* window);
void _glfwPlatformFocusWindow(_GLFWwindow* window);
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor,
int xpos, int ypos, int width, int height,
int refreshRate);
int _glfwPlatformWindowFocused(_GLFWwindow* window);
int _glfwPlatformWindowIconified(_GLFWwindow* window);
int _glfwPlatformWindowVisible(_GLFWwindow* window);
int _glfwPlatformWindowMaximized(_GLFWwindow* window);
int _glfwPlatformWindowHovered(_GLFWwindow* window);
int _glfwPlatformFramebufferTransparent(_GLFWwindow* window);
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window);
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled);
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled);
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled);
void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity);
void _glfwPlatformPollEvents(void);
void _glfwPlatformWaitEvents(void);
void _glfwPlatformWaitEventsTimeout(double timeout);
void _glfwPlatformPostEmptyEvent(void);
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions);
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
VkPhysicalDevice device,
uint32_t queuefamily);
VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
_GLFWwindow* window,
const VkAllocationCallbacks* allocator,
VkSurfaceKHR* surface);
GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls);
void _glfwPlatformDestroyTls(_GLFWtls* tls);
void* _glfwPlatformGetTls(_GLFWtls* tls);
void _glfwPlatformSetTls(_GLFWtls* tls, void* value);
GLFWbool _glfwPlatformCreateMutex(_GLFWmutex* mutex);
void _glfwPlatformDestroyMutex(_GLFWmutex* mutex);
void _glfwPlatformLockMutex(_GLFWmutex* mutex);
void _glfwPlatformUnlockMutex(_GLFWmutex* mutex);
//////////////////////////////////////////////////////////////////////////
////// GLFW event API //////
//////////////////////////////////////////////////////////////////////////
void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused);
void _glfwInputWindowPos(_GLFWwindow* window, int xpos, int ypos);
void _glfwInputWindowSize(_GLFWwindow* window, int width, int height);
void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height);
void _glfwInputWindowContentScale(_GLFWwindow* window,
float xscale, float yscale);
void _glfwInputWindowIconify(_GLFWwindow* window, GLFWbool iconified);
void _glfwInputWindowMaximize(_GLFWwindow* window, GLFWbool maximized);
void _glfwInputWindowDamage(_GLFWwindow* window);
void _glfwInputWindowCloseRequest(_GLFWwindow* window);
void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor);
void _glfwInputKey(_GLFWwindow* window,
int key, int scancode, int action, int mods);
void _glfwInputChar(_GLFWwindow* window,
unsigned int codepoint, int mods, GLFWbool plain);
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset);
void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods);
void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos);
void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered);
void _glfwInputDrop(_GLFWwindow* window, int count, const char** names);
void _glfwInputJoystick(_GLFWjoystick* js, int event);
void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value);
void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value);
void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value);
void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement);
void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window);
#if defined(__GNUC__)
void _glfwInputError(int code, const char* format, ...)
__attribute__((format(printf, 2, 3)));
#else
void _glfwInputError(int code, const char* format, ...);
#endif
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions);
const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired,
const _GLFWfbconfig* alternatives,
unsigned int count);
GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig);
GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig);
const GLFWvidmode* _glfwChooseVideoMode(_GLFWmonitor* monitor,
const GLFWvidmode* desired);
int _glfwCompareVideoModes(const GLFWvidmode* first, const GLFWvidmode* second);
_GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM);
void _glfwFreeMonitor(_GLFWmonitor* monitor);
void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size);
void _glfwFreeGammaArrays(GLFWgammaramp* ramp);
void _glfwSplitBPP(int bpp, int* red, int* green, int* blue);
_GLFWjoystick* _glfwAllocJoystick(const char* name,
const char* guid,
int axisCount,
int buttonCount,
int hatCount);
void _glfwFreeJoystick(_GLFWjoystick* js);
GLFWbool _glfwInitVulkan(int mode);
void _glfwTerminateVulkan(void);
const char* _glfwGetVulkanResultString(VkResult result);
char* _glfw_strdup(const char* source);

434
glfw/linux_joystick.c vendored Normal file
View File

@@ -0,0 +1,434 @@
//========================================================================
// GLFW 3.3 Linux - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/inotify.h>
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifndef SYN_DROPPED // < v2.6.39 kernel headers
// Workaround for CentOS-6, which is supported till 2020-11-30, but still on v2.6.32
#define SYN_DROPPED 3
#endif
// Apply an EV_KEY event to the specified joystick
//
static void handleKeyEvent(_GLFWjoystick* js, int code, int value)
{
_glfwInputJoystickButton(js,
js->linjs.keyMap[code - BTN_MISC],
value ? GLFW_PRESS : GLFW_RELEASE);
}
// Apply an EV_ABS event to the specified joystick
//
static void handleAbsEvent(_GLFWjoystick* js, int code, int value)
{
const int index = js->linjs.absMap[code];
if (code >= ABS_HAT0X && code <= ABS_HAT3Y)
{
static const char stateMap[3][3] =
{
{ GLFW_HAT_CENTERED, GLFW_HAT_UP, GLFW_HAT_DOWN },
{ GLFW_HAT_LEFT, GLFW_HAT_LEFT_UP, GLFW_HAT_LEFT_DOWN },
{ GLFW_HAT_RIGHT, GLFW_HAT_RIGHT_UP, GLFW_HAT_RIGHT_DOWN },
};
const int hat = (code - ABS_HAT0X) / 2;
const int axis = (code - ABS_HAT0X) % 2;
int* state = js->linjs.hats[hat];
// NOTE: Looking at several input drivers, it seems all hat events use
// -1 for left / up, 0 for centered and 1 for right / down
if (value == 0)
state[axis] = 0;
else if (value < 0)
state[axis] = 1;
else if (value > 0)
state[axis] = 2;
_glfwInputJoystickHat(js, index, stateMap[state[0]][state[1]]);
}
else
{
const struct input_absinfo* info = &js->linjs.absInfo[code];
float normalized = value;
const int range = info->maximum - info->minimum;
if (range)
{
// Normalize to 0.0 -> 1.0
normalized = (normalized - info->minimum) / range;
// Normalize to -1.0 -> 1.0
normalized = normalized * 2.0f - 1.0f;
}
_glfwInputJoystickAxis(js, index, normalized);
}
}
// Poll state of absolute axes
//
static void pollAbsState(_GLFWjoystick* js)
{
int code;
for (code = 0; code < ABS_CNT; code++)
{
if (js->linjs.absMap[code] < 0)
continue;
struct input_absinfo* info = &js->linjs.absInfo[code];
if (ioctl(js->linjs.fd, EVIOCGABS(code), info) < 0)
continue;
handleAbsEvent(js, code, info->value);
}
}
#define isBitSet(bit, arr) (arr[(bit) / 8] & (1 << ((bit) % 8)))
// Attempt to open the specified joystick device
//
static GLFWbool openJoystickDevice(const char* path)
{
int jid, code;
char name[256] = "";
char guid[33] = "";
char evBits[(EV_CNT + 7) / 8] = {0};
char keyBits[(KEY_CNT + 7) / 8] = {0};
char absBits[(ABS_CNT + 7) / 8] = {0};
int axisCount = 0, buttonCount = 0, hatCount = 0;
struct input_id id;
_GLFWjoystickLinux linjs = {0};
_GLFWjoystick* js = NULL;
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
{
if (!_glfw.joysticks[jid].present)
continue;
if (strcmp(_glfw.joysticks[jid].linjs.path, path) == 0)
return GLFW_FALSE;
}
linjs.fd = open(path, O_RDONLY | O_NONBLOCK);
if (linjs.fd == -1)
return GLFW_FALSE;
if (ioctl(linjs.fd, EVIOCGBIT(0, sizeof(evBits)), evBits) < 0 ||
ioctl(linjs.fd, EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits) < 0 ||
ioctl(linjs.fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits) < 0 ||
ioctl(linjs.fd, EVIOCGID, &id) < 0)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Linux: Failed to query input device: %s",
strerror(errno));
close(linjs.fd);
return GLFW_FALSE;
}
// Ensure this device supports the events expected of a joystick
if (!isBitSet(EV_KEY, evBits) || !isBitSet(EV_ABS, evBits))
{
close(linjs.fd);
return GLFW_FALSE;
}
if (ioctl(linjs.fd, EVIOCGNAME(sizeof(name)), name) < 0)
strncpy(name, "Unknown", sizeof(name));
// Generate a joystick GUID that matches the SDL 2.0.5+ one
if (id.vendor && id.product && id.version)
{
sprintf(guid, "%02x%02x0000%02x%02x0000%02x%02x0000%02x%02x0000",
id.bustype & 0xff, id.bustype >> 8,
id.vendor & 0xff, id.vendor >> 8,
id.product & 0xff, id.product >> 8,
id.version & 0xff, id.version >> 8);
}
else
{
sprintf(guid, "%02x%02x0000%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x00",
id.bustype & 0xff, id.bustype >> 8,
name[0], name[1], name[2], name[3],
name[4], name[5], name[6], name[7],
name[8], name[9], name[10]);
}
for (code = BTN_MISC; code < KEY_CNT; code++)
{
if (!isBitSet(code, keyBits))
continue;
linjs.keyMap[code - BTN_MISC] = buttonCount;
buttonCount++;
}
for (code = 0; code < ABS_CNT; code++)
{
linjs.absMap[code] = -1;
if (!isBitSet(code, absBits))
continue;
if (code >= ABS_HAT0X && code <= ABS_HAT3Y)
{
linjs.absMap[code] = hatCount;
hatCount++;
// Skip the Y axis
code++;
}
else
{
if (ioctl(linjs.fd, EVIOCGABS(code), &linjs.absInfo[code]) < 0)
continue;
linjs.absMap[code] = axisCount;
axisCount++;
}
}
js = _glfwAllocJoystick(name, guid, axisCount, buttonCount, hatCount);
if (!js)
{
close(linjs.fd);
return GLFW_FALSE;
}
strncpy(linjs.path, path, sizeof(linjs.path));
memcpy(&js->linjs, &linjs, sizeof(linjs));
pollAbsState(js);
_glfwInputJoystick(js, GLFW_CONNECTED);
return GLFW_TRUE;
}
#undef isBitSet
// Frees all resources associated with the specified joystick
//
static void closeJoystick(_GLFWjoystick* js)
{
close(js->linjs.fd);
_glfwFreeJoystick(js);
_glfwInputJoystick(js, GLFW_DISCONNECTED);
}
// Lexically compare joysticks by name; used by qsort
//
static int compareJoysticks(const void* fp, const void* sp)
{
const _GLFWjoystick* fj = fp;
const _GLFWjoystick* sj = sp;
return strcmp(fj->linjs.path, sj->linjs.path);
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
// Initialize joystick interface
//
GLFWbool _glfwInitJoysticksLinux(void)
{
DIR* dir;
int count = 0;
const char* dirname = "/dev/input";
_glfw.linjs.inotify = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
if (_glfw.linjs.inotify > 0)
{
// HACK: Register for IN_ATTRIB to get notified when udev is done
// This works well in practice but the true way is libudev
_glfw.linjs.watch = inotify_add_watch(_glfw.linjs.inotify,
dirname,
IN_CREATE | IN_ATTRIB | IN_DELETE);
}
// Continue without device connection notifications if inotify fails
if (regcomp(&_glfw.linjs.regex, "^event[0-9]\\+$", 0) != 0)
{
_glfwInputError(GLFW_PLATFORM_ERROR, "Linux: Failed to compile regex");
return GLFW_FALSE;
}
dir = opendir(dirname);
if (dir)
{
struct dirent* entry;
while ((entry = readdir(dir)))
{
regmatch_t match;
if (regexec(&_glfw.linjs.regex, entry->d_name, 1, &match, 0) != 0)
continue;
char path[PATH_MAX];
snprintf(path, sizeof(path), "%s/%s", dirname, entry->d_name);
if (openJoystickDevice(path))
count++;
}
closedir(dir);
}
// Continue with no joysticks if enumeration fails
qsort(_glfw.joysticks, count, sizeof(_GLFWjoystick), compareJoysticks);
return GLFW_TRUE;
}
// Close all opened joystick handles
//
void _glfwTerminateJoysticksLinux(void)
{
int jid;
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
{
_GLFWjoystick* js = _glfw.joysticks + jid;
if (js->present)
closeJoystick(js);
}
regfree(&_glfw.linjs.regex);
if (_glfw.linjs.inotify > 0)
{
if (_glfw.linjs.watch > 0)
inotify_rm_watch(_glfw.linjs.inotify, _glfw.linjs.watch);
close(_glfw.linjs.inotify);
}
}
void _glfwDetectJoystickConnectionLinux(void)
{
ssize_t offset = 0;
char buffer[16384];
if (_glfw.linjs.inotify <= 0)
return;
const ssize_t size = read(_glfw.linjs.inotify, buffer, sizeof(buffer));
while (size > offset)
{
regmatch_t match;
const struct inotify_event* e = (struct inotify_event*) (buffer + offset);
offset += sizeof(struct inotify_event) + e->len;
if (regexec(&_glfw.linjs.regex, e->name, 1, &match, 0) != 0)
continue;
char path[PATH_MAX];
snprintf(path, sizeof(path), "/dev/input/%s", e->name);
if (e->mask & (IN_CREATE | IN_ATTRIB))
openJoystickDevice(path);
else if (e->mask & IN_DELETE)
{
int jid;
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
{
if (strcmp(_glfw.joysticks[jid].linjs.path, path) == 0)
{
closeJoystick(_glfw.joysticks + jid);
break;
}
}
}
}
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode)
{
// Read all queued events (non-blocking)
for (;;)
{
struct input_event e;
errno = 0;
if (read(js->linjs.fd, &e, sizeof(e)) < 0)
{
// Reset the joystick slot if the device was disconnected
if (errno == ENODEV)
closeJoystick(js);
break;
}
if (e.type == EV_SYN)
{
if (e.code == SYN_DROPPED)
_glfw.linjs.dropped = GLFW_TRUE;
else if (e.code == SYN_REPORT)
{
_glfw.linjs.dropped = GLFW_FALSE;
pollAbsState(js);
}
}
if (_glfw.linjs.dropped)
continue;
if (e.type == EV_KEY)
handleKeyEvent(js, e.code, e.value);
else if (e.type == EV_ABS)
handleAbsEvent(js, e.code, e.value);
}
return js->present;
}
void _glfwPlatformUpdateGamepadGUID(char* guid)
{
}

62
glfw/linux_joystick.h vendored Normal file
View File

@@ -0,0 +1,62 @@
//========================================================================
// GLFW 3.3 Linux - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include <linux/input.h>
#include <linux/limits.h>
#include <regex.h>
#define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickLinux linjs
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE _GLFWlibraryLinux linjs
#define _GLFW_PLATFORM_MAPPING_NAME "Linux"
// Linux-specific joystick data
//
typedef struct _GLFWjoystickLinux
{
int fd;
char path[PATH_MAX];
int keyMap[KEY_CNT - BTN_MISC];
int absMap[ABS_CNT];
struct input_absinfo absInfo[ABS_CNT];
int hats[4][2];
} _GLFWjoystickLinux;
// Linux-specific joystick API data
//
typedef struct _GLFWlibraryLinux
{
int inotify;
int watch;
regex_t regex;
GLFWbool dropped;
} _GLFWlibraryLinux;
GLFWbool _glfwInitJoysticksLinux(void);
void _glfwTerminateJoysticksLinux(void);
void _glfwDetectJoystickConnectionLinux(void);

478
glfw/mappings.h vendored Normal file
View File

@@ -0,0 +1,478 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
// As mappings.h.in, this file is used by CMake to produce the mappings.h
// header file. If you are adding a GLFW specific gamepad mapping, this is
// where to put it.
//========================================================================
// As mappings.h, this provides all pre-defined gamepad mappings, including
// all available in SDL_GameControllerDB. Do not edit this file. Any gamepad
// mappings not specific to GLFW should be submitted to SDL_GameControllerDB.
// This file can be re-generated from mappings.h.in and the upstream
// gamecontrollerdb.txt with the GenerateMappings.cmake script.
//========================================================================
// All gamepad mappings not labeled GLFW are copied from the
// SDL_GameControllerDB project under the following license:
//
// Simple DirectMedia Layer
// Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the
// use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
const char* _glfwDefaultMappings[] =
{
"03000000fa2d00000100000000000000,3DRUDDER,leftx:a0,lefty:a1,rightx:a5,righty:a2,platform:Windows,",
"03000000022000000090000000000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
"03000000203800000900000000000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
"03000000102800000900000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,",
"03000000a00500003232000000000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,",
"030000008f0e00001200000000000000,Acme,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows,",
"03000000341a00003608000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"03000000c01100001352000000000000,Battalife Joystick,a:b6,b:b7,back:b2,leftshoulder:b0,leftx:a0,lefty:a1,rightshoulder:b1,start:b3,x:b4,y:b5,platform:Windows,",
"030000006b1400000055000000000000,bigben ps3padstreetnew,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
"0300000066f700000500000000000000,BrutalLegendTest,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",
"03000000d81d00000b00000000000000,BUFFALO BSGP1601 Series ,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Windows,",
"03000000e82000006058000000000000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
"030000005e0400008e02000000000000,Controller (XBOX 360 For Windows),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
"03000000260900008888000000000000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a4,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Windows,",
"03000000a306000022f6000000000000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
"03000000791d00000103000000000000,Dual Box WII,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
"030000004f04000023b3000000000000,Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"03000000341a00000108000000000000,EXEQ RF USB Gamepad 8206,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
"030000000d0f00008500000000000000,Fighting Commander 2016 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"030000000d0f00008400000000000000,Fighting Commander 5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"030000000d0f00008800000000000000,Fighting Stick mini 4,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,",
"030000000d0f00008700000000000000,Fighting Stick mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
"030000000d0f00002700000000000000,FIGHTING STICK V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
"78696e70757403000000000000000000,Fightstick TES,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Windows,",
"03000000790000000600000000000000,G-Shark GS-GP702,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows,",
"03000000260900002625000000000000,Gamecube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,lefttrigger:a4,leftx:a0,lefty:a1,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Windows,",
"030000008f0e00000d31000000000000,GAMEPAD 3 TURBO,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"03000000280400000140000000000000,GamePad Pro USB,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
"03000000ffff00000000000000000000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
"03000000451300000010000000000000,Generic USB Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
"03000000341a00000302000000000000,Hama Scorpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"030000000d0f00004900000000000000,Hatsune Miku Sho Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"03000000d81400000862000000000000,HitBox Edition Cthulhu+,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,",
"030000000d0f00005f00000000000000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"030000000d0f00005e00000000000000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"030000000d0f00004000000000000000,Hori Fighting Stick Mini 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,",
"030000000d0f00006e00000000000000,HORIPAD 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"030000000d0f00006600000000000000,HORIPAD 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"030000000d0f0000ee00000000000000,HORIPAD mini4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"030000000d0f00004d00000000000000,HORIPAD3 A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"03000000250900000017000000000000,HRAP2 on PS/SS/N64 Joypad to USB BOX,a:b2,b:b1,back:b9,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b8,x:b3,y:b0,platform:Windows,",
"030000008f0e00001330000000000000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,platform:Windows,",
"03000000d81d00000f00000000000000,iBUFFALO BSGP1204 Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
"03000000d81d00001000000000000000,iBUFFALO BSGP1204P Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
"03000000830500006020000000000000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Windows,",
"03000000b50700001403000000000000,IMPACT BLACK,a:b2,b:b3,back:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,",
"030000006f0e00002401000000000000,INJUSTICE FightStick for PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
"03000000491900000204000000000000,Ipega PG-9023,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,",
"030000006d04000011c2000000000000,Logitech Cordless Wingman,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b2,righttrigger:b7,rightx:a3,righty:a4,x:b4,platform:Windows,",
"030000006d04000016c2000000000000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"030000006d04000018c2000000000000,Logitech F510 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"030000006d04000019c2000000000000,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"03000000380700005032000000000000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"03000000380700005082000000000000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"03000000380700008433000000000000,Mad Catz FightStick TE S+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
"03000000380700008483000000000000,Mad Catz FightStick TE S+ PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b6,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"03000000380700008134000000000000,Mad Catz FightStick TE2+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"03000000380700008184000000000000,Mad Catz FightStick TE2+ PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,leftstick:b10,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"03000000380700008034000000000000,Mad Catz TE2 PS3 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"03000000380700008084000000000000,Mad Catz TE2 PS4 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"03000000380700008532000000000000,Madcatz Arcade Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"03000000380700003888000000000000,Madcatz Arcade Fightstick TE S+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"03000000380700001888000000000000,MadCatz SFIV FightStick PS3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
"03000000380700008081000000000000,MADCATZ SFV Arcade FightStick Alpha PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"030000008305000031b0000000000000,MaxfireBlaze3,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
"03000000250900000128000000000000,Mayflash Arcade Stick,a:b1,b:b2,back:b8,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b5,y:b6,platform:Windows,",
"03000000790000004418000000000000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",
"03000000790000004318000000000000,Mayflash GameCube Controller Adapter,a:b1,b:b2,back:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b0,leftshoulder:b4,leftstick:b0,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b0,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",
"030000008f0e00001030000000000000,Mayflash USB Adapter for original Sega Saturn controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,rightshoulder:b2,righttrigger:b7,start:b9,x:b3,y:b4,platform:Windows,",
"0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,",
"03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Windows,",
"03000000bd12000015d0000000000000,Nintendo Retrolink USB Super SNES Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,",
"030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
"030000004b120000014d000000000000,NYKO AIRFLO,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a3,leftstick:a0,lefttrigger:b6,leftx:h0.6,lefty:h0.12,rightshoulder:b5,rightstick:a2,righttrigger:b7,rightx:h0.9,righty:h0.4,start:b9,x:b2,y:b3,platform:Windows,",
"03000000362800000100000000000000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows,",
"03000000120c0000f60e000000000000,P4 Wired Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,",
"030000008f0e00000300000000000000,Piranha xtreme,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
"03000000d62000006dca000000000000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"030000008f0e00007530000000000000,PS (R) Gamepad,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b1,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"03000000e30500009605000000000000,PS to USB convert cable,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,",
"03000000100800000100000000000000,PS1 USB,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
"03000000100800000300000000000000,PS2 USB,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
"03000000888800000803000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,",
"030000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows,",
"03000000250900000500000000000000,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows,",
"03000000100000008200000000000000,PS360+ v1.66,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:h0.4,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
"030000004c050000a00b000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"030000004c050000cc09000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"03000000300f00000011000000000000,QanBa Arcade JoyStick 1008,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b10,x:b0,y:b3,platform:Windows,",
"03000000300f00001611000000000000,QanBa Arcade JoyStick 4018,a:b1,b:b2,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,",
"03000000222c00000020000000000000,QANBA DRONE ARCADE JOYSTICK,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,x:b0,y:b3,platform:Windows,",
"03000000300f00001210000000000000,QanBa Joystick Plus,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows,",
"03000000341a00000104000000000000,QanBa Joystick Q4RAF,a:b5,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b1,y:b2,platform:Windows,",
"03000000222c00000223000000000000,Qanba Obsidian Arcade Joystick PS3 Mode,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"03000000222c00000023000000000000,Qanba Obsidian Arcade Joystick PS4 Mode,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"03000000321500000003000000000000,Razer Hydra,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
"030000000d0f00001100000000000000,REAL ARCADE PRO.3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
"030000000d0f00008b00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"030000000d0f00008a00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"030000000d0f00006b00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"030000000d0f00006a00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"030000000d0f00007000000000000000,REAL ARCADE PRO.4 VLX,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
"030000000d0f00002200000000000000,REAL ARCADE Pro.V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"030000000d0f00005c00000000000000,Real Arcade Pro.V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"030000000d0f00005b00000000000000,Real Arcade Pro.V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"03000000790000001100000000000000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,",
"0300000000f000000300000000000000,RetroUSB.com RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,",
"0300000000f00000f100000000000000,RetroUSB.com Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,",
"030000006b140000010d000000000000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"030000006f0e00001e01000000000000,Rock Candy Gamepad for PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"030000004f04000003d0000000000000,run'n'drive,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:a3,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:a4,rightstick:b11,righttrigger:b5,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
"03000000a30600001af5000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
"03000000a306000023f6000000000000,Saitek Cyborg V.1 Game pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
"03000000300f00001201000000000000,Saitek Dual Analog Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,",
"03000000a30600000cff000000000000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,x:b0,y:b1,platform:Windows,",
"03000000a30600000c04000000000000,Saitek P2900,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",
"03000000300f00001001000000000000,Saitek P480 Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,",
"03000000a30600000b04000000000000,Saitek P990,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,",
"03000000a30600000b04000000010000,Saitek P990 Dual Analog Pad,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Windows,",
"03000000300f00001101000000000000,saitek rumble pad,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,",
"0300000000050000289b000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,",
"030000009b2800000500000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,",
"03000000341a00000208000000000000,SL-6555-SBK,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:-a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a3,righty:a2,start:b7,x:b2,y:b3,platform:Windows,",
"030000008f0e00000800000000000000,SpeedLink Strike FX Wireless,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
"03000000ff1100003133000000000000,SVEN X-PAD,a:b2,b:b3,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a4,start:b5,x:b0,y:b1,platform:Windows,",
"03000000fa1900000706000000000000,Team 5,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
"03000000b50700001203000000000000,Techmobility X6-38V,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,",
"030000004f04000015b3000000000000,Thrustmaster Dual Analog 2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,",
"030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Windows,",
"030000004f04000004b3000000000000,Thrustmaster Firestorm Dual Power 3,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,",
"03000000666600000488000000000000,TigerGame PS/PS2 Game Controller Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,",
"03000000d90400000200000000000000,TwinShock PS2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,",
"03000000380700006652000000000000,UnKnown,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,",
"03000000632500002305000000000000,USB Vibration Joystick (BM),a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,",
"03000000790000001b18000000000000,Venom Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
"03000000450c00002043000000000000,XEOX Gamepad SL-6556-BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
"03000000172700004431000000000000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a7,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,",
"03000000786901006e70000000000000,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,",
"03000000203800000900000000010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
"03000000022000000090000001000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
"03000000102800000900000000000000,8Bitdo SFC30 GamePad Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,",
"03000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,",
"030000008305000031b0000000000000,Cideko AK08b,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
"03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X,",
"03000000a306000022f6000001030000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X,",
"03000000790000000600000000000000,G-Shark GP-702,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Mac OS X,",
"03000000ad1b000001f9000000000000,Gamestop BB-070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,",
"030000000d0f00005f00000000010000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000000d0f00005e00000000010000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000000d0f00005f00000000000000,HORI Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000000d0f00005e00000000000000,HORI Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000000d0f00004d00000000000000,HORI Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000000d0f00006e00000000010000,HORIPAD 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000000d0f00006600000000010000,HORIPAD 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000000d0f00006600000000000000,HORIPAD FPS PLUS 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000008f0e00001330000011010000,HuiJia SNES Controller,a:b4,b:b2,back:b16,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b12,rightshoulder:b14,start:b18,x:b6,y:b0,platform:Mac OS X,",
"03000000830500006020000000010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X,",
"03000000830500006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X,",
"030000006d04000016c2000000020000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000006d04000016c2000000030000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000006d04000016c2000014040000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000006d04000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000006d04000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000006d0400001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
"030000006d04000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
"03000000380700005032000000010000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
"03000000380700005082000000010000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
"03000000790000004418000000010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Mac OS X,",
"0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Mac OS X,",
"03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X,",
"03000000d8140000cecf000000000000,MC Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Mac OS X,",
"030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,",
"030000008f0e00000300000000000000,Piranha xtreme,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Mac OS X,",
"030000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,",
"030000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,",
"030000004c050000a00b000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000008916000000fd000000000000,Razer Onza TE,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
"03000000321500000010000000010000,Razer RAIJU,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
"0300000032150000030a000000000000,Razer Wildcat,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
"03000000790000001100000000000000,Retrolink Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a3,lefty:a4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,",
"03000000790000001100000006010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,",
"030000006b140000010d000000010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
"03000000811700007e05000000000000,Sega Saturn,a:b2,b:b4,dpdown:b16,dpleft:b15,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,leftx:a0,lefty:a2,rightshoulder:b9,righttrigger:a4,start:b13,x:b0,y:b6,platform:Mac OS X,",
"03000000b40400000a01000000000000,Sega Saturn USB Gamepad,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X,",
"030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,",
"030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000004c050000a00b000000000000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
"030000005e0400008e02000001000000,Steam Virtual GamePad,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
"03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Mac OS X,",
"03000000110100002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,",
"03000000381000002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,",
"03000000110100001714000000000000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,",
"03000000110100001714000020010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,",
"030000004f04000015b3000000000000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Mac OS X,",
"030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Mac OS X,",
"03000000bd12000015d0000000010000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,",
"03000000bd12000015d0000000000000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,",
"03000000100800000100000000000000,Twin USB Joystick,a:b4,b:b2,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b12,leftstick:b20,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b14,rightstick:b22,righttrigger:b10,rightx:a6,righty:a4,start:b18,x:b6,y:b0,platform:Mac OS X,",
"050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,back:b7,dpdown:b3,dpleft:b0,dpright:b1,dpup:b2,guide:b8,leftshoulder:b11,lefttrigger:b12,leftx:a0,lefty:a1,start:b6,x:b10,y:b9,platform:Mac OS X,",
"050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b8,leftshoulder:b19,leftstick:b23,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b24,righttrigger:b22,rightx:a2,righty:a3,start:b6,x:b18,y:b17,platform:Mac OS X,",
"030000005e0400008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
"03000000c6240000045d000000000000,Xbox 360 Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
"030000005e040000e302000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
"030000005e040000d102000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
"030000005e040000dd02000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
"030000005e040000e002000000000000,Xbox Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X,",
"030000005e040000fd02000003090000,Xbox Wireless Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,",
"030000005e040000ea02000000000000,Xbox Wireless Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
"030000005e040000e002000003090000,Xbox Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X,",
"03000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X,",
"03000000120c0000100e000000010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
"05000000203800000900000000010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
"03000000022000000090000011010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
"05000000c82d00002038000000010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
"03000000c82d00000190000011010000,8Bitdo NES30 Pro 8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
"05000000c82d00003028000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,",
"05000000102800000900000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,",
"05000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,",
"05000000a00500003232000001000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,",
"030000006f0e00003901000020060000,Afterglow Wired Controller for Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"03000000100000008200000011010000,Akishop Customs PS360+ v1.66,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
"05000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,",
"03000000666600006706000000010000,boom PSX to PC Converter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux,",
"03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
"03000000260900008888000000010000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Linux,",
"03000000a306000022f6000011010000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,",
"03000000b40400000a01000000010000,CYPRESS USB Gamepad,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Linux,",
"03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux,",
"030000006f0e00003001000001010000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,",
"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
"030000006f0e00000104000000010000,Gamestop Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000006f0e00001304000000010000,Generic X-Box pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:a0,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:a3,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000006f0e00001f01000000010000,Generic X-Box pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"03000000280400000140000000010000,Gravis GamePad Pro USB ,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
"030000008f0e00000610000000010000,GreenAsia Electronics 4Axes 12Keys GamePad ,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Linux,",
"030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,",
"030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,",
"0500000047532067616d657061640000,GS gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
"06000000adde0000efbe000002010000,Hidromancer Game Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"03000000d81400000862000011010000,HitBox (PS3/PC) Analog Mode,a:b1,b:b2,back:b8,guide:b9,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,platform:Linux,",
"03000000c9110000f055000011010000,HJC Game GAMEPAD,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
"030000000d0f00000d00000000010000,hori,a:b0,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftx:b4,lefty:b5,rightshoulder:b7,start:b9,x:b1,y:b2,platform:Linux,",
"030000000d0f00001000000011010000,HORI CO. LTD. FIGHTING STICK 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
"030000000d0f00006a00000011010000,HORI CO. LTD. Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"030000000d0f00006b00000011010000,HORI CO. LTD. Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,",
"030000000d0f00005f00000011010000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"030000000d0f00005e00000011010000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000000d0f00006e00000011010000,HORIPAD 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"030000000d0f00006600000011010000,HORIPAD 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"030000000d0f00006700000001010000,HORIPAD ONE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000008f0e00001330000010010000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,platform:Linux,",
"03000000830500006020000010010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,",
"050000006964726f69643a636f6e0000,idroid:con,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"03000000b50700001503000010010000,impact,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,",
"03000000fd0500000030000000010000,InterAct GoPad I-73000 (Fighting Game Layout),a:b3,b:b4,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b7,x:b0,y:b1,platform:Linux,",
"030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Linux,",
"03000000300f00001001000010010000,Jess Tech Dual Analog Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,",
"03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,",
"030000006f0e00000103000000020000,Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"030000006d04000016c2000011010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"030000006d04000016c2000010010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000006d04000015c2000010010000,Logitech Logitech Extreme 3D,a:b0,b:b4,back:b6,guide:b8,leftshoulder:b9,leftstick:h0.8,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:h0.2,start:b7,x:b2,y:b5,platform:Linux,",
"030000006d04000018c2000010010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b10,rightx:a3,righty:a4,start:b8,x:b3,y:b4,platform:Linux,",
"05000000380700006652000025010000,Mad Catz C.T.R.L.R ,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"03000000380700005032000011010000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"03000000380700005082000011010000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux,",
"03000000380700008034000011010000,Mad Catz fightstick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"03000000380700008084000011010000,Mad Catz fightstick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"03000000380700008433000011010000,Mad Catz FightStick TE S+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"03000000380700008483000011010000,Mad Catz FightStick TE S+ PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"03000000380700001647000010040000,Mad Catz Wired Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"03000000380700003847000090040000,Mad Catz Wired Xbox 360 Controller (SFIV),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
"03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"03000000380700001888000010010000,MadCatz PC USB Wired Stick 8818,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"03000000380700003888000010010000,MadCatz PC USB Wired Stick 8838,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:a0,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"03000000790000004418000010010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,",
"03000000780000000600000010010000,Microntek USB Joystick,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,",
"030000005e0400008e02000004010000,Microsoft X-Box 360 pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000005e0400008e02000062230000,Microsoft X-Box 360 pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000005e040000d102000001010000,Microsoft X-Box One pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000005e040000d102000003020000,Microsoft X-Box One pad v2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000005e0400008502000000010000,Microsoft X-Box pad (Japan),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,",
"030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,",
"05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,",
"030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Linux,",
"050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
"050000007e0500003003000001000000,Nintendo Wii Remote Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,",
"05000000010000000100000003000000,Nintendo Wiimote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
"030000000d0500000308000010010000,Nostromo n45 Dual Analog Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux,",
"03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,",
"03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"030000005e0400000202000000010000,Old Xbox pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,",
"05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,",
"05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,",
"03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
"030000006f0e00006401000001010000,PDP Battlefield One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,",
"030000004c0500006802000010010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",
"050000004c0500006802000000810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
"03000000341a00003608000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"030000004c0500006802000011810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
"050000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:a12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:a13,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",
"030000004c0500006802000010810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
"030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",
"060000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",
"05000000504c415953544154494f4e00,PS3 Controller (Bluetooth),a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,",
"050000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"030000004c050000a00b000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"050000004c050000cc09000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
"050000004c050000c405000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
"030000004c050000c405000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
"050000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"030000004c050000cc09000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"030000004c050000a00b000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
"030000004c050000cc09000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,",
"030000004c050000c405000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"03000000300f00001211000011010000,QanBa Arcade JoyStick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,platform:Linux,",
"030000009b2800000300000001010000,raphnet.net 4nes4snes v1.5,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux,",
"030000008916000001fd000024010000,Razer Onza Classic Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000008916000000fd000024010000,Razer Onza Tournament,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"03000000321500000010000011010000,Razer RAIJU,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"03000000c6240000045d000025010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"03000000321500000009000011010000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,",
"050000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,",
"0300000032150000030a000001010000,Razer Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"03000000790000001100000010010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux,",
"0300000000f000000300000000010000,RetroUSB.com RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,",
"0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,",
"030000006b140000010d000011010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"030000006f0e00001e01000011010000,Rock Candy Gamepad for PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"030000006f0e00004601000001010000,Rock Candy Wired Controller for Xbox One,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,",
"03000000a30600000cff000010010000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,platform:Linux,",
"03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b12,x:b0,y:b3,platform:Linux,",
"03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,platform:Linux,",
"03000000a30600000b04000000010000,Saitek P990 Dual Analog Pad,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Linux,",
"03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux,",
"03000000c01600008704000011010000,Serial/Keyboard/Mouse/Joystick,a:b12,b:b10,back:b4,dpdown:b2,dpleft:b3,dpright:b1,dpup:b0,leftshoulder:b9,leftstick:b14,lefttrigger:b6,leftx:a1,lefty:a0,rightshoulder:b8,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b5,x:b13,y:b11,platform:Linux,",
"03000000f025000021c1000010010000,ShanWan Gioteck PS3 Wired Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,",
"03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,",
"030000005e0400008e02000073050000,Speedlink TORID Wireless Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,",
"05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,",
"03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,",
"05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,",
"03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"03000000de2800004211000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,",
"03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,",
"030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,",
"030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,",
"030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Linux,",
"030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,",
"03000000bd12000015d0000010010000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux,",
"03000000d814000007cd000011010000,Toodles 2008 Chimp PC/PS3,a:b0,b:b1,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux,",
"03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,",
"03000000100800000300000010010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,",
"03000000790000001100000000010000,USB Gamepad1,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux,",
"05000000ac0500003232000001000000,VR-BOX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,",
"030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000005e040000a102000007010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"030000005e040000a102000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"0000000058626f782033363020576900,Xbox 360 Wireless Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux,",
"0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,",
"050000005e040000e002000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,",
"050000005e040000fd02000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,",
"03000000450c00002043000010010000,XEOX Gamepad SL-6556-BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,",
"05000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux,",
"03000000c0160000e105000001010000,Xin-Mo Xin-Mo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux,",
"03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"64633436313965656664373634323364,Microsoft X-Box 360 pad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android,",
"61363931656135336130663561616264,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,",
"4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,",
"37336435666338653565313731303834,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,",
"35643031303033326130316330353564,PS4 Controller,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,",
"05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android,",
"5477696e20555342204a6f7973746963,Twin USB Joystick,a:b22,b:b21,back:b28,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,leftstick:b30,lefttrigger:b24,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b31,righttrigger:b25,rightx:a3,righty:a2,start:b29,x:b23,y:b20,platform:Android,",
"34356136633366613530316338376136,Xbox Wireless Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,x:b17,y:b2,platform:Android,",
"4d466947616d65706164010000000000,MFi Extended Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:iOS,",
"4d466947616d65706164020000000000,MFi Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:iOS,",
"05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS,",
"78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
"78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
"78696e70757403000000000000000000,XInput Arcade Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
"78696e70757404000000000000000000,XInput Flight Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
"78696e70757405000000000000000000,XInput Dance Pad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
"78696e70757406000000000000000000,XInput Guitar (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
"78696e70757408000000000000000000,XInput Drum Kit (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
NULL
};

508
glfw/monitor.c vendored Normal file
View File

@@ -0,0 +1,508 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <assert.h>
#include <math.h>
#include <float.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
// Lexically compare video modes, used by qsort
//
static int compareVideoModes(const void* fp, const void* sp)
{
const GLFWvidmode* fm = fp;
const GLFWvidmode* sm = sp;
const int fbpp = fm->redBits + fm->greenBits + fm->blueBits;
const int sbpp = sm->redBits + sm->greenBits + sm->blueBits;
const int farea = fm->width * fm->height;
const int sarea = sm->width * sm->height;
// First sort on color bits per pixel
if (fbpp != sbpp)
return fbpp - sbpp;
// Then sort on screen area
if (farea != sarea)
return farea - sarea;
// Lastly sort on refresh rate
return fm->refreshRate - sm->refreshRate;
}
// Retrieves the available modes for the specified monitor
//
static GLFWbool refreshVideoModes(_GLFWmonitor* monitor)
{
int modeCount;
GLFWvidmode* modes;
if (monitor->modes)
return GLFW_TRUE;
modes = _glfwPlatformGetVideoModes(monitor, &modeCount);
if (!modes)
return GLFW_FALSE;
qsort(modes, modeCount, sizeof(GLFWvidmode), compareVideoModes);
free(monitor->modes);
monitor->modes = modes;
monitor->modeCount = modeCount;
return GLFW_TRUE;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW event API //////
//////////////////////////////////////////////////////////////////////////
// Notifies shared code of a monitor connection or disconnection
//
void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement)
{
if (action == GLFW_CONNECTED)
{
_glfw.monitorCount++;
_glfw.monitors =
realloc(_glfw.monitors, sizeof(_GLFWmonitor*) * _glfw.monitorCount);
if (placement == _GLFW_INSERT_FIRST)
{
memmove(_glfw.monitors + 1,
_glfw.monitors,
(_glfw.monitorCount - 1) * sizeof(_GLFWmonitor*));
_glfw.monitors[0] = monitor;
}
else
_glfw.monitors[_glfw.monitorCount - 1] = monitor;
}
else if (action == GLFW_DISCONNECTED)
{
int i;
_GLFWwindow* window;
for (window = _glfw.windowListHead; window; window = window->next)
{
if (window->monitor == monitor)
{
int width, height, xoff, yoff;
_glfwPlatformGetWindowSize(window, &width, &height);
_glfwPlatformSetWindowMonitor(window, NULL, 0, 0, width, height, 0);
_glfwPlatformGetWindowFrameSize(window, &xoff, &yoff, NULL, NULL);
_glfwPlatformSetWindowPos(window, xoff, yoff);
}
}
for (i = 0; i < _glfw.monitorCount; i++)
{
if (_glfw.monitors[i] == monitor)
{
_glfw.monitorCount--;
memmove(_glfw.monitors + i,
_glfw.monitors + i + 1,
(_glfw.monitorCount - i) * sizeof(_GLFWmonitor*));
break;
}
}
}
if (_glfw.callbacks.monitor)
_glfw.callbacks.monitor((GLFWmonitor*) monitor, action);
if (action == GLFW_DISCONNECTED)
_glfwFreeMonitor(monitor);
}
// Notifies shared code that a full screen window has acquired or released
// a monitor
//
void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window)
{
monitor->window = window;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
// Allocates and returns a monitor object with the specified name and dimensions
//
_GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM)
{
_GLFWmonitor* monitor = calloc(1, sizeof(_GLFWmonitor));
monitor->widthMM = widthMM;
monitor->heightMM = heightMM;
if (name)
monitor->name = _glfw_strdup(name);
return monitor;
}
// Frees a monitor object and any data associated with it
//
void _glfwFreeMonitor(_GLFWmonitor* monitor)
{
if (monitor == NULL)
return;
_glfwPlatformFreeMonitor(monitor);
_glfwFreeGammaArrays(&monitor->originalRamp);
_glfwFreeGammaArrays(&monitor->currentRamp);
free(monitor->modes);
free(monitor->name);
free(monitor);
}
// Allocates red, green and blue value arrays of the specified size
//
void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size)
{
ramp->red = calloc(size, sizeof(unsigned short));
ramp->green = calloc(size, sizeof(unsigned short));
ramp->blue = calloc(size, sizeof(unsigned short));
ramp->size = size;
}
// Frees the red, green and blue value arrays and clears the struct
//
void _glfwFreeGammaArrays(GLFWgammaramp* ramp)
{
free(ramp->red);
free(ramp->green);
free(ramp->blue);
memset(ramp, 0, sizeof(GLFWgammaramp));
}
// Chooses the video mode most closely matching the desired one
//
const GLFWvidmode* _glfwChooseVideoMode(_GLFWmonitor* monitor,
const GLFWvidmode* desired)
{
int i;
unsigned int sizeDiff, leastSizeDiff = UINT_MAX;
unsigned int rateDiff, leastRateDiff = UINT_MAX;
unsigned int colorDiff, leastColorDiff = UINT_MAX;
const GLFWvidmode* current;
const GLFWvidmode* closest = NULL;
if (!refreshVideoModes(monitor))
return NULL;
for (i = 0; i < monitor->modeCount; i++)
{
current = monitor->modes + i;
colorDiff = 0;
if (desired->redBits != GLFW_DONT_CARE)
colorDiff += abs(current->redBits - desired->redBits);
if (desired->greenBits != GLFW_DONT_CARE)
colorDiff += abs(current->greenBits - desired->greenBits);
if (desired->blueBits != GLFW_DONT_CARE)
colorDiff += abs(current->blueBits - desired->blueBits);
sizeDiff = abs((current->width - desired->width) *
(current->width - desired->width) +
(current->height - desired->height) *
(current->height - desired->height));
if (desired->refreshRate != GLFW_DONT_CARE)
rateDiff = abs(current->refreshRate - desired->refreshRate);
else
rateDiff = UINT_MAX - current->refreshRate;
if ((colorDiff < leastColorDiff) ||
(colorDiff == leastColorDiff && sizeDiff < leastSizeDiff) ||
(colorDiff == leastColorDiff && sizeDiff == leastSizeDiff && rateDiff < leastRateDiff))
{
closest = current;
leastSizeDiff = sizeDiff;
leastRateDiff = rateDiff;
leastColorDiff = colorDiff;
}
}
return closest;
}
// Performs lexical comparison between two @ref GLFWvidmode structures
//
int _glfwCompareVideoModes(const GLFWvidmode* fm, const GLFWvidmode* sm)
{
return compareVideoModes(fm, sm);
}
// Splits a color depth into red, green and blue bit depths
//
void _glfwSplitBPP(int bpp, int* red, int* green, int* blue)
{
int delta;
// We assume that by 32 the user really meant 24
if (bpp == 32)
bpp = 24;
// Convert "bits per pixel" to red, green & blue sizes
*red = *green = *blue = bpp / 3;
delta = bpp - (*red * 3);
if (delta >= 1)
*green = *green + 1;
if (delta == 2)
*red = *red + 1;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW public API //////
//////////////////////////////////////////////////////////////////////////
GLFWAPI GLFWmonitor** glfwGetMonitors(int* count)
{
assert(count != NULL);
*count = 0;
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
*count = _glfw.monitorCount;
return (GLFWmonitor**) _glfw.monitors;
}
GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (!_glfw.monitorCount)
return NULL;
return (GLFWmonitor*) _glfw.monitors[0];
}
GLFWAPI void glfwGetMonitorPos(GLFWmonitor* handle, int* xpos, int* ypos)
{
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
assert(monitor != NULL);
if (xpos)
*xpos = 0;
if (ypos)
*ypos = 0;
_GLFW_REQUIRE_INIT();
_glfwPlatformGetMonitorPos(monitor, xpos, ypos);
}
GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* handle, int* widthMM, int* heightMM)
{
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
assert(monitor != NULL);
if (widthMM)
*widthMM = 0;
if (heightMM)
*heightMM = 0;
_GLFW_REQUIRE_INIT();
if (widthMM)
*widthMM = monitor->widthMM;
if (heightMM)
*heightMM = monitor->heightMM;
}
GLFWAPI void glfwGetMonitorContentScale(GLFWmonitor* handle,
float* xscale, float* yscale)
{
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
assert(monitor != NULL);
if (xscale)
*xscale = 0.f;
if (yscale)
*yscale = 0.f;
_GLFW_REQUIRE_INIT();
_glfwPlatformGetMonitorContentScale(monitor, xscale, yscale);
}
GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* handle)
{
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
assert(monitor != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
return monitor->name;
}
GLFWAPI void glfwSetMonitorUserPointer(GLFWmonitor* handle, void* pointer)
{
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
assert(monitor != NULL);
_GLFW_REQUIRE_INIT();
monitor->userPointer = pointer;
}
GLFWAPI void* glfwGetMonitorUserPointer(GLFWmonitor* handle)
{
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
assert(monitor != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
return monitor->userPointer;
}
GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP_POINTERS(_glfw.callbacks.monitor, cbfun);
return cbfun;
}
GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* handle, int* count)
{
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
assert(monitor != NULL);
assert(count != NULL);
*count = 0;
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (!refreshVideoModes(monitor))
return NULL;
*count = monitor->modeCount;
return monitor->modes;
}
GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* handle)
{
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
assert(monitor != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_glfwPlatformGetVideoMode(monitor, &monitor->currentMode);
return &monitor->currentMode;
}
GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
{
int i;
unsigned short values[256];
GLFWgammaramp ramp;
assert(handle != NULL);
assert(gamma == gamma);
assert(gamma >= 0.f);
assert(gamma <= FLT_MAX);
_GLFW_REQUIRE_INIT();
if (gamma != gamma || gamma <= 0.f || gamma > FLT_MAX)
{
_glfwInputError(GLFW_INVALID_VALUE, "Invalid gamma value %f", gamma);
return;
}
for (i = 0; i < 256; i++)
{
float value;
// Calculate intensity
value = i / 255.f;
// Apply gamma curve
value = powf(value, 1.f / gamma) * 65535.f + 0.5f;
// Clamp to value range
if (value > 65535.f)
value = 65535.f;
values[i] = (unsigned short) value;
}
ramp.red = values;
ramp.green = values;
ramp.blue = values;
ramp.size = 256;
glfwSetGammaRamp(handle, &ramp);
}
GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle)
{
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
assert(monitor != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_glfwFreeGammaArrays(&monitor->currentRamp);
_glfwPlatformGetGammaRamp(monitor, &monitor->currentRamp);
return &monitor->currentRamp;
}
GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp)
{
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
assert(monitor != NULL);
assert(ramp != NULL);
assert(ramp->size > 0);
assert(ramp->red != NULL);
assert(ramp->green != NULL);
assert(ramp->blue != NULL);
if (ramp->size <= 0)
{
_glfwInputError(GLFW_INVALID_VALUE,
"Invalid gamma ramp size %i",
ramp->size);
return;
}
_GLFW_REQUIRE_INIT();
if (!monitor->originalRamp.size)
_glfwPlatformGetGammaRamp(monitor, &monitor->originalRamp);
_glfwPlatformSetGammaRamp(monitor, ramp);
}

56
glfw/nsgl_context.h vendored Normal file
View File

@@ -0,0 +1,56 @@
//========================================================================
// GLFW 3.3 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextNSGL nsgl
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryNSGL nsgl
// NSGL-specific per-context data
//
typedef struct _GLFWcontextNSGL
{
id pixelFormat;
id object;
} _GLFWcontextNSGL;
// NSGL-specific global data
//
typedef struct _GLFWlibraryNSGL
{
// dlopen handle for OpenGL.framework (for glfwGetProcAddress)
CFBundleRef framework;
} _GLFWlibraryNSGL;
GLFWbool _glfwInitNSGL(void);
void _glfwTerminateNSGL(void);
GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig);
void _glfwDestroyContextNSGL(_GLFWwindow* window);

335
glfw/nsgl_context.m Normal file
View File

@@ -0,0 +1,335 @@
//========================================================================
// GLFW 3.3 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
static void makeContextCurrentNSGL(_GLFWwindow* window)
{
if (window)
[window->context.nsgl.object makeCurrentContext];
else
[NSOpenGLContext clearCurrentContext];
_glfwPlatformSetTls(&_glfw.contextSlot, window);
}
static void swapBuffersNSGL(_GLFWwindow* window)
{
// ARP appears to be unnecessary, but this is future-proof
[window->context.nsgl.object flushBuffer];
}
static void swapIntervalNSGL(int interval)
{
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
GLint sync = interval;
[window->context.nsgl.object setValues:&sync
forParameter:NSOpenGLCPSwapInterval];
}
static int extensionSupportedNSGL(const char* extension)
{
// There are no NSGL extensions
return GLFW_FALSE;
}
static GLFWglproc getProcAddressNSGL(const char* procname)
{
CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault,
procname,
kCFStringEncodingASCII);
GLFWglproc symbol = CFBundleGetFunctionPointerForName(_glfw.nsgl.framework,
symbolName);
CFRelease(symbolName);
return symbol;
}
// Destroy the OpenGL context
//
static void destroyContextNSGL(_GLFWwindow* window)
{
[window->context.nsgl.pixelFormat release];
window->context.nsgl.pixelFormat = nil;
[window->context.nsgl.object release];
window->context.nsgl.object = nil;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
// Initialize OpenGL support
//
GLFWbool _glfwInitNSGL(void)
{
if (_glfw.nsgl.framework)
return GLFW_TRUE;
_glfw.nsgl.framework =
CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
if (_glfw.nsgl.framework == NULL)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"NSGL: Failed to locate OpenGL framework");
return GLFW_FALSE;
}
return GLFW_TRUE;
}
// Terminate OpenGL support
//
void _glfwTerminateNSGL(void)
{
}
// Create the OpenGL context
//
GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
if (ctxconfig->client == GLFW_OPENGL_ES_API)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"NSGL: OpenGL ES is not available on macOS");
return GLFW_FALSE;
}
if (ctxconfig->major > 2)
{
if (ctxconfig->major == 3 && ctxconfig->minor < 2)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"NSGL: The targeted version of macOS does not support OpenGL 3.0 or 3.1 but may support 3.2 and above");
return GLFW_FALSE;
}
if (!ctxconfig->forward || ctxconfig->profile != GLFW_OPENGL_CORE_PROFILE)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"NSGL: The targeted version of macOS only supports forward-compatible core profile contexts for OpenGL 3.2 and above");
return GLFW_FALSE;
}
}
// Context robustness modes (GL_KHR_robustness) are not yet supported by
// macOS but are not a hard constraint, so ignore and continue
// Context release behaviors (GL_KHR_context_flush_control) are not yet
// supported by macOS but are not a hard constraint, so ignore and continue
// Debug contexts (GL_KHR_debug) are not yet supported by macOS but are not
// a hard constraint, so ignore and continue
// No-error contexts (GL_KHR_no_error) are not yet supported by macOS but
// are not a hard constraint, so ignore and continue
#define addAttrib(a) \
{ \
assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \
attribs[index++] = a; \
}
#define setAttrib(a, v) { addAttrib(a); addAttrib(v); }
NSOpenGLPixelFormatAttribute attribs[40];
int index = 0;
addAttrib(NSOpenGLPFAAccelerated);
addAttrib(NSOpenGLPFAClosestPolicy);
if (ctxconfig->nsgl.offline)
{
addAttrib(NSOpenGLPFAAllowOfflineRenderers);
// NOTE: This replaces the NSSupportsAutomaticGraphicsSwitching key in
// Info.plist for unbundled applications
// HACK: This assumes that NSOpenGLPixelFormat will remain
// a straightforward wrapper of its CGL counterpart
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
addAttrib(kCGLPFASupportsAutomaticGraphicsSwitching);
#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
}
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
if (ctxconfig->major >= 4)
{
setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core);
}
else
#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
if (ctxconfig->major >= 3)
{
setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core);
}
if (ctxconfig->major <= 2)
{
if (fbconfig->auxBuffers != GLFW_DONT_CARE)
setAttrib(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers);
if (fbconfig->accumRedBits != GLFW_DONT_CARE &&
fbconfig->accumGreenBits != GLFW_DONT_CARE &&
fbconfig->accumBlueBits != GLFW_DONT_CARE &&
fbconfig->accumAlphaBits != GLFW_DONT_CARE)
{
const int accumBits = fbconfig->accumRedBits +
fbconfig->accumGreenBits +
fbconfig->accumBlueBits +
fbconfig->accumAlphaBits;
setAttrib(NSOpenGLPFAAccumSize, accumBits);
}
}
if (fbconfig->redBits != GLFW_DONT_CARE &&
fbconfig->greenBits != GLFW_DONT_CARE &&
fbconfig->blueBits != GLFW_DONT_CARE)
{
int colorBits = fbconfig->redBits +
fbconfig->greenBits +
fbconfig->blueBits;
// macOS needs non-zero color size, so set reasonable values
if (colorBits == 0)
colorBits = 24;
else if (colorBits < 15)
colorBits = 15;
setAttrib(NSOpenGLPFAColorSize, colorBits);
}
if (fbconfig->alphaBits != GLFW_DONT_CARE)
setAttrib(NSOpenGLPFAAlphaSize, fbconfig->alphaBits);
if (fbconfig->depthBits != GLFW_DONT_CARE)
setAttrib(NSOpenGLPFADepthSize, fbconfig->depthBits);
if (fbconfig->stencilBits != GLFW_DONT_CARE)
setAttrib(NSOpenGLPFAStencilSize, fbconfig->stencilBits);
if (fbconfig->stereo)
{
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
"NSGL: Stereo rendering is deprecated");
return GLFW_FALSE;
#else
addAttrib(NSOpenGLPFAStereo);
#endif
}
if (fbconfig->doublebuffer)
addAttrib(NSOpenGLPFADoubleBuffer);
if (fbconfig->samples != GLFW_DONT_CARE)
{
if (fbconfig->samples == 0)
{
setAttrib(NSOpenGLPFASampleBuffers, 0);
}
else
{
setAttrib(NSOpenGLPFASampleBuffers, 1);
setAttrib(NSOpenGLPFASamples, fbconfig->samples);
}
}
// NOTE: All NSOpenGLPixelFormats on the relevant cards support sRGB
// framebuffer, so there's no need (and no way) to request it
addAttrib(0);
#undef addAttrib
#undef setAttrib
window->context.nsgl.pixelFormat =
[[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
if (window->context.nsgl.pixelFormat == nil)
{
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
"NSGL: Failed to find a suitable pixel format");
return GLFW_FALSE;
}
NSOpenGLContext* share = NULL;
if (ctxconfig->share)
share = ctxconfig->share->context.nsgl.object;
window->context.nsgl.object =
[[NSOpenGLContext alloc] initWithFormat:window->context.nsgl.pixelFormat
shareContext:share];
if (window->context.nsgl.object == nil)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"NSGL: Failed to create OpenGL context");
return GLFW_FALSE;
}
if (fbconfig->transparent)
{
GLint opaque = 0;
[window->context.nsgl.object setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity];
}
[window->context.nsgl.object setView:window->ns.view];
window->context.makeCurrent = makeContextCurrentNSGL;
window->context.swapBuffers = swapBuffersNSGL;
window->context.swapInterval = swapIntervalNSGL;
window->context.extensionSupported = extensionSupportedNSGL;
window->context.getProcAddress = getProcAddressNSGL;
window->context.destroy = destroyContextNSGL;
return GLFW_TRUE;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////
//////////////////////////////////////////////////////////////////////////
GLFWAPI id glfwGetNSGLContext(GLFWwindow* handle)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
_GLFW_REQUIRE_INIT_OR_RETURN(nil);
if (window->context.client == GLFW_NO_API)
{
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
return NULL;
}
return window->context.nsgl.object;
}

50
glfw/null_init.c vendored Normal file
View File

@@ -0,0 +1,50 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
int _glfwPlatformInit(void)
{
_glfwInitTimerPOSIX();
return GLFW_TRUE;
}
void _glfwPlatformTerminate(void)
{
_glfwTerminateOSMesa();
}
const char* _glfwPlatformGetVersionString(void)
{
return _GLFW_VERSION_NUMBER " null OSMesa";
}

42
glfw/null_joystick.c vendored Normal file
View File

@@ -0,0 +1,42 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode)
{
return GLFW_FALSE;
}
void _glfwPlatformUpdateGamepadGUID(char* guid)
{
}

31
glfw/null_joystick.h vendored Normal file
View File

@@ -0,0 +1,31 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#define _GLFW_PLATFORM_JOYSTICK_STATE int nulljs
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE int nulljs
#define _GLFW_PLATFORM_MAPPING_NAME ""

68
glfw/null_monitor.c vendored Normal file
View File

@@ -0,0 +1,68 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
{
}
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
{
}
void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
float* xscale, float* yscale)
{
if (xscale)
*xscale = 1.f;
if (yscale)
*yscale = 1.f;
}
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
{
return NULL;
}
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
{
}
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{
}
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
{
}

62
glfw/null_platform.h vendored Normal file
View File

@@ -0,0 +1,62 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include <dlfcn.h>
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNull null
#define _GLFW_PLATFORM_CONTEXT_STATE
#define _GLFW_PLATFORM_MONITOR_STATE
#define _GLFW_PLATFORM_CURSOR_STATE
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE
#define _GLFW_EGL_CONTEXT_STATE
#define _GLFW_EGL_LIBRARY_CONTEXT_STATE
#include "osmesa_context.h"
#include "posix_time.h"
#include "posix_thread.h"
#include "null_joystick.h"
#if defined(_GLFW_WIN32)
#define _glfw_dlopen(name) LoadLibraryA(name)
#define _glfw_dlclose(handle) FreeLibrary((HMODULE) handle)
#define _glfw_dlsym(handle, name) GetProcAddress((HMODULE) handle, name)
#else
#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
#define _glfw_dlclose(handle) dlclose(handle)
#define _glfw_dlsym(handle, name) dlsym(handle, name)
#endif
// Null-specific per-window data
//
typedef struct _GLFWwindowNull
{
int width;
int height;
} _GLFWwindowNull;

325
glfw/null_window.c vendored Normal file
View File

@@ -0,0 +1,325 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
static int createNativeWindow(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig)
{
window->null.width = wndconfig->width;
window->null.height = wndconfig->height;
return GLFW_TRUE;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
int _glfwPlatformCreateWindow(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
if (!createNativeWindow(window, wndconfig))
return GLFW_FALSE;
if (ctxconfig->client != GLFW_NO_API)
{
if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API ||
ctxconfig->source == GLFW_OSMESA_CONTEXT_API)
{
if (!_glfwInitOSMesa())
return GLFW_FALSE;
if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
return GLFW_FALSE;
}
else
{
_glfwInputError(GLFW_API_UNAVAILABLE, "Null: EGL not available");
return GLFW_FALSE;
}
}
return GLFW_TRUE;
}
void _glfwPlatformDestroyWindow(_GLFWwindow* window)
{
if (window->context.destroy)
window->context.destroy(window);
}
void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
{
}
void _glfwPlatformSetWindowIcon(_GLFWwindow* window, int count,
const GLFWimage* images)
{
}
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
_GLFWmonitor* monitor,
int xpos, int ypos,
int width, int height,
int refreshRate)
{
}
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
{
}
void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
{
}
void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
{
if (width)
*width = window->null.width;
if (height)
*height = window->null.height;
}
void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
{
window->null.width = width;
window->null.height = height;
}
void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
int minwidth, int minheight,
int maxwidth, int maxheight)
{
}
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int n, int d)
{
}
void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height)
{
if (width)
*width = window->null.width;
if (height)
*height = window->null.height;
}
void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
int* left, int* top,
int* right, int* bottom)
{
}
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
float* xscale, float* yscale)
{
if (xscale)
*xscale = 1.f;
if (yscale)
*yscale = 1.f;
}
void _glfwPlatformIconifyWindow(_GLFWwindow* window)
{
}
void _glfwPlatformRestoreWindow(_GLFWwindow* window)
{
}
void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
{
}
int _glfwPlatformWindowMaximized(_GLFWwindow* window)
{
return GLFW_FALSE;
}
int _glfwPlatformWindowHovered(_GLFWwindow* window)
{
return GLFW_FALSE;
}
int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
{
return GLFW_FALSE;
}
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
{
}
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled)
{
}
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
{
}
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window)
{
return 1.f;
}
void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity)
{
}
void _glfwPlatformShowWindow(_GLFWwindow* window)
{
}
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window)
{
}
int _glfwPlatformWindowBell(_GLFWwindow* window)
{
return GLFW_FALSE;
}
void _glfwPlatformUnhideWindow(_GLFWwindow* window)
{
}
void _glfwPlatformHideWindow(_GLFWwindow* window)
{
}
void _glfwPlatformFocusWindow(_GLFWwindow* window)
{
}
int _glfwPlatformWindowFocused(_GLFWwindow* window)
{
return GLFW_FALSE;
}
int _glfwPlatformWindowIconified(_GLFWwindow* window)
{
return GLFW_FALSE;
}
int _glfwPlatformWindowVisible(_GLFWwindow* window)
{
return GLFW_FALSE;
}
void _glfwPlatformPollEvents(void)
{
}
void _glfwPlatformWaitEvents(void)
{
}
void _glfwPlatformWaitEventsTimeout(double timeout)
{
}
void _glfwPlatformPostEmptyEvent(void)
{
}
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
{
}
void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
{
}
void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
{
}
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
const GLFWimage* image,
int xhot, int yhot)
{
return GLFW_TRUE;
}
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
{
return GLFW_TRUE;
}
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
{
}
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
{
}
void _glfwPlatformSetClipboardString(const char* string)
{
}
const char* _glfwPlatformGetClipboardString(void)
{
return NULL;
}
const char* _glfwPlatformGetScancodeName(int scancode)
{
return "";
}
int _glfwPlatformGetKeyScancode(int key)
{
return -1;
}
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)
{
}
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
VkPhysicalDevice device,
uint32_t queuefamily)
{
return GLFW_FALSE;
}
VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
_GLFWwindow* window,
const VkAllocationCallbacks* allocator,
VkSurfaceKHR* surface)
{
// This seems like the most appropriate error to return here
return VK_ERROR_INITIALIZATION_FAILED;
}

370
glfw/osmesa_context.c vendored Normal file
View File

@@ -0,0 +1,370 @@
//========================================================================
// GLFW 3.3 OSMesa - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "internal.h"
static void makeContextCurrentOSMesa(_GLFWwindow* window)
{
if (window)
{
int width, height;
_glfwPlatformGetFramebufferSize(window, &width, &height);
// Check to see if we need to allocate a new buffer
if ((window->context.osmesa.buffer == NULL) ||
(width != window->context.osmesa.width) ||
(height != window->context.osmesa.height))
{
free(window->context.osmesa.buffer);
// Allocate the new buffer (width * height * 8-bit RGBA)
window->context.osmesa.buffer = calloc(4, width * height);
window->context.osmesa.width = width;
window->context.osmesa.height = height;
}
if (!OSMesaMakeCurrent(window->context.osmesa.handle,
window->context.osmesa.buffer,
GL_UNSIGNED_BYTE,
width, height))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"OSMesa: Failed to make context current");
return;
}
}
_glfwPlatformSetTls(&_glfw.contextSlot, window);
}
static GLFWglproc getProcAddressOSMesa(const char* procname)
{
return (GLFWglproc) OSMesaGetProcAddress(procname);
}
static void destroyContextOSMesa(_GLFWwindow* window)
{
if (window->context.osmesa.handle)
{
OSMesaDestroyContext(window->context.osmesa.handle);
window->context.osmesa.handle = NULL;
}
if (window->context.osmesa.buffer)
{
free(window->context.osmesa.buffer);
window->context.osmesa.width = 0;
window->context.osmesa.height = 0;
}
}
static void swapBuffersOSMesa(_GLFWwindow* window)
{
// No double buffering on OSMesa
}
static void swapIntervalOSMesa(int interval)
{
// No swap interval on OSMesa
}
static int extensionSupportedOSMesa(const char* extension)
{
// OSMesa does not have extensions
return GLFW_FALSE;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
GLFWbool _glfwInitOSMesa(void)
{
int i;
const char* sonames[] =
{
#if defined(_GLFW_OSMESA_LIBRARY)
_GLFW_OSMESA_LIBRARY,
#elif defined(_WIN32)
"libOSMesa.dll",
"OSMesa.dll",
#elif defined(__APPLE__)
"libOSMesa.8.dylib",
#elif defined(__CYGWIN__)
"libOSMesa-8.so",
#else
"libOSMesa.so.8",
"libOSMesa.so.6",
#endif
NULL
};
if (_glfw.osmesa.handle)
return GLFW_TRUE;
for (i = 0; sonames[i]; i++)
{
_glfw.osmesa.handle = _glfw_dlopen(sonames[i]);
if (_glfw.osmesa.handle)
break;
}
if (!_glfw.osmesa.handle)
{
_glfwInputError(GLFW_API_UNAVAILABLE, "OSMesa: Library not found");
return GLFW_FALSE;
}
_glfw.osmesa.CreateContextExt = (PFN_OSMesaCreateContextExt)
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaCreateContextExt");
_glfw.osmesa.CreateContextAttribs = (PFN_OSMesaCreateContextAttribs)
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaCreateContextAttribs");
_glfw.osmesa.DestroyContext = (PFN_OSMesaDestroyContext)
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaDestroyContext");
_glfw.osmesa.MakeCurrent = (PFN_OSMesaMakeCurrent)
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaMakeCurrent");
_glfw.osmesa.GetColorBuffer = (PFN_OSMesaGetColorBuffer)
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetColorBuffer");
_glfw.osmesa.GetDepthBuffer = (PFN_OSMesaGetDepthBuffer)
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetDepthBuffer");
_glfw.osmesa.GetProcAddress = (PFN_OSMesaGetProcAddress)
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetProcAddress");
if (!_glfw.osmesa.CreateContextExt ||
!_glfw.osmesa.DestroyContext ||
!_glfw.osmesa.MakeCurrent ||
!_glfw.osmesa.GetColorBuffer ||
!_glfw.osmesa.GetDepthBuffer ||
!_glfw.osmesa.GetProcAddress)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"OSMesa: Failed to load required entry points");
_glfwTerminateOSMesa();
return GLFW_FALSE;
}
return GLFW_TRUE;
}
void _glfwTerminateOSMesa(void)
{
if (_glfw.osmesa.handle)
{
_glfw_dlclose(_glfw.osmesa.handle);
_glfw.osmesa.handle = NULL;
}
}
#define setAttrib(a, v) \
{ \
assert((size_t) (index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
attribs[index++] = a; \
attribs[index++] = v; \
}
GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
OSMesaContext share = NULL;
const int accumBits = fbconfig->accumRedBits +
fbconfig->accumGreenBits +
fbconfig->accumBlueBits +
fbconfig->accumAlphaBits;
if (ctxconfig->client == GLFW_OPENGL_ES_API)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"OSMesa: OpenGL ES is not available on OSMesa");
return GLFW_FALSE;
}
if (ctxconfig->share)
share = ctxconfig->share->context.osmesa.handle;
if (OSMesaCreateContextAttribs)
{
int index = 0, attribs[40];
setAttrib(OSMESA_FORMAT, OSMESA_RGBA);
setAttrib(OSMESA_DEPTH_BITS, fbconfig->depthBits);
setAttrib(OSMESA_STENCIL_BITS, fbconfig->stencilBits);
setAttrib(OSMESA_ACCUM_BITS, accumBits);
if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
{
setAttrib(OSMESA_PROFILE, OSMESA_CORE_PROFILE);
}
else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
{
setAttrib(OSMESA_PROFILE, OSMESA_COMPAT_PROFILE);
}
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
{
setAttrib(OSMESA_CONTEXT_MAJOR_VERSION, ctxconfig->major);
setAttrib(OSMESA_CONTEXT_MINOR_VERSION, ctxconfig->minor);
}
if (ctxconfig->forward)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"OSMesa: Foward-compatible contexts not supported");
return GLFW_FALSE;
}
setAttrib(0, 0);
window->context.osmesa.handle =
OSMesaCreateContextAttribs(attribs, share);
}
else
{
if (ctxconfig->profile)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"OSMesa: OpenGL profiles unavailable");
return GLFW_FALSE;
}
window->context.osmesa.handle =
OSMesaCreateContextExt(OSMESA_RGBA,
fbconfig->depthBits,
fbconfig->stencilBits,
accumBits,
share);
}
if (window->context.osmesa.handle == NULL)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"OSMesa: Failed to create context");
return GLFW_FALSE;
}
window->context.makeCurrent = makeContextCurrentOSMesa;
window->context.swapBuffers = swapBuffersOSMesa;
window->context.swapInterval = swapIntervalOSMesa;
window->context.extensionSupported = extensionSupportedOSMesa;
window->context.getProcAddress = getProcAddressOSMesa;
window->context.destroy = destroyContextOSMesa;
return GLFW_TRUE;
}
#undef setAttrib
//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////
//////////////////////////////////////////////////////////////////////////
GLFWAPI int glfwGetOSMesaColorBuffer(GLFWwindow* handle, int* width,
int* height, int* format, void** buffer)
{
void* mesaBuffer;
GLint mesaWidth, mesaHeight, mesaFormat;
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
if (!OSMesaGetColorBuffer(window->context.osmesa.handle,
&mesaWidth, &mesaHeight,
&mesaFormat, &mesaBuffer))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"OSMesa: Failed to retrieve color buffer");
return GLFW_FALSE;
}
if (width)
*width = mesaWidth;
if (height)
*height = mesaHeight;
if (format)
*format = mesaFormat;
if (buffer)
*buffer = mesaBuffer;
return GLFW_TRUE;
}
GLFWAPI int glfwGetOSMesaDepthBuffer(GLFWwindow* handle,
int* width, int* height,
int* bytesPerValue,
void** buffer)
{
void* mesaBuffer;
GLint mesaWidth, mesaHeight, mesaBytes;
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
if (!OSMesaGetDepthBuffer(window->context.osmesa.handle,
&mesaWidth, &mesaHeight,
&mesaBytes, &mesaBuffer))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"OSMesa: Failed to retrieve depth buffer");
return GLFW_FALSE;
}
if (width)
*width = mesaWidth;
if (height)
*height = mesaHeight;
if (bytesPerValue)
*bytesPerValue = mesaBytes;
if (buffer)
*buffer = mesaBuffer;
return GLFW_TRUE;
}
GLFWAPI OSMesaContext glfwGetOSMesaContext(GLFWwindow* handle)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (window->context.client == GLFW_NO_API)
{
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
return NULL;
}
return window->context.osmesa.handle;
}

94
glfw/osmesa_context.h vendored Normal file
View File

@@ -0,0 +1,94 @@
//========================================================================
// GLFW 3.3 OSMesa - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#define OSMESA_RGBA 0x1908
#define OSMESA_FORMAT 0x22
#define OSMESA_DEPTH_BITS 0x30
#define OSMESA_STENCIL_BITS 0x31
#define OSMESA_ACCUM_BITS 0x32
#define OSMESA_PROFILE 0x33
#define OSMESA_CORE_PROFILE 0x34
#define OSMESA_COMPAT_PROFILE 0x35
#define OSMESA_CONTEXT_MAJOR_VERSION 0x36
#define OSMESA_CONTEXT_MINOR_VERSION 0x37
typedef void* OSMesaContext;
typedef void (*OSMESAproc)(void);
typedef OSMesaContext (GLAPIENTRY * PFN_OSMesaCreateContextExt)(GLenum,GLint,GLint,GLint,OSMesaContext);
typedef OSMesaContext (GLAPIENTRY * PFN_OSMesaCreateContextAttribs)(const int*,OSMesaContext);
typedef void (GLAPIENTRY * PFN_OSMesaDestroyContext)(OSMesaContext);
typedef int (GLAPIENTRY * PFN_OSMesaMakeCurrent)(OSMesaContext,void*,int,int,int);
typedef int (GLAPIENTRY * PFN_OSMesaGetColorBuffer)(OSMesaContext,int*,int*,int*,void**);
typedef int (GLAPIENTRY * PFN_OSMesaGetDepthBuffer)(OSMesaContext,int*,int*,int*,void**);
typedef GLFWglproc (GLAPIENTRY * PFN_OSMesaGetProcAddress)(const char*);
#define OSMesaCreateContextExt _glfw.osmesa.CreateContextExt
#define OSMesaCreateContextAttribs _glfw.osmesa.CreateContextAttribs
#define OSMesaDestroyContext _glfw.osmesa.DestroyContext
#define OSMesaMakeCurrent _glfw.osmesa.MakeCurrent
#define OSMesaGetColorBuffer _glfw.osmesa.GetColorBuffer
#define OSMesaGetDepthBuffer _glfw.osmesa.GetDepthBuffer
#define OSMesaGetProcAddress _glfw.osmesa.GetProcAddress
#define _GLFW_OSMESA_CONTEXT_STATE _GLFWcontextOSMesa osmesa
#define _GLFW_OSMESA_LIBRARY_CONTEXT_STATE _GLFWlibraryOSMesa osmesa
// OSMesa-specific per-context data
//
typedef struct _GLFWcontextOSMesa
{
OSMesaContext handle;
int width;
int height;
void* buffer;
} _GLFWcontextOSMesa;
// OSMesa-specific global data
//
typedef struct _GLFWlibraryOSMesa
{
void* handle;
PFN_OSMesaCreateContextExt CreateContextExt;
PFN_OSMesaCreateContextAttribs CreateContextAttribs;
PFN_OSMesaDestroyContext DestroyContext;
PFN_OSMesaMakeCurrent MakeCurrent;
PFN_OSMesaGetColorBuffer GetColorBuffer;
PFN_OSMesaGetDepthBuffer GetDepthBuffer;
PFN_OSMesaGetProcAddress GetProcAddress;
} _GLFWlibraryOSMesa;
GLFWbool _glfwInitOSMesa(void);
void _glfwTerminateOSMesa(void);
GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig);

103
glfw/posix_thread.c vendored Normal file
View File

@@ -0,0 +1,103 @@
//========================================================================
// GLFW 3.3 POSIX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <assert.h>
#include <string.h>
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls)
{
assert(tls->posix.allocated == GLFW_FALSE);
if (pthread_key_create(&tls->posix.key, NULL) != 0)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"POSIX: Failed to create context TLS");
return GLFW_FALSE;
}
tls->posix.allocated = GLFW_TRUE;
return GLFW_TRUE;
}
void _glfwPlatformDestroyTls(_GLFWtls* tls)
{
if (tls->posix.allocated)
pthread_key_delete(tls->posix.key);
memset(tls, 0, sizeof(_GLFWtls));
}
void* _glfwPlatformGetTls(_GLFWtls* tls)
{
assert(tls->posix.allocated == GLFW_TRUE);
return pthread_getspecific(tls->posix.key);
}
void _glfwPlatformSetTls(_GLFWtls* tls, void* value)
{
assert(tls->posix.allocated == GLFW_TRUE);
pthread_setspecific(tls->posix.key, value);
}
GLFWbool _glfwPlatformCreateMutex(_GLFWmutex* mutex)
{
assert(mutex->posix.allocated == GLFW_FALSE);
if (pthread_mutex_init(&mutex->posix.handle, NULL) != 0)
{
_glfwInputError(GLFW_PLATFORM_ERROR, "POSIX: Failed to create mutex");
return GLFW_FALSE;
}
return mutex->posix.allocated = GLFW_TRUE;
}
void _glfwPlatformDestroyMutex(_GLFWmutex* mutex)
{
if (mutex->posix.allocated)
pthread_mutex_destroy(&mutex->posix.handle);
memset(mutex, 0, sizeof(_GLFWmutex));
}
void _glfwPlatformLockMutex(_GLFWmutex* mutex)
{
assert(mutex->posix.allocated == GLFW_TRUE);
pthread_mutex_lock(&mutex->posix.handle);
}
void _glfwPlatformUnlockMutex(_GLFWmutex* mutex)
{
assert(mutex->posix.allocated == GLFW_TRUE);
pthread_mutex_unlock(&mutex->posix.handle);
}

51
glfw/posix_thread.h vendored Normal file
View File

@@ -0,0 +1,51 @@
//========================================================================
// GLFW 3.3 POSIX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include <pthread.h>
#define _GLFW_PLATFORM_TLS_STATE _GLFWtlsPOSIX posix
#define _GLFW_PLATFORM_MUTEX_STATE _GLFWmutexPOSIX posix
// POSIX-specific thread local storage data
//
typedef struct _GLFWtlsPOSIX
{
GLFWbool allocated;
pthread_key_t key;
} _GLFWtlsPOSIX;
// POSIX-specific mutex data
//
typedef struct _GLFWmutexPOSIX
{
GLFWbool allocated;
pthread_mutex_t handle;
} _GLFWmutexPOSIX;

85
glfw/posix_time.c vendored Normal file
View File

@@ -0,0 +1,85 @@
//========================================================================
// GLFW 3.3 POSIX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <sys/time.h>
#include <time.h>
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
// Initialise timer
//
void _glfwInitTimerPOSIX(void)
{
#if defined(CLOCK_MONOTONIC)
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
{
_glfw.timer.posix.monotonic = GLFW_TRUE;
_glfw.timer.posix.frequency = 1000000000;
}
else
#endif
{
_glfw.timer.posix.monotonic = GLFW_FALSE;
_glfw.timer.posix.frequency = 1000000;
}
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
uint64_t _glfwPlatformGetTimerValue(void)
{
#if defined(CLOCK_MONOTONIC)
if (_glfw.timer.posix.monotonic)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (uint64_t) ts.tv_sec * (uint64_t) 1000000000 + (uint64_t) ts.tv_nsec;
}
else
#endif
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (uint64_t) tv.tv_sec * (uint64_t) 1000000 + (uint64_t) tv.tv_usec;
}
}
uint64_t _glfwPlatformGetTimerFrequency(void)
{
return _glfw.timer.posix.frequency;
}

44
glfw/posix_time.h vendored Normal file
View File

@@ -0,0 +1,44 @@
//========================================================================
// GLFW 3.3 POSIX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#define _GLFW_PLATFORM_LIBRARY_TIMER_STATE _GLFWtimerPOSIX posix
#include <stdint.h>
// POSIX-specific global timer data
//
typedef struct _GLFWtimerPOSIX
{
GLFWbool monotonic;
uint64_t frequency;
} _GLFWtimerPOSIX;
void _glfwInitTimerPOSIX(void);

133
glfw/source-info.json Normal file
View File

@@ -0,0 +1,133 @@
{
"cocoa": {
"headers": [
"cocoa_platform.h",
"cocoa_joystick.h",
"posix_thread.h",
"nsgl_context.h",
"egl_context.h",
"osmesa_context.h"
],
"sources": [
"cocoa_init.m",
"cocoa_joystick.m",
"cocoa_monitor.m",
"cocoa_window.m",
"cocoa_time.c",
"posix_thread.c",
"nsgl_context.m",
"egl_context.c",
"osmesa_context.c"
]
},
"common": {
"headers": [
"internal.h",
"mappings.h"
],
"sources": [
"context.c",
"init.c",
"input.c",
"monitor.c",
"vulkan.c",
"window.c"
]
},
"osmesa": {
"headers": [
"null_platform.h",
"null_joystick.h",
"posix_time.h",
"posix_thread.h",
"osmesa_context.h"
],
"sources": [
"null_init.c",
"null_monitor.c",
"null_window.c",
"null_joystick.c",
"posix_time.c",
"posix_thread.c",
"osmesa_context.c"
]
},
"wayland": {
"headers": [
"wl_platform.h",
"posix_time.h",
"posix_thread.h",
"xkb_glfw.h",
"xkb_unicode.h",
"egl_context.h",
"osmesa_context.h",
"linux_joystick.h"
],
"protocols": [
"stable/xdg-shell/xdg-shell.xml",
"stable/viewporter/viewporter.xml",
"unstable/relative-pointer/relative-pointer-unstable-v1.xml",
"unstable/pointer-constraints/pointer-constraints-unstable-v1.xml",
"unstable/idle-inhibit/idle-inhibit-unstable-v1.xml"
],
"sources": [
"wl_init.c",
"wl_monitor.c",
"wl_window.c",
"posix_time.c",
"posix_thread.c",
"xkb_unicode.c",
"egl_context.c",
"osmesa_context.c",
"linux_joystick.c"
]
},
"wayland_protocols": [
1,
12
],
"win32": {
"headers": [
"win32_platform.h",
"win32_joystick.h",
"wgl_context.h",
"egl_context.h",
"osmesa_context.h"
],
"sources": [
"win32_init.c",
"win32_joystick.c",
"win32_monitor.c",
"win32_time.c",
"win32_thread.c",
"win32_window.c",
"wgl_context.c",
"egl_context.c",
"osmesa_context.c"
]
},
"x11": {
"headers": [
"x11_platform.h",
"xkb_unicode.h",
"posix_time.h",
"posix_thread.h",
"glx_context.h",
"egl_context.h",
"osmesa_context.h",
"linux_joystick.h"
],
"sources": [
"x11_init.c",
"x11_monitor.c",
"x11_window.c",
"xkb_unicode.c",
"posix_time.c",
"posix_thread.c",
"glx_context.c",
"egl_context.c",
"osmesa_context.c",
"linux_joystick.c"
]
}
}

329
glfw/vulkan.c vendored Normal file
View File

@@ -0,0 +1,329 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#define _GLFW_FIND_LOADER 1
#define _GLFW_REQUIRE_LOADER 2
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
GLFWbool _glfwInitVulkan(int mode)
{
VkResult err;
VkExtensionProperties* ep;
uint32_t i, count;
if (_glfw.vk.available)
return GLFW_TRUE;
#if !defined(_GLFW_VULKAN_STATIC)
#if defined(_GLFW_VULKAN_LIBRARY)
_glfw.vk.handle = _glfw_dlopen(_GLFW_VULKAN_LIBRARY);
#elif defined(_GLFW_WIN32)
_glfw.vk.handle = _glfw_dlopen("vulkan-1.dll");
#elif defined(_GLFW_COCOA)
_glfw.vk.handle = _glfw_dlopen("libvulkan.1.dylib");
#else
_glfw.vk.handle = _glfw_dlopen("libvulkan.so.1");
#endif
if (!_glfw.vk.handle)
{
if (mode == _GLFW_REQUIRE_LOADER)
_glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Loader not found");
return GLFW_FALSE;
}
_glfw.vk.GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)
_glfw_dlsym(_glfw.vk.handle, "vkGetInstanceProcAddr");
if (!_glfw.vk.GetInstanceProcAddr)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Vulkan: Loader does not export vkGetInstanceProcAddr");
_glfwTerminateVulkan();
return GLFW_FALSE;
}
_glfw.vk.EnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)
vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceExtensionProperties");
if (!_glfw.vk.EnumerateInstanceExtensionProperties)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Vulkan: Failed to retrieve vkEnumerateInstanceExtensionProperties");
_glfwTerminateVulkan();
return GLFW_FALSE;
}
#endif // _GLFW_VULKAN_STATIC
err = vkEnumerateInstanceExtensionProperties(NULL, &count, NULL);
if (err)
{
// NOTE: This happens on systems with a loader but without any Vulkan ICD
if (mode == _GLFW_REQUIRE_LOADER)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Vulkan: Failed to query instance extension count: %s",
_glfwGetVulkanResultString(err));
}
_glfwTerminateVulkan();
return GLFW_FALSE;
}
ep = calloc(count, sizeof(VkExtensionProperties));
err = vkEnumerateInstanceExtensionProperties(NULL, &count, ep);
if (err)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Vulkan: Failed to query instance extensions: %s",
_glfwGetVulkanResultString(err));
free(ep);
_glfwTerminateVulkan();
return GLFW_FALSE;
}
for (i = 0; i < count; i++)
{
if (strcmp(ep[i].extensionName, "VK_KHR_surface") == 0)
_glfw.vk.KHR_surface = GLFW_TRUE;
#if defined(_GLFW_WIN32)
else if (strcmp(ep[i].extensionName, "VK_KHR_win32_surface") == 0)
_glfw.vk.KHR_win32_surface = GLFW_TRUE;
#elif defined(_GLFW_COCOA)
else if (strcmp(ep[i].extensionName, "VK_MVK_macos_surface") == 0)
_glfw.vk.MVK_macos_surface = GLFW_TRUE;
#elif defined(_GLFW_X11)
else if (strcmp(ep[i].extensionName, "VK_KHR_xlib_surface") == 0)
_glfw.vk.KHR_xlib_surface = GLFW_TRUE;
else if (strcmp(ep[i].extensionName, "VK_KHR_xcb_surface") == 0)
_glfw.vk.KHR_xcb_surface = GLFW_TRUE;
#elif defined(_GLFW_WAYLAND)
else if (strcmp(ep[i].extensionName, "VK_KHR_wayland_surface") == 0)
_glfw.vk.KHR_wayland_surface = GLFW_TRUE;
#elif defined(_GLFW_MIR)
else if (strcmp(ep[i].extensionName, "VK_KHR_mir_surface") == 0)
_glfw.vk.KHR_mir_surface = GLFW_TRUE;
#endif
}
free(ep);
_glfw.vk.available = GLFW_TRUE;
_glfwPlatformGetRequiredInstanceExtensions(_glfw.vk.extensions);
return GLFW_TRUE;
}
void _glfwTerminateVulkan(void)
{
#if !defined(_GLFW_VULKAN_STATIC)
if (_glfw.vk.handle)
_glfw_dlclose(_glfw.vk.handle);
#endif
}
const char* _glfwGetVulkanResultString(VkResult result)
{
switch (result)
{
case VK_SUCCESS:
return "Success";
case VK_NOT_READY:
return "A fence or query has not yet completed";
case VK_TIMEOUT:
return "A wait operation has not completed in the specified time";
case VK_EVENT_SET:
return "An event is signaled";
case VK_EVENT_RESET:
return "An event is unsignaled";
case VK_INCOMPLETE:
return "A return array was too small for the result";
case VK_ERROR_OUT_OF_HOST_MEMORY:
return "A host memory allocation has failed";
case VK_ERROR_OUT_OF_DEVICE_MEMORY:
return "A device memory allocation has failed";
case VK_ERROR_INITIALIZATION_FAILED:
return "Initialization of an object could not be completed for implementation-specific reasons";
case VK_ERROR_DEVICE_LOST:
return "The logical or physical device has been lost";
case VK_ERROR_MEMORY_MAP_FAILED:
return "Mapping of a memory object has failed";
case VK_ERROR_LAYER_NOT_PRESENT:
return "A requested layer is not present or could not be loaded";
case VK_ERROR_EXTENSION_NOT_PRESENT:
return "A requested extension is not supported";
case VK_ERROR_FEATURE_NOT_PRESENT:
return "A requested feature is not supported";
case VK_ERROR_INCOMPATIBLE_DRIVER:
return "The requested version of Vulkan is not supported by the driver or is otherwise incompatible";
case VK_ERROR_TOO_MANY_OBJECTS:
return "Too many objects of the type have already been created";
case VK_ERROR_FORMAT_NOT_SUPPORTED:
return "A requested format is not supported on this device";
case VK_ERROR_SURFACE_LOST_KHR:
return "A surface is no longer available";
case VK_SUBOPTIMAL_KHR:
return "A swapchain no longer matches the surface properties exactly, but can still be used";
case VK_ERROR_OUT_OF_DATE_KHR:
return "A surface has changed in such a way that it is no longer compatible with the swapchain";
case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:
return "The display used by a swapchain does not use the same presentable image layout";
case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
return "The requested window is already connected to a VkSurfaceKHR, or to some other non-Vulkan API";
case VK_ERROR_VALIDATION_FAILED_EXT:
return "A validation layer found an error";
default:
return "ERROR: UNKNOWN VULKAN ERROR";
}
}
//////////////////////////////////////////////////////////////////////////
////// GLFW public API //////
//////////////////////////////////////////////////////////////////////////
GLFWAPI int glfwVulkanSupported(void)
{
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
return _glfwInitVulkan(_GLFW_FIND_LOADER);
}
GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count)
{
assert(count != NULL);
*count = 0;
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
return NULL;
if (!_glfw.vk.extensions[0])
return NULL;
*count = 2;
return (const char**) _glfw.vk.extensions;
}
GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance,
const char* procname)
{
GLFWvkproc proc;
assert(procname != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
return NULL;
proc = (GLFWvkproc) vkGetInstanceProcAddr(instance, procname);
#if defined(_GLFW_VULKAN_STATIC)
if (!proc)
{
if (strcmp(procname, "vkGetInstanceProcAddr") == 0)
return (GLFWvkproc) vkGetInstanceProcAddr;
}
#else
if (!proc)
proc = (GLFWvkproc) _glfw_dlsym(_glfw.vk.handle, procname);
#endif
return proc;
}
GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance,
VkPhysicalDevice device,
uint32_t queuefamily)
{
assert(instance != VK_NULL_HANDLE);
assert(device != VK_NULL_HANDLE);
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
return GLFW_FALSE;
if (!_glfw.vk.extensions[0])
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Vulkan: Window surface creation extensions not found");
return GLFW_FALSE;
}
return _glfwPlatformGetPhysicalDevicePresentationSupport(instance,
device,
queuefamily);
}
GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance,
GLFWwindow* handle,
const VkAllocationCallbacks* allocator,
VkSurfaceKHR* surface)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(instance != VK_NULL_HANDLE);
assert(window != NULL);
assert(surface != NULL);
*surface = VK_NULL_HANDLE;
_GLFW_REQUIRE_INIT_OR_RETURN(VK_ERROR_INITIALIZATION_FAILED);
if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
return VK_ERROR_INITIALIZATION_FAILED;
if (!_glfw.vk.extensions[0])
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Vulkan: Window surface creation extensions not found");
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
if (window->context.client != GLFW_NO_API)
{
_glfwInputError(GLFW_INVALID_VALUE,
"Vulkan: Window surface creation requires the window to have the client API set to GLFW_NO_API");
return VK_ERROR_NATIVE_WINDOW_IN_USE_KHR;
}
return _glfwPlatformCreateWindowSurface(instance, window, allocator, surface);
}

728
glfw/wgl_context.c vendored Normal file
View File

@@ -0,0 +1,728 @@
//========================================================================
// GLFW 3.3 WGL - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <stdlib.h>
#include <malloc.h>
#include <assert.h>
// Returns the specified attribute of the specified pixel format
//
static int getPixelFormatAttrib(_GLFWwindow* window, int pixelFormat, int attrib)
{
int value = 0;
assert(_glfw.wgl.ARB_pixel_format);
if (!_glfw.wgl.GetPixelFormatAttribivARB(window->context.wgl.dc,
pixelFormat,
0, 1, &attrib, &value))
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WGL: Failed to retrieve pixel format attribute");
return 0;
}
return value;
}
// Return a list of available and usable framebuffer configs
//
static int choosePixelFormat(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
_GLFWfbconfig* usableConfigs;
const _GLFWfbconfig* closest;
int i, pixelFormat, nativeCount, usableCount;
if (_glfw.wgl.ARB_pixel_format)
{
nativeCount = getPixelFormatAttrib(window,
1,
WGL_NUMBER_PIXEL_FORMATS_ARB);
}
else
{
nativeCount = DescribePixelFormat(window->context.wgl.dc,
1,
sizeof(PIXELFORMATDESCRIPTOR),
NULL);
}
usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig));
usableCount = 0;
for (i = 0; i < nativeCount; i++)
{
const int n = i + 1;
_GLFWfbconfig* u = usableConfigs + usableCount;
if (_glfw.wgl.ARB_pixel_format)
{
// Get pixel format attributes through "modern" extension
if (!getPixelFormatAttrib(window, n, WGL_SUPPORT_OPENGL_ARB) ||
!getPixelFormatAttrib(window, n, WGL_DRAW_TO_WINDOW_ARB))
{
continue;
}
if (getPixelFormatAttrib(window, n, WGL_PIXEL_TYPE_ARB) !=
WGL_TYPE_RGBA_ARB)
{
continue;
}
if (getPixelFormatAttrib(window, n, WGL_ACCELERATION_ARB) ==
WGL_NO_ACCELERATION_ARB)
{
continue;
}
u->redBits = getPixelFormatAttrib(window, n, WGL_RED_BITS_ARB);
u->greenBits = getPixelFormatAttrib(window, n, WGL_GREEN_BITS_ARB);
u->blueBits = getPixelFormatAttrib(window, n, WGL_BLUE_BITS_ARB);
u->alphaBits = getPixelFormatAttrib(window, n, WGL_ALPHA_BITS_ARB);
u->depthBits = getPixelFormatAttrib(window, n, WGL_DEPTH_BITS_ARB);
u->stencilBits = getPixelFormatAttrib(window, n, WGL_STENCIL_BITS_ARB);
u->accumRedBits = getPixelFormatAttrib(window, n, WGL_ACCUM_RED_BITS_ARB);
u->accumGreenBits = getPixelFormatAttrib(window, n, WGL_ACCUM_GREEN_BITS_ARB);
u->accumBlueBits = getPixelFormatAttrib(window, n, WGL_ACCUM_BLUE_BITS_ARB);
u->accumAlphaBits = getPixelFormatAttrib(window, n, WGL_ACCUM_ALPHA_BITS_ARB);
u->auxBuffers = getPixelFormatAttrib(window, n, WGL_AUX_BUFFERS_ARB);
if (getPixelFormatAttrib(window, n, WGL_STEREO_ARB))
u->stereo = GLFW_TRUE;
if (getPixelFormatAttrib(window, n, WGL_DOUBLE_BUFFER_ARB))
u->doublebuffer = GLFW_TRUE;
if (_glfw.wgl.ARB_multisample)
u->samples = getPixelFormatAttrib(window, n, WGL_SAMPLES_ARB);
if (ctxconfig->client == GLFW_OPENGL_API)
{
if (_glfw.wgl.ARB_framebuffer_sRGB ||
_glfw.wgl.EXT_framebuffer_sRGB)
{
if (getPixelFormatAttrib(window, n, WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB))
u->sRGB = GLFW_TRUE;
}
}
else
{
if (_glfw.wgl.EXT_colorspace)
{
if (getPixelFormatAttrib(window, n, WGL_COLORSPACE_EXT) ==
WGL_COLORSPACE_SRGB_EXT)
{
u->sRGB = GLFW_TRUE;
}
}
}
}
else
{
// Get pixel format attributes through legacy PFDs
PIXELFORMATDESCRIPTOR pfd;
if (!DescribePixelFormat(window->context.wgl.dc,
n,
sizeof(PIXELFORMATDESCRIPTOR),
&pfd))
{
continue;
}
if (!(pfd.dwFlags & PFD_DRAW_TO_WINDOW) ||
!(pfd.dwFlags & PFD_SUPPORT_OPENGL))
{
continue;
}
if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED) &&
(pfd.dwFlags & PFD_GENERIC_FORMAT))
{
continue;
}
if (pfd.iPixelType != PFD_TYPE_RGBA)
continue;
u->redBits = pfd.cRedBits;
u->greenBits = pfd.cGreenBits;
u->blueBits = pfd.cBlueBits;
u->alphaBits = pfd.cAlphaBits;
u->depthBits = pfd.cDepthBits;
u->stencilBits = pfd.cStencilBits;
u->accumRedBits = pfd.cAccumRedBits;
u->accumGreenBits = pfd.cAccumGreenBits;
u->accumBlueBits = pfd.cAccumBlueBits;
u->accumAlphaBits = pfd.cAccumAlphaBits;
u->auxBuffers = pfd.cAuxBuffers;
if (pfd.dwFlags & PFD_STEREO)
u->stereo = GLFW_TRUE;
if (pfd.dwFlags & PFD_DOUBLEBUFFER)
u->doublebuffer = GLFW_TRUE;
}
u->handle = n;
usableCount++;
}
if (!usableCount)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"WGL: The driver does not appear to support OpenGL");
free(usableConfigs);
return 0;
}
closest = _glfwChooseFBConfig(fbconfig, usableConfigs, usableCount);
if (!closest)
{
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
"WGL: Failed to find a suitable pixel format");
free(usableConfigs);
return 0;
}
pixelFormat = (int) closest->handle;
free(usableConfigs);
return pixelFormat;
}
static void makeContextCurrentWGL(_GLFWwindow* window)
{
if (window)
{
if (wglMakeCurrent(window->context.wgl.dc, window->context.wgl.handle))
_glfwPlatformSetTls(&_glfw.contextSlot, window);
else
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WGL: Failed to make context current");
_glfwPlatformSetTls(&_glfw.contextSlot, NULL);
}
}
else
{
if (!wglMakeCurrent(NULL, NULL))
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WGL: Failed to clear current context");
}
_glfwPlatformSetTls(&_glfw.contextSlot, NULL);
}
}
static void swapBuffersWGL(_GLFWwindow* window)
{
// HACK: Use DwmFlush when desktop composition is enabled
if (_glfwIsCompositionEnabledWin32() && !window->monitor)
{
int count = abs(window->context.wgl.interval);
while (count--)
DwmFlush();
}
SwapBuffers(window->context.wgl.dc);
}
static void swapIntervalWGL(int interval)
{
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
window->context.wgl.interval = interval;
// HACK: Disable WGL swap interval when desktop composition is enabled to
// avoid interfering with DWM vsync
if (_glfwIsCompositionEnabledWin32() && !window->monitor)
interval = 0;
if (_glfw.wgl.EXT_swap_control)
_glfw.wgl.SwapIntervalEXT(interval);
}
static int extensionSupportedWGL(const char* extension)
{
const char* extensions;
if (_glfw.wgl.GetExtensionsStringEXT)
{
extensions = _glfw.wgl.GetExtensionsStringEXT();
if (extensions)
{
if (_glfwStringInExtensionString(extension, extensions))
return GLFW_TRUE;
}
}
if (_glfw.wgl.GetExtensionsStringARB)
{
extensions = _glfw.wgl.GetExtensionsStringARB(wglGetCurrentDC());
if (extensions)
{
if (_glfwStringInExtensionString(extension, extensions))
return GLFW_TRUE;
}
}
return GLFW_FALSE;
}
static GLFWglproc getProcAddressWGL(const char* procname)
{
const GLFWglproc proc = (GLFWglproc) wglGetProcAddress(procname);
if (proc)
return proc;
return (GLFWglproc) GetProcAddress(_glfw.wgl.instance, procname);
}
// Destroy the OpenGL context
//
static void destroyContextWGL(_GLFWwindow* window)
{
if (window->context.wgl.handle)
{
wglDeleteContext(window->context.wgl.handle);
window->context.wgl.handle = NULL;
}
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
// Initialize WGL
//
GLFWbool _glfwInitWGL(void)
{
PIXELFORMATDESCRIPTOR pfd;
HGLRC prc, rc;
HDC pdc, dc;
if (_glfw.wgl.instance)
return GLFW_TRUE;
_glfw.wgl.instance = LoadLibraryA("opengl32.dll");
if (!_glfw.wgl.instance)
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WGL: Failed to load opengl32.dll");
return GLFW_FALSE;
}
_glfw.wgl.CreateContext = (PFN_wglCreateContext)
GetProcAddress(_glfw.wgl.instance, "wglCreateContext");
_glfw.wgl.DeleteContext = (PFN_wglDeleteContext)
GetProcAddress(_glfw.wgl.instance, "wglDeleteContext");
_glfw.wgl.GetProcAddress = (PFN_wglGetProcAddress)
GetProcAddress(_glfw.wgl.instance, "wglGetProcAddress");
_glfw.wgl.GetCurrentDC = (PFN_wglGetCurrentDC)
GetProcAddress(_glfw.wgl.instance, "wglGetCurrentDC");
_glfw.wgl.GetCurrentContext = (PFN_wglGetCurrentContext)
GetProcAddress(_glfw.wgl.instance, "wglGetCurrentContext");
_glfw.wgl.MakeCurrent = (PFN_wglMakeCurrent)
GetProcAddress(_glfw.wgl.instance, "wglMakeCurrent");
_glfw.wgl.ShareLists = (PFN_wglShareLists)
GetProcAddress(_glfw.wgl.instance, "wglShareLists");
// NOTE: A dummy context has to be created for opengl32.dll to load the
// OpenGL ICD, from which we can then query WGL extensions
// NOTE: This code will accept the Microsoft GDI ICD; accelerated context
// creation failure occurs during manual pixel format enumeration
dc = GetDC(_glfw.win32.helperWindowHandle);;
ZeroMemory(&pfd, sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
if (!SetPixelFormat(dc, ChoosePixelFormat(dc, &pfd), &pfd))
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WGL: Failed to set pixel format for dummy context");
return GLFW_FALSE;
}
rc = wglCreateContext(dc);
if (!rc)
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WGL: Failed to create dummy context");
return GLFW_FALSE;
}
pdc = wglGetCurrentDC();
prc = wglGetCurrentContext();
if (!wglMakeCurrent(dc, rc))
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WGL: Failed to make dummy context current");
wglMakeCurrent(pdc, prc);
wglDeleteContext(rc);
return GLFW_FALSE;
}
// NOTE: Functions must be loaded first as they're needed to retrieve the
// extension string that tells us whether the functions are supported
_glfw.wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)
wglGetProcAddress("wglGetExtensionsStringEXT");
_glfw.wgl.GetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)
wglGetProcAddress("wglGetExtensionsStringARB");
_glfw.wgl.CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)
wglGetProcAddress("wglCreateContextAttribsARB");
_glfw.wgl.SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)
wglGetProcAddress("wglSwapIntervalEXT");
_glfw.wgl.GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)
wglGetProcAddress("wglGetPixelFormatAttribivARB");
// NOTE: WGL_ARB_extensions_string and WGL_EXT_extensions_string are not
// checked below as we are already using them
_glfw.wgl.ARB_multisample =
extensionSupportedWGL("WGL_ARB_multisample");
_glfw.wgl.ARB_framebuffer_sRGB =
extensionSupportedWGL("WGL_ARB_framebuffer_sRGB");
_glfw.wgl.EXT_framebuffer_sRGB =
extensionSupportedWGL("WGL_EXT_framebuffer_sRGB");
_glfw.wgl.ARB_create_context =
extensionSupportedWGL("WGL_ARB_create_context");
_glfw.wgl.ARB_create_context_profile =
extensionSupportedWGL("WGL_ARB_create_context_profile");
_glfw.wgl.EXT_create_context_es2_profile =
extensionSupportedWGL("WGL_EXT_create_context_es2_profile");
_glfw.wgl.ARB_create_context_robustness =
extensionSupportedWGL("WGL_ARB_create_context_robustness");
_glfw.wgl.ARB_create_context_no_error =
extensionSupportedWGL("WGL_ARB_create_context_no_error");
_glfw.wgl.EXT_swap_control =
extensionSupportedWGL("WGL_EXT_swap_control");
_glfw.wgl.EXT_colorspace =
extensionSupportedWGL("WGL_EXT_colorspace");
_glfw.wgl.ARB_pixel_format =
extensionSupportedWGL("WGL_ARB_pixel_format");
_glfw.wgl.ARB_context_flush_control =
extensionSupportedWGL("WGL_ARB_context_flush_control");
wglMakeCurrent(pdc, prc);
wglDeleteContext(rc);
return GLFW_TRUE;
}
// Terminate WGL
//
void _glfwTerminateWGL(void)
{
if (_glfw.wgl.instance)
FreeLibrary(_glfw.wgl.instance);
}
#define setAttrib(a, v) \
{ \
assert((size_t) (index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
attribs[index++] = a; \
attribs[index++] = v; \
}
// Create the OpenGL or OpenGL ES context
//
GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
int attribs[40];
int pixelFormat;
PIXELFORMATDESCRIPTOR pfd;
HGLRC share = NULL;
if (ctxconfig->share)
share = ctxconfig->share->context.wgl.handle;
window->context.wgl.dc = GetDC(window->win32.handle);
if (!window->context.wgl.dc)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"WGL: Failed to retrieve DC for window");
return GLFW_FALSE;
}
pixelFormat = choosePixelFormat(window, ctxconfig, fbconfig);
if (!pixelFormat)
return GLFW_FALSE;
if (!DescribePixelFormat(window->context.wgl.dc,
pixelFormat, sizeof(pfd), &pfd))
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WGL: Failed to retrieve PFD for selected pixel format");
return GLFW_FALSE;
}
if (!SetPixelFormat(window->context.wgl.dc, pixelFormat, &pfd))
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WGL: Failed to set selected pixel format");
return GLFW_FALSE;
}
if (ctxconfig->client == GLFW_OPENGL_API)
{
if (ctxconfig->forward)
{
if (!_glfw.wgl.ARB_create_context)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"WGL: A forward compatible OpenGL context requested but WGL_ARB_create_context is unavailable");
return GLFW_FALSE;
}
}
if (ctxconfig->profile)
{
if (!_glfw.wgl.ARB_create_context_profile)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"WGL: OpenGL profile requested but WGL_ARB_create_context_profile is unavailable");
return GLFW_FALSE;
}
}
}
else
{
if (!_glfw.wgl.ARB_create_context ||
!_glfw.wgl.ARB_create_context_profile ||
!_glfw.wgl.EXT_create_context_es2_profile)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"WGL: OpenGL ES requested but WGL_ARB_create_context_es2_profile is unavailable");
return GLFW_FALSE;
}
}
if (_glfw.wgl.ARB_create_context)
{
int index = 0, mask = 0, flags = 0;
if (ctxconfig->client == GLFW_OPENGL_API)
{
if (ctxconfig->forward)
flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
mask |= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
}
else
mask |= WGL_CONTEXT_ES2_PROFILE_BIT_EXT;
if (ctxconfig->debug)
flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
if (ctxconfig->robustness)
{
if (_glfw.wgl.ARB_create_context_robustness)
{
if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
{
setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
WGL_NO_RESET_NOTIFICATION_ARB);
}
else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
{
setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
WGL_LOSE_CONTEXT_ON_RESET_ARB);
}
flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB;
}
}
if (ctxconfig->release)
{
if (_glfw.wgl.ARB_context_flush_control)
{
if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE)
{
setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB,
WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB);
}
else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH)
{
setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB,
WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB);
}
}
}
if (ctxconfig->noerror)
{
if (_glfw.wgl.ARB_create_context_no_error)
setAttrib(WGL_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE);
}
// NOTE: Only request an explicitly versioned context when necessary, as
// explicitly requesting version 1.0 does not always return the
// highest version supported by the driver
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
{
setAttrib(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major);
setAttrib(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor);
}
if (flags)
setAttrib(WGL_CONTEXT_FLAGS_ARB, flags);
if (mask)
setAttrib(WGL_CONTEXT_PROFILE_MASK_ARB, mask);
setAttrib(0, 0);
window->context.wgl.handle =
_glfw.wgl.CreateContextAttribsARB(window->context.wgl.dc,
share, attribs);
if (!window->context.wgl.handle)
{
const DWORD error = GetLastError();
if (error == (0xc0070000 | ERROR_INVALID_VERSION_ARB))
{
if (ctxconfig->client == GLFW_OPENGL_API)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"WGL: Driver does not support OpenGL version %i.%i",
ctxconfig->major,
ctxconfig->minor);
}
else
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"WGL: Driver does not support OpenGL ES version %i.%i",
ctxconfig->major,
ctxconfig->minor);
}
}
else if (error == (0xc0070000 | ERROR_INVALID_PROFILE_ARB))
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"WGL: Driver does not support the requested OpenGL profile");
}
else if (error == (0xc0070000 | ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB))
{
_glfwInputError(GLFW_INVALID_VALUE,
"WGL: The share context is not compatible with the requested context");
}
else
{
if (ctxconfig->client == GLFW_OPENGL_API)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"WGL: Failed to create OpenGL context");
}
else
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"WGL: Failed to create OpenGL ES context");
}
}
return GLFW_FALSE;
}
}
else
{
window->context.wgl.handle = wglCreateContext(window->context.wgl.dc);
if (!window->context.wgl.handle)
{
_glfwInputErrorWin32(GLFW_VERSION_UNAVAILABLE,
"WGL: Failed to create OpenGL context");
return GLFW_FALSE;
}
if (share)
{
if (!wglShareLists(share, window->context.wgl.handle))
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WGL: Failed to enable sharing with specified OpenGL context");
return GLFW_FALSE;
}
}
}
window->context.makeCurrent = makeContextCurrentWGL;
window->context.swapBuffers = swapBuffersWGL;
window->context.swapInterval = swapIntervalWGL;
window->context.extensionSupported = extensionSupportedWGL;
window->context.getProcAddress = getProcAddressWGL;
window->context.destroy = destroyContextWGL;
return GLFW_TRUE;
}
#undef setAttrib
//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////
//////////////////////////////////////////////////////////////////////////
GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* handle)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (window->context.client == GLFW_NO_API)
{
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
return NULL;
}
return window->context.wgl.handle;
}

159
glfw/wgl_context.h vendored Normal file
View File

@@ -0,0 +1,159 @@
//========================================================================
// GLFW 3.3 WGL - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
#define WGL_SUPPORT_OPENGL_ARB 0x2010
#define WGL_DRAW_TO_WINDOW_ARB 0x2001
#define WGL_PIXEL_TYPE_ARB 0x2013
#define WGL_TYPE_RGBA_ARB 0x202b
#define WGL_ACCELERATION_ARB 0x2003
#define WGL_NO_ACCELERATION_ARB 0x2025
#define WGL_RED_BITS_ARB 0x2015
#define WGL_RED_SHIFT_ARB 0x2016
#define WGL_GREEN_BITS_ARB 0x2017
#define WGL_GREEN_SHIFT_ARB 0x2018
#define WGL_BLUE_BITS_ARB 0x2019
#define WGL_BLUE_SHIFT_ARB 0x201a
#define WGL_ALPHA_BITS_ARB 0x201b
#define WGL_ALPHA_SHIFT_ARB 0x201c
#define WGL_ACCUM_BITS_ARB 0x201d
#define WGL_ACCUM_RED_BITS_ARB 0x201e
#define WGL_ACCUM_GREEN_BITS_ARB 0x201f
#define WGL_ACCUM_BLUE_BITS_ARB 0x2020
#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
#define WGL_DEPTH_BITS_ARB 0x2022
#define WGL_STENCIL_BITS_ARB 0x2023
#define WGL_AUX_BUFFERS_ARB 0x2024
#define WGL_STEREO_ARB 0x2012
#define WGL_DOUBLE_BUFFER_ARB 0x2011
#define WGL_SAMPLES_ARB 0x2042
#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9
#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001
#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
#define WGL_CONTEXT_FLAGS_ARB 0x2094
#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
#define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252
#define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
#define WGL_NO_RESET_NOTIFICATION_ARB 0x8261
#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
#define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0
#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
#define WGL_CONTEXT_OPENGL_NO_ERROR_ARB 0x31b3
#define WGL_COLORSPACE_EXT 0x309d
#define WGL_COLORSPACE_SRGB_EXT 0x3089
#define ERROR_INVALID_VERSION_ARB 0x2095
#define ERROR_INVALID_PROFILE_ARB 0x2096
#define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054
typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC)(int);
typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC)(HDC,int,int,UINT,const int*,int*);
typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC)(void);
typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC);
typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC,HGLRC,const int*);
typedef HGLRC (WINAPI * PFN_wglCreateContext)(HDC);
typedef BOOL (WINAPI * PFN_wglDeleteContext)(HGLRC);
typedef PROC (WINAPI * PFN_wglGetProcAddress)(LPCSTR);
typedef HDC (WINAPI * PFN_wglGetCurrentDC)(void);
typedef HGLRC (WINAPI * PFN_wglGetCurrentContext)(void);
typedef BOOL (WINAPI * PFN_wglMakeCurrent)(HDC,HGLRC);
typedef BOOL (WINAPI * PFN_wglShareLists)(HGLRC,HGLRC);
// opengl32.dll function pointer typedefs
#define wglCreateContext _glfw.wgl.CreateContext
#define wglDeleteContext _glfw.wgl.DeleteContext
#define wglGetProcAddress _glfw.wgl.GetProcAddress
#define wglGetCurrentDC _glfw.wgl.GetCurrentDC
#define wglGetCurrentContext _glfw.wgl.GetCurrentContext
#define wglMakeCurrent _glfw.wgl.MakeCurrent
#define wglShareLists _glfw.wgl.ShareLists
#define _GLFW_RECREATION_NOT_NEEDED 0
#define _GLFW_RECREATION_REQUIRED 1
#define _GLFW_RECREATION_IMPOSSIBLE 2
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextWGL wgl
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryWGL wgl
// WGL-specific per-context data
//
typedef struct _GLFWcontextWGL
{
HDC dc;
HGLRC handle;
int interval;
} _GLFWcontextWGL;
// WGL-specific global data
//
typedef struct _GLFWlibraryWGL
{
HINSTANCE instance;
PFN_wglCreateContext CreateContext;
PFN_wglDeleteContext DeleteContext;
PFN_wglGetProcAddress GetProcAddress;
PFN_wglGetCurrentDC GetCurrentDC;
PFN_wglGetCurrentContext GetCurrentContext;
PFN_wglMakeCurrent MakeCurrent;
PFN_wglShareLists ShareLists;
PFNWGLSWAPINTERVALEXTPROC SwapIntervalEXT;
PFNWGLGETPIXELFORMATATTRIBIVARBPROC GetPixelFormatAttribivARB;
PFNWGLGETEXTENSIONSSTRINGEXTPROC GetExtensionsStringEXT;
PFNWGLGETEXTENSIONSSTRINGARBPROC GetExtensionsStringARB;
PFNWGLCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB;
GLFWbool EXT_swap_control;
GLFWbool EXT_colorspace;
GLFWbool ARB_multisample;
GLFWbool ARB_framebuffer_sRGB;
GLFWbool EXT_framebuffer_sRGB;
GLFWbool ARB_pixel_format;
GLFWbool ARB_create_context;
GLFWbool ARB_create_context_profile;
GLFWbool EXT_create_context_es2_profile;
GLFWbool ARB_create_context_robustness;
GLFWbool ARB_create_context_no_error;
GLFWbool ARB_context_flush_control;
} _GLFWlibraryWGL;
GLFWbool _glfwInitWGL(void);
void _glfwTerminateWGL(void);
GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig);

587
glfw/win32_init.c vendored Normal file
View File

@@ -0,0 +1,587 @@
//========================================================================
// GLFW 3.3 Win32 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <stdlib.h>
#include <malloc.h>
static const GUID _glfw_GUID_DEVINTERFACE_HID =
{0x4d1e55b2,0xf16f,0x11cf,{0x88,0xcb,0x00,0x11,0x11,0x00,0x00,0x30}};
#define GUID_DEVINTERFACE_HID _glfw_GUID_DEVINTERFACE_HID
#if defined(_GLFW_USE_HYBRID_HPG) || defined(_GLFW_USE_OPTIMUS_HPG)
// Executables (but not DLLs) exporting this symbol with this value will be
// automatically directed to the high-performance GPU on Nvidia Optimus systems
// with up-to-date drivers
//
__declspec(dllexport) DWORD NvOptimusEnablement = 1;
// Executables (but not DLLs) exporting this symbol with this value will be
// automatically directed to the high-performance GPU on AMD PowerXpress systems
// with up-to-date drivers
//
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
#endif // _GLFW_USE_HYBRID_HPG
#if defined(_GLFW_BUILD_DLL)
// GLFW DLL entry point
//
BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
{
return TRUE;
}
#endif // _GLFW_BUILD_DLL
// HACK: Define versionhelpers.h functions manually as MinGW lacks the header
BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp)
{
OSVERSIONINFOEXW osvi = { sizeof(osvi), major, minor, 0, 0, {0}, sp };
DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR;
ULONGLONG cond = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL);
cond = VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL);
cond = VerSetConditionMask(cond, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
return VerifyVersionInfoW(&osvi, mask, cond);
}
// Load necessary libraries (DLLs)
//
static GLFWbool loadLibraries(void)
{
_glfw.win32.winmm.instance = LoadLibraryA("winmm.dll");
if (!_glfw.win32.winmm.instance)
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"Win32: Failed to load winmm.dll");
return GLFW_FALSE;
}
_glfw.win32.winmm.GetTime = (PFN_timeGetTime)
GetProcAddress(_glfw.win32.winmm.instance, "timeGetTime");
_glfw.win32.user32.instance = LoadLibraryA("user32.dll");
if (!_glfw.win32.user32.instance)
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"Win32: Failed to load user32.dll");
return GLFW_FALSE;
}
_glfw.win32.user32.SetProcessDPIAware_ = (PFN_SetProcessDPIAware)
GetProcAddress(_glfw.win32.user32.instance, "SetProcessDPIAware");
_glfw.win32.user32.ChangeWindowMessageFilterEx_ = (PFN_ChangeWindowMessageFilterEx)
GetProcAddress(_glfw.win32.user32.instance, "ChangeWindowMessageFilterEx");
_glfw.win32.dinput8.instance = LoadLibraryA("dinput8.dll");
if (_glfw.win32.dinput8.instance)
{
_glfw.win32.dinput8.Create = (PFN_DirectInput8Create)
GetProcAddress(_glfw.win32.dinput8.instance, "DirectInput8Create");
}
{
int i;
const char* names[] =
{
"xinput1_4.dll",
"xinput1_3.dll",
"xinput9_1_0.dll",
"xinput1_2.dll",
"xinput1_1.dll",
NULL
};
for (i = 0; names[i]; i++)
{
_glfw.win32.xinput.instance = LoadLibraryA(names[i]);
if (_glfw.win32.xinput.instance)
{
_glfw.win32.xinput.GetCapabilities = (PFN_XInputGetCapabilities)
GetProcAddress(_glfw.win32.xinput.instance, "XInputGetCapabilities");
_glfw.win32.xinput.GetState = (PFN_XInputGetState)
GetProcAddress(_glfw.win32.xinput.instance, "XInputGetState");
break;
}
}
}
_glfw.win32.dwmapi.instance = LoadLibraryA("dwmapi.dll");
if (_glfw.win32.dwmapi.instance)
{
_glfw.win32.dwmapi.IsCompositionEnabled = (PFN_DwmIsCompositionEnabled)
GetProcAddress(_glfw.win32.dwmapi.instance, "DwmIsCompositionEnabled");
_glfw.win32.dwmapi.Flush = (PFN_DwmFlush)
GetProcAddress(_glfw.win32.dwmapi.instance, "DwmFlush");
_glfw.win32.dwmapi.EnableBlurBehindWindow = (PFN_DwmEnableBlurBehindWindow)
GetProcAddress(_glfw.win32.dwmapi.instance, "DwmEnableBlurBehindWindow");
}
_glfw.win32.shcore.instance = LoadLibraryA("shcore.dll");
if (_glfw.win32.shcore.instance)
{
_glfw.win32.shcore.SetProcessDpiAwareness_ = (PFN_SetProcessDpiAwareness)
GetProcAddress(_glfw.win32.shcore.instance, "SetProcessDpiAwareness");
_glfw.win32.shcore.GetDpiForMonitor_ = (PFN_GetDpiForMonitor)
GetProcAddress(_glfw.win32.shcore.instance, "GetDpiForMonitor");
}
return GLFW_TRUE;
}
// Unload used libraries (DLLs)
//
static void freeLibraries(void)
{
if (_glfw.win32.xinput.instance)
FreeLibrary(_glfw.win32.xinput.instance);
if (_glfw.win32.dinput8.instance)
FreeLibrary(_glfw.win32.dinput8.instance);
if (_glfw.win32.winmm.instance)
FreeLibrary(_glfw.win32.winmm.instance);
if (_glfw.win32.user32.instance)
FreeLibrary(_glfw.win32.user32.instance);
if (_glfw.win32.dwmapi.instance)
FreeLibrary(_glfw.win32.dwmapi.instance);
if (_glfw.win32.shcore.instance)
FreeLibrary(_glfw.win32.shcore.instance);
}
// Create key code translation tables
//
static void createKeyTables(void)
{
int scancode;
memset(_glfw.win32.keycodes, -1, sizeof(_glfw.win32.keycodes));
memset(_glfw.win32.scancodes, -1, sizeof(_glfw.win32.scancodes));
_glfw.win32.keycodes[0x00B] = GLFW_KEY_0;
_glfw.win32.keycodes[0x002] = GLFW_KEY_1;
_glfw.win32.keycodes[0x003] = GLFW_KEY_2;
_glfw.win32.keycodes[0x004] = GLFW_KEY_3;
_glfw.win32.keycodes[0x005] = GLFW_KEY_4;
_glfw.win32.keycodes[0x006] = GLFW_KEY_5;
_glfw.win32.keycodes[0x007] = GLFW_KEY_6;
_glfw.win32.keycodes[0x008] = GLFW_KEY_7;
_glfw.win32.keycodes[0x009] = GLFW_KEY_8;
_glfw.win32.keycodes[0x00A] = GLFW_KEY_9;
_glfw.win32.keycodes[0x01E] = GLFW_KEY_A;
_glfw.win32.keycodes[0x030] = GLFW_KEY_B;
_glfw.win32.keycodes[0x02E] = GLFW_KEY_C;
_glfw.win32.keycodes[0x020] = GLFW_KEY_D;
_glfw.win32.keycodes[0x012] = GLFW_KEY_E;
_glfw.win32.keycodes[0x021] = GLFW_KEY_F;
_glfw.win32.keycodes[0x022] = GLFW_KEY_G;
_glfw.win32.keycodes[0x023] = GLFW_KEY_H;
_glfw.win32.keycodes[0x017] = GLFW_KEY_I;
_glfw.win32.keycodes[0x024] = GLFW_KEY_J;
_glfw.win32.keycodes[0x025] = GLFW_KEY_K;
_glfw.win32.keycodes[0x026] = GLFW_KEY_L;
_glfw.win32.keycodes[0x032] = GLFW_KEY_M;
_glfw.win32.keycodes[0x031] = GLFW_KEY_N;
_glfw.win32.keycodes[0x018] = GLFW_KEY_O;
_glfw.win32.keycodes[0x019] = GLFW_KEY_P;
_glfw.win32.keycodes[0x010] = GLFW_KEY_Q;
_glfw.win32.keycodes[0x013] = GLFW_KEY_R;
_glfw.win32.keycodes[0x01F] = GLFW_KEY_S;
_glfw.win32.keycodes[0x014] = GLFW_KEY_T;
_glfw.win32.keycodes[0x016] = GLFW_KEY_U;
_glfw.win32.keycodes[0x02F] = GLFW_KEY_V;
_glfw.win32.keycodes[0x011] = GLFW_KEY_W;
_glfw.win32.keycodes[0x02D] = GLFW_KEY_X;
_glfw.win32.keycodes[0x015] = GLFW_KEY_Y;
_glfw.win32.keycodes[0x02C] = GLFW_KEY_Z;
_glfw.win32.keycodes[0x028] = GLFW_KEY_APOSTROPHE;
_glfw.win32.keycodes[0x02B] = GLFW_KEY_BACKSLASH;
_glfw.win32.keycodes[0x033] = GLFW_KEY_COMMA;
_glfw.win32.keycodes[0x00D] = GLFW_KEY_EQUAL;
_glfw.win32.keycodes[0x029] = GLFW_KEY_GRAVE_ACCENT;
_glfw.win32.keycodes[0x01A] = GLFW_KEY_LEFT_BRACKET;
_glfw.win32.keycodes[0x00C] = GLFW_KEY_MINUS;
_glfw.win32.keycodes[0x034] = GLFW_KEY_PERIOD;
_glfw.win32.keycodes[0x01B] = GLFW_KEY_RIGHT_BRACKET;
_glfw.win32.keycodes[0x027] = GLFW_KEY_SEMICOLON;
_glfw.win32.keycodes[0x035] = GLFW_KEY_SLASH;
_glfw.win32.keycodes[0x056] = GLFW_KEY_WORLD_2;
_glfw.win32.keycodes[0x00E] = GLFW_KEY_BACKSPACE;
_glfw.win32.keycodes[0x153] = GLFW_KEY_DELETE;
_glfw.win32.keycodes[0x14F] = GLFW_KEY_END;
_glfw.win32.keycodes[0x01C] = GLFW_KEY_ENTER;
_glfw.win32.keycodes[0x001] = GLFW_KEY_ESCAPE;
_glfw.win32.keycodes[0x147] = GLFW_KEY_HOME;
_glfw.win32.keycodes[0x152] = GLFW_KEY_INSERT;
_glfw.win32.keycodes[0x15D] = GLFW_KEY_MENU;
_glfw.win32.keycodes[0x151] = GLFW_KEY_PAGE_DOWN;
_glfw.win32.keycodes[0x149] = GLFW_KEY_PAGE_UP;
_glfw.win32.keycodes[0x045] = GLFW_KEY_PAUSE;
_glfw.win32.keycodes[0x146] = GLFW_KEY_PAUSE;
_glfw.win32.keycodes[0x039] = GLFW_KEY_SPACE;
_glfw.win32.keycodes[0x00F] = GLFW_KEY_TAB;
_glfw.win32.keycodes[0x03A] = GLFW_KEY_CAPS_LOCK;
_glfw.win32.keycodes[0x145] = GLFW_KEY_NUM_LOCK;
_glfw.win32.keycodes[0x046] = GLFW_KEY_SCROLL_LOCK;
_glfw.win32.keycodes[0x03B] = GLFW_KEY_F1;
_glfw.win32.keycodes[0x03C] = GLFW_KEY_F2;
_glfw.win32.keycodes[0x03D] = GLFW_KEY_F3;
_glfw.win32.keycodes[0x03E] = GLFW_KEY_F4;
_glfw.win32.keycodes[0x03F] = GLFW_KEY_F5;
_glfw.win32.keycodes[0x040] = GLFW_KEY_F6;
_glfw.win32.keycodes[0x041] = GLFW_KEY_F7;
_glfw.win32.keycodes[0x042] = GLFW_KEY_F8;
_glfw.win32.keycodes[0x043] = GLFW_KEY_F9;
_glfw.win32.keycodes[0x044] = GLFW_KEY_F10;
_glfw.win32.keycodes[0x057] = GLFW_KEY_F11;
_glfw.win32.keycodes[0x058] = GLFW_KEY_F12;
_glfw.win32.keycodes[0x064] = GLFW_KEY_F13;
_glfw.win32.keycodes[0x065] = GLFW_KEY_F14;
_glfw.win32.keycodes[0x066] = GLFW_KEY_F15;
_glfw.win32.keycodes[0x067] = GLFW_KEY_F16;
_glfw.win32.keycodes[0x068] = GLFW_KEY_F17;
_glfw.win32.keycodes[0x069] = GLFW_KEY_F18;
_glfw.win32.keycodes[0x06A] = GLFW_KEY_F19;
_glfw.win32.keycodes[0x06B] = GLFW_KEY_F20;
_glfw.win32.keycodes[0x06C] = GLFW_KEY_F21;
_glfw.win32.keycodes[0x06D] = GLFW_KEY_F22;
_glfw.win32.keycodes[0x06E] = GLFW_KEY_F23;
_glfw.win32.keycodes[0x076] = GLFW_KEY_F24;
_glfw.win32.keycodes[0x038] = GLFW_KEY_LEFT_ALT;
_glfw.win32.keycodes[0x01D] = GLFW_KEY_LEFT_CONTROL;
_glfw.win32.keycodes[0x02A] = GLFW_KEY_LEFT_SHIFT;
_glfw.win32.keycodes[0x15B] = GLFW_KEY_LEFT_SUPER;
_glfw.win32.keycodes[0x137] = GLFW_KEY_PRINT_SCREEN;
_glfw.win32.keycodes[0x138] = GLFW_KEY_RIGHT_ALT;
_glfw.win32.keycodes[0x11D] = GLFW_KEY_RIGHT_CONTROL;
_glfw.win32.keycodes[0x036] = GLFW_KEY_RIGHT_SHIFT;
_glfw.win32.keycodes[0x15C] = GLFW_KEY_RIGHT_SUPER;
_glfw.win32.keycodes[0x150] = GLFW_KEY_DOWN;
_glfw.win32.keycodes[0x14B] = GLFW_KEY_LEFT;
_glfw.win32.keycodes[0x14D] = GLFW_KEY_RIGHT;
_glfw.win32.keycodes[0x148] = GLFW_KEY_UP;
_glfw.win32.keycodes[0x052] = GLFW_KEY_KP_0;
_glfw.win32.keycodes[0x04F] = GLFW_KEY_KP_1;
_glfw.win32.keycodes[0x050] = GLFW_KEY_KP_2;
_glfw.win32.keycodes[0x051] = GLFW_KEY_KP_3;
_glfw.win32.keycodes[0x04B] = GLFW_KEY_KP_4;
_glfw.win32.keycodes[0x04C] = GLFW_KEY_KP_5;
_glfw.win32.keycodes[0x04D] = GLFW_KEY_KP_6;
_glfw.win32.keycodes[0x047] = GLFW_KEY_KP_7;
_glfw.win32.keycodes[0x048] = GLFW_KEY_KP_8;
_glfw.win32.keycodes[0x049] = GLFW_KEY_KP_9;
_glfw.win32.keycodes[0x04E] = GLFW_KEY_KP_ADD;
_glfw.win32.keycodes[0x053] = GLFW_KEY_KP_DECIMAL;
_glfw.win32.keycodes[0x135] = GLFW_KEY_KP_DIVIDE;
_glfw.win32.keycodes[0x11C] = GLFW_KEY_KP_ENTER;
_glfw.win32.keycodes[0x037] = GLFW_KEY_KP_MULTIPLY;
_glfw.win32.keycodes[0x04A] = GLFW_KEY_KP_SUBTRACT;
for (scancode = 0; scancode < 512; scancode++)
{
if (_glfw.win32.keycodes[scancode] > 0)
_glfw.win32.scancodes[_glfw.win32.keycodes[scancode]] = scancode;
}
}
// Creates a dummy window for behind-the-scenes work
//
static HWND createHelperWindow(void)
{
MSG msg;
HWND window = CreateWindowExW(WS_EX_OVERLAPPEDWINDOW,
_GLFW_WNDCLASSNAME,
L"GLFW message window",
WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
0, 0, 1, 1,
NULL, NULL,
GetModuleHandleW(NULL),
NULL);
if (!window)
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"Win32: Failed to create helper window");
return NULL;
}
// HACK: The first call to ShowWindow is ignored if the parent process
// passed along a STARTUPINFO, so clear that flag with a no-op call
ShowWindow(window, SW_HIDE);
// Register for HID device notifications
{
DEV_BROADCAST_DEVICEINTERFACE_W dbi;
ZeroMemory(&dbi, sizeof(dbi));
dbi.dbcc_size = sizeof(dbi);
dbi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
dbi.dbcc_classguid = GUID_DEVINTERFACE_HID;
_glfw.win32.deviceNotificationHandle =
RegisterDeviceNotificationW(window,
(DEV_BROADCAST_HDR*) &dbi,
DEVICE_NOTIFY_WINDOW_HANDLE);
}
while (PeekMessageW(&msg, _glfw.win32.helperWindowHandle, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return window;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
// Returns a wide string version of the specified UTF-8 string
//
WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source)
{
WCHAR* target;
int count;
count = MultiByteToWideChar(CP_UTF8, 0, source, -1, NULL, 0);
if (!count)
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"Win32: Failed to convert string from UTF-8");
return NULL;
}
target = calloc(count, sizeof(WCHAR));
if (!MultiByteToWideChar(CP_UTF8, 0, source, -1, target, count))
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"Win32: Failed to convert string from UTF-8");
free(target);
return NULL;
}
return target;
}
// Returns a UTF-8 string version of the specified wide string
//
char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source)
{
char* target;
int size;
size = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL);
if (!size)
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"Win32: Failed to convert string to UTF-8");
return NULL;
}
target = calloc(size, 1);
if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, size, NULL, NULL))
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"Win32: Failed to convert string to UTF-8");
free(target);
return NULL;
}
return target;
}
// Reports the specified error, appending information about the last Win32 error
//
void _glfwInputErrorWin32(int error, const char* description)
{
WCHAR buffer[_GLFW_MESSAGE_SIZE] = L"";
char message[_GLFW_MESSAGE_SIZE] = "";
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_MAX_WIDTH_MASK,
NULL,
GetLastError() & 0xffff,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
buffer,
sizeof(buffer),
NULL);
WideCharToMultiByte(CP_UTF8, 0, buffer, -1, message, sizeof(message), NULL, NULL);
_glfwInputError(error, "%s: %s", description, message);
}
// Updates key names according to the current keyboard layout
//
void _glfwUpdateKeyNamesWin32(void)
{
int key;
BYTE state[256] = {0};
memset(_glfw.win32.keynames, 0, sizeof(_glfw.win32.keynames));
for (key = GLFW_KEY_SPACE; key <= GLFW_KEY_LAST; key++)
{
UINT vk;
int scancode, length;
WCHAR chars[16];
scancode = _glfw.win32.scancodes[key];
if (scancode == -1)
continue;
if (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_ADD)
{
const UINT vks[] = {
VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3,
VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
VK_NUMPAD8, VK_NUMPAD9, VK_DECIMAL, VK_DIVIDE,
VK_MULTIPLY, VK_SUBTRACT, VK_ADD
};
vk = vks[key - GLFW_KEY_KP_0];
}
else
vk = MapVirtualKey(scancode, MAPVK_VSC_TO_VK);
length = ToUnicode(vk, scancode, state,
chars, sizeof(chars) / sizeof(WCHAR),
0);
if (length == -1)
{
length = ToUnicode(vk, scancode, state,
chars, sizeof(chars) / sizeof(WCHAR),
0);
}
if (length < 1)
continue;
WideCharToMultiByte(CP_UTF8, 0, chars, 1,
_glfw.win32.keynames[key],
sizeof(_glfw.win32.keynames[key]),
NULL, NULL);
}
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
int _glfwPlatformInit(void)
{
// To make SetForegroundWindow work as we want, we need to fiddle
// with the FOREGROUNDLOCKTIMEOUT system setting (we do this as early
// as possible in the hope of still being the foreground process)
SystemParametersInfoW(SPI_GETFOREGROUNDLOCKTIMEOUT, 0,
&_glfw.win32.foregroundLockTimeout, 0);
SystemParametersInfoW(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, UIntToPtr(0),
SPIF_SENDCHANGE);
if (!loadLibraries())
return GLFW_FALSE;
createKeyTables();
_glfwUpdateKeyNamesWin32();
if (IsWindows8Point1OrGreater())
SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
else if (IsWindowsVistaOrGreater())
SetProcessDPIAware();
if (!_glfwRegisterWindowClassWin32())
return GLFW_FALSE;
_glfw.win32.helperWindowHandle = createHelperWindow();
if (!_glfw.win32.helperWindowHandle)
return GLFW_FALSE;
_glfwInitTimerWin32();
_glfwInitJoysticksWin32();
_glfwPollMonitorsWin32();
return GLFW_TRUE;
}
void _glfwPlatformTerminate(void)
{
if (_glfw.win32.deviceNotificationHandle)
UnregisterDeviceNotification(_glfw.win32.deviceNotificationHandle);
if (_glfw.win32.helperWindowHandle)
DestroyWindow(_glfw.win32.helperWindowHandle);
_glfwUnregisterWindowClassWin32();
// Restore previous foreground lock timeout system setting
SystemParametersInfoW(SPI_SETFOREGROUNDLOCKTIMEOUT, 0,
UIntToPtr(_glfw.win32.foregroundLockTimeout),
SPIF_SENDCHANGE);
free(_glfw.win32.clipboardString);
free(_glfw.win32.rawInput);
_glfwTerminateWGL();
_glfwTerminateEGL();
_glfwTerminateJoysticksWin32();
freeLibraries();
}
const char* _glfwPlatformGetVersionString(void)
{
return _GLFW_VERSION_NUMBER " Win32 WGL EGL"
#if defined(__MINGW32__)
" MinGW"
#elif defined(_MSC_VER)
" VisualC"
#endif
#if defined(_GLFW_USE_HYBRID_HPG) || defined(_GLFW_USE_OPTIMUS_HPG)
" hybrid-GPU"
#endif
#if defined(_GLFW_BUILD_DLL)
" DLL"
#endif
;
}

751
glfw/win32_joystick.c vendored Normal file
View File

@@ -0,0 +1,751 @@
//========================================================================
// GLFW 3.3 Win32 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <stdio.h>
#include <math.h>
#define _GLFW_TYPE_AXIS 0
#define _GLFW_TYPE_SLIDER 1
#define _GLFW_TYPE_BUTTON 2
#define _GLFW_TYPE_POV 3
// Data produced with DirectInput device object enumeration
//
typedef struct _GLFWobjenumWin32
{
IDirectInputDevice8W* device;
_GLFWjoyobjectWin32* objects;
int objectCount;
int axisCount;
int sliderCount;
int buttonCount;
int povCount;
} _GLFWobjenumWin32;
// Define local copies of the necessary GUIDs
//
static const GUID _glfw_IID_IDirectInput8W =
{0xbf798031,0x483a,0x4da2,{0xaa,0x99,0x5d,0x64,0xed,0x36,0x97,0x00}};
static const GUID _glfw_GUID_XAxis =
{0xa36d02e0,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
static const GUID _glfw_GUID_YAxis =
{0xa36d02e1,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
static const GUID _glfw_GUID_ZAxis =
{0xa36d02e2,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
static const GUID _glfw_GUID_RxAxis =
{0xa36d02f4,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
static const GUID _glfw_GUID_RyAxis =
{0xa36d02f5,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
static const GUID _glfw_GUID_RzAxis =
{0xa36d02e3,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
static const GUID _glfw_GUID_Slider =
{0xa36d02e4,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
static const GUID _glfw_GUID_POV =
{0xa36d02f2,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
#define IID_IDirectInput8W _glfw_IID_IDirectInput8W
#define GUID_XAxis _glfw_GUID_XAxis
#define GUID_YAxis _glfw_GUID_YAxis
#define GUID_ZAxis _glfw_GUID_ZAxis
#define GUID_RxAxis _glfw_GUID_RxAxis
#define GUID_RyAxis _glfw_GUID_RyAxis
#define GUID_RzAxis _glfw_GUID_RzAxis
#define GUID_Slider _glfw_GUID_Slider
#define GUID_POV _glfw_GUID_POV
// Object data array for our clone of c_dfDIJoystick
// Generated with https://github.com/elmindreda/c_dfDIJoystick2
//
static DIOBJECTDATAFORMAT _glfwObjectDataFormats[] =
{
{ &GUID_XAxis,DIJOFS_X,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
{ &GUID_YAxis,DIJOFS_Y,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
{ &GUID_ZAxis,DIJOFS_Z,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
{ &GUID_RxAxis,DIJOFS_RX,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
{ &GUID_RyAxis,DIJOFS_RY,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
{ &GUID_RzAxis,DIJOFS_RZ,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
{ &GUID_Slider,DIJOFS_SLIDER(0),DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
{ &GUID_Slider,DIJOFS_SLIDER(1),DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
{ &GUID_POV,DIJOFS_POV(0),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ &GUID_POV,DIJOFS_POV(1),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ &GUID_POV,DIJOFS_POV(2),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ &GUID_POV,DIJOFS_POV(3),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(0),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(1),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(2),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(3),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(4),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(5),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(6),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(7),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(8),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(9),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(10),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(11),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(12),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(13),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(14),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(15),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(16),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(17),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(18),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(19),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(20),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(21),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(22),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(23),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(24),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(25),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(26),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(27),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(28),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(29),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(30),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
{ NULL,DIJOFS_BUTTON(31),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
};
// Our clone of c_dfDIJoystick
//
static const DIDATAFORMAT _glfwDataFormat =
{
sizeof(DIDATAFORMAT),
sizeof(DIOBJECTDATAFORMAT),
DIDFT_ABSAXIS,
sizeof(DIJOYSTATE),
sizeof(_glfwObjectDataFormats) / sizeof(DIOBJECTDATAFORMAT),
_glfwObjectDataFormats
};
// Returns a description fitting the specified XInput capabilities
//
static const char* getDeviceDescription(const XINPUT_CAPABILITIES* xic)
{
switch (xic->SubType)
{
case XINPUT_DEVSUBTYPE_WHEEL:
return "XInput Wheel";
case XINPUT_DEVSUBTYPE_ARCADE_STICK:
return "XInput Arcade Stick";
case XINPUT_DEVSUBTYPE_FLIGHT_STICK:
return "XInput Flight Stick";
case XINPUT_DEVSUBTYPE_DANCE_PAD:
return "XInput Dance Pad";
case XINPUT_DEVSUBTYPE_GUITAR:
return "XInput Guitar";
case XINPUT_DEVSUBTYPE_DRUM_KIT:
return "XInput Drum Kit";
case XINPUT_DEVSUBTYPE_GAMEPAD:
{
if (xic->Flags & XINPUT_CAPS_WIRELESS)
return "Wireless Xbox Controller";
else
return "Xbox Controller";
}
}
return "Unknown XInput Device";
}
// Lexically compare device objects
//
static int compareJoystickObjects(const void* first, const void* second)
{
const _GLFWjoyobjectWin32* fo = first;
const _GLFWjoyobjectWin32* so = second;
if (fo->type != so->type)
return fo->type - so->type;
return fo->offset - so->offset;
}
// Checks whether the specified device supports XInput
// Technique from FDInputJoystickManager::IsXInputDeviceFast in ZDoom
//
static GLFWbool supportsXInput(const GUID* guid)
{
UINT i, count = 0;
RAWINPUTDEVICELIST* ridl;
GLFWbool result = GLFW_FALSE;
if (GetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST)) != 0)
return GLFW_FALSE;
ridl = calloc(count, sizeof(RAWINPUTDEVICELIST));
if (GetRawInputDeviceList(ridl, &count, sizeof(RAWINPUTDEVICELIST)) == (UINT) -1)
{
free(ridl);
return GLFW_FALSE;
}
for (i = 0; i < count; i++)
{
RID_DEVICE_INFO rdi;
char name[256];
UINT size;
if (ridl[i].dwType != RIM_TYPEHID)
continue;
ZeroMemory(&rdi, sizeof(rdi));
rdi.cbSize = sizeof(rdi);
size = sizeof(rdi);
if ((INT) GetRawInputDeviceInfoA(ridl[i].hDevice,
RIDI_DEVICEINFO,
&rdi, &size) == -1)
{
continue;
}
if (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) != (LONG) guid->Data1)
continue;
memset(name, 0, sizeof(name));
size = sizeof(name);
if ((INT) GetRawInputDeviceInfoA(ridl[i].hDevice,
RIDI_DEVICENAME,
name, &size) == -1)
{
break;
}
name[sizeof(name) - 1] = '\0';
if (strstr(name, "IG_"))
{
result = GLFW_TRUE;
break;
}
}
free(ridl);
return result;
}
// Frees all resources associated with the specified joystick
//
static void closeJoystick(_GLFWjoystick* js)
{
if (js->win32.device)
{
IDirectInputDevice8_Unacquire(js->win32.device);
IDirectInputDevice8_Release(js->win32.device);
}
_glfwFreeJoystick(js);
_glfwInputJoystick(js, GLFW_DISCONNECTED);
}
// DirectInput device object enumeration callback
// Insights gleaned from SDL
//
static BOOL CALLBACK deviceObjectCallback(const DIDEVICEOBJECTINSTANCEW* doi,
void* user)
{
_GLFWobjenumWin32* data = user;
_GLFWjoyobjectWin32* object = data->objects + data->objectCount;
if (DIDFT_GETTYPE(doi->dwType) & DIDFT_AXIS)
{
DIPROPRANGE dipr;
if (memcmp(&doi->guidType, &GUID_Slider, sizeof(GUID)) == 0)
object->offset = DIJOFS_SLIDER(data->sliderCount);
else if (memcmp(&doi->guidType, &GUID_XAxis, sizeof(GUID)) == 0)
object->offset = DIJOFS_X;
else if (memcmp(&doi->guidType, &GUID_YAxis, sizeof(GUID)) == 0)
object->offset = DIJOFS_Y;
else if (memcmp(&doi->guidType, &GUID_ZAxis, sizeof(GUID)) == 0)
object->offset = DIJOFS_Z;
else if (memcmp(&doi->guidType, &GUID_RxAxis, sizeof(GUID)) == 0)
object->offset = DIJOFS_RX;
else if (memcmp(&doi->guidType, &GUID_RyAxis, sizeof(GUID)) == 0)
object->offset = DIJOFS_RY;
else if (memcmp(&doi->guidType, &GUID_RzAxis, sizeof(GUID)) == 0)
object->offset = DIJOFS_RZ;
else
return DIENUM_CONTINUE;
ZeroMemory(&dipr, sizeof(dipr));
dipr.diph.dwSize = sizeof(dipr);
dipr.diph.dwHeaderSize = sizeof(dipr.diph);
dipr.diph.dwObj = doi->dwType;
dipr.diph.dwHow = DIPH_BYID;
dipr.lMin = -32768;
dipr.lMax = 32767;
if (FAILED(IDirectInputDevice8_SetProperty(data->device,
DIPROP_RANGE,
&dipr.diph)))
{
return DIENUM_CONTINUE;
}
if (memcmp(&doi->guidType, &GUID_Slider, sizeof(GUID)) == 0)
{
object->type = _GLFW_TYPE_SLIDER;
data->sliderCount++;
}
else
{
object->type = _GLFW_TYPE_AXIS;
data->axisCount++;
}
}
else if (DIDFT_GETTYPE(doi->dwType) & DIDFT_BUTTON)
{
object->offset = DIJOFS_BUTTON(data->buttonCount);
object->type = _GLFW_TYPE_BUTTON;
data->buttonCount++;
}
else if (DIDFT_GETTYPE(doi->dwType) & DIDFT_POV)
{
object->offset = DIJOFS_POV(data->povCount);
object->type = _GLFW_TYPE_POV;
data->povCount++;
}
data->objectCount++;
return DIENUM_CONTINUE;
}
// DirectInput device enumeration callback
//
static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user)
{
int jid = 0;
DIDEVCAPS dc;
DIPROPDWORD dipd;
IDirectInputDevice8* device;
_GLFWobjenumWin32 data;
_GLFWjoystick* js;
char guid[33];
char name[256];
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
{
_GLFWjoystick* js = _glfw.joysticks + jid;
if (js->present)
{
if (memcmp(&js->win32.guid, &di->guidInstance, sizeof(GUID)) == 0)
return DIENUM_CONTINUE;
}
}
if (supportsXInput(&di->guidProduct))
return DIENUM_CONTINUE;
if (FAILED(IDirectInput8_CreateDevice(_glfw.win32.dinput8.api,
&di->guidInstance,
&device,
NULL)))
{
_glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create device");
return DIENUM_CONTINUE;
}
if (FAILED(IDirectInputDevice8_SetDataFormat(device, &_glfwDataFormat)))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Win32: Failed to set device data format");
IDirectInputDevice8_Release(device);
return DIENUM_CONTINUE;
}
ZeroMemory(&dc, sizeof(dc));
dc.dwSize = sizeof(dc);
if (FAILED(IDirectInputDevice8_GetCapabilities(device, &dc)))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Win32: Failed to query device capabilities");
IDirectInputDevice8_Release(device);
return DIENUM_CONTINUE;
}
ZeroMemory(&dipd, sizeof(dipd));
dipd.diph.dwSize = sizeof(dipd);
dipd.diph.dwHeaderSize = sizeof(dipd.diph);
dipd.diph.dwHow = DIPH_DEVICE;
dipd.dwData = DIPROPAXISMODE_ABS;
if (FAILED(IDirectInputDevice8_SetProperty(device,
DIPROP_AXISMODE,
&dipd.diph)))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Win32: Failed to set device axis mode");
IDirectInputDevice8_Release(device);
return DIENUM_CONTINUE;
}
memset(&data, 0, sizeof(data));
data.device = device;
data.objects = calloc(dc.dwAxes + dc.dwButtons + dc.dwPOVs,
sizeof(_GLFWjoyobjectWin32));
if (FAILED(IDirectInputDevice8_EnumObjects(device,
deviceObjectCallback,
&data,
DIDFT_AXIS | DIDFT_BUTTON | DIDFT_POV)))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Win32: Failed to enumerate device objects");
IDirectInputDevice8_Release(device);
free(data.objects);
return DIENUM_CONTINUE;
}
qsort(data.objects, data.objectCount,
sizeof(_GLFWjoyobjectWin32),
compareJoystickObjects);
if (!WideCharToMultiByte(CP_UTF8, 0,
di->tszInstanceName, -1,
name, sizeof(name),
NULL, NULL))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Win32: Failed to convert joystick name to UTF-8");
IDirectInputDevice8_Release(device);
free(data.objects);
return DIENUM_STOP;
}
// Generate a joystick GUID that matches the SDL 2.0.5+ one
if (memcmp(&di->guidProduct.Data4[2], "PIDVID", 6) == 0)
{
sprintf(guid, "03000000%02x%02x0000%02x%02x000000000000",
(uint8_t) di->guidProduct.Data1,
(uint8_t) (di->guidProduct.Data1 >> 8),
(uint8_t) (di->guidProduct.Data1 >> 16),
(uint8_t) (di->guidProduct.Data1 >> 24));
}
else
{
sprintf(guid, "05000000%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x00",
name[0], name[1], name[2], name[3],
name[4], name[5], name[6], name[7],
name[8], name[9], name[10]);
}
js = _glfwAllocJoystick(name, guid,
data.axisCount + data.sliderCount,
data.buttonCount,
data.povCount);
if (!js)
{
IDirectInputDevice8_Release(device);
free(data.objects);
return DIENUM_STOP;
}
js->win32.device = device;
js->win32.guid = di->guidInstance;
js->win32.objects = data.objects;
js->win32.objectCount = data.objectCount;
_glfwInputJoystick(js, GLFW_CONNECTED);
return DIENUM_CONTINUE;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
// Initialize joystick interface
//
void _glfwInitJoysticksWin32(void)
{
if (_glfw.win32.dinput8.instance)
{
if (FAILED(DirectInput8Create(GetModuleHandle(NULL),
DIRECTINPUT_VERSION,
&IID_IDirectInput8W,
(void**) &_glfw.win32.dinput8.api,
NULL)))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Win32: Failed to create interface");
}
}
_glfwDetectJoystickConnectionWin32();
}
// Close all opened joystick handles
//
void _glfwTerminateJoysticksWin32(void)
{
int jid;
for (jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; jid++)
closeJoystick(_glfw.joysticks + jid);
if (_glfw.win32.dinput8.api)
IDirectInput8_Release(_glfw.win32.dinput8.api);
}
// Checks for new joysticks after DBT_DEVICEARRIVAL
//
void _glfwDetectJoystickConnectionWin32(void)
{
if (_glfw.win32.xinput.instance)
{
DWORD index;
for (index = 0; index < XUSER_MAX_COUNT; index++)
{
int jid;
char guid[33];
XINPUT_CAPABILITIES xic;
_GLFWjoystick* js;
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
{
if (_glfw.joysticks[jid].present &&
_glfw.joysticks[jid].win32.device == NULL &&
_glfw.joysticks[jid].win32.index == index)
{
break;
}
}
if (jid <= GLFW_JOYSTICK_LAST)
continue;
if (XInputGetCapabilities(index, 0, &xic) != ERROR_SUCCESS)
continue;
// Generate a joystick GUID that matches the SDL 2.0.5+ one
sprintf(guid, "78696e707574%02x000000000000000000",
xic.SubType & 0xff);
js = _glfwAllocJoystick(getDeviceDescription(&xic), guid, 6, 10, 1);
if (!js)
continue;
js->win32.index = index;
_glfwInputJoystick(js, GLFW_CONNECTED);
}
}
if (_glfw.win32.dinput8.api)
{
if (FAILED(IDirectInput8_EnumDevices(_glfw.win32.dinput8.api,
DI8DEVCLASS_GAMECTRL,
deviceCallback,
NULL,
DIEDFL_ALLDEVICES)))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Failed to enumerate DirectInput8 devices");
return;
}
}
}
// Checks for joystick disconnection after DBT_DEVICEREMOVECOMPLETE
//
void _glfwDetectJoystickDisconnectionWin32(void)
{
int jid;
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
{
_GLFWjoystick* js = _glfw.joysticks + jid;
if (js->present)
_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE);
}
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode)
{
if (js->win32.device)
{
int i, ai = 0, bi = 0, pi = 0;
HRESULT result;
DIJOYSTATE state;
IDirectInputDevice8_Poll(js->win32.device);
result = IDirectInputDevice8_GetDeviceState(js->win32.device,
sizeof(state),
&state);
if (result == DIERR_NOTACQUIRED || result == DIERR_INPUTLOST)
{
IDirectInputDevice8_Acquire(js->win32.device);
IDirectInputDevice8_Poll(js->win32.device);
result = IDirectInputDevice8_GetDeviceState(js->win32.device,
sizeof(state),
&state);
}
if (FAILED(result))
{
closeJoystick(js);
return GLFW_FALSE;
}
if (mode == _GLFW_POLL_PRESENCE)
return GLFW_TRUE;
for (i = 0; i < js->win32.objectCount; i++)
{
const void* data = (char*) &state + js->win32.objects[i].offset;
switch (js->win32.objects[i].type)
{
case _GLFW_TYPE_AXIS:
case _GLFW_TYPE_SLIDER:
{
const float value = (*((LONG*) data) + 0.5f) / 32767.5f;
_glfwInputJoystickAxis(js, ai, value);
ai++;
break;
}
case _GLFW_TYPE_BUTTON:
{
const char value = (*((BYTE*) data) & 0x80) != 0;
_glfwInputJoystickButton(js, bi, value);
bi++;
break;
}
case _GLFW_TYPE_POV:
{
const int states[9] =
{
GLFW_HAT_UP,
GLFW_HAT_RIGHT_UP,
GLFW_HAT_RIGHT,
GLFW_HAT_RIGHT_DOWN,
GLFW_HAT_DOWN,
GLFW_HAT_LEFT_DOWN,
GLFW_HAT_LEFT,
GLFW_HAT_LEFT_UP,
GLFW_HAT_CENTERED
};
// Screams of horror are appropriate at this point
int state = LOWORD(*(DWORD*) data) / (45 * DI_DEGREES);
if (state < 0 || state > 8)
state = 8;
_glfwInputJoystickHat(js, pi, states[state]);
pi++;
break;
}
}
}
}
else
{
int i, dpad = 0;
DWORD result;
XINPUT_STATE xis;
const WORD buttons[10] =
{
XINPUT_GAMEPAD_A,
XINPUT_GAMEPAD_B,
XINPUT_GAMEPAD_X,
XINPUT_GAMEPAD_Y,
XINPUT_GAMEPAD_LEFT_SHOULDER,
XINPUT_GAMEPAD_RIGHT_SHOULDER,
XINPUT_GAMEPAD_BACK,
XINPUT_GAMEPAD_START,
XINPUT_GAMEPAD_LEFT_THUMB,
XINPUT_GAMEPAD_RIGHT_THUMB
};
result = XInputGetState(js->win32.index, &xis);
if (result != ERROR_SUCCESS)
{
if (result == ERROR_DEVICE_NOT_CONNECTED)
closeJoystick(js);
return GLFW_FALSE;
}
if (mode == _GLFW_POLL_PRESENCE)
return GLFW_TRUE;
_glfwInputJoystickAxis(js, 0, (xis.Gamepad.sThumbLX + 0.5f) / 32767.5f);
_glfwInputJoystickAxis(js, 1, -(xis.Gamepad.sThumbLY + 0.5f) / 32767.5f);
_glfwInputJoystickAxis(js, 2, (xis.Gamepad.sThumbRX + 0.5f) / 32767.5f);
_glfwInputJoystickAxis(js, 3, -(xis.Gamepad.sThumbRY + 0.5f) / 32767.5f);
_glfwInputJoystickAxis(js, 4, xis.Gamepad.bLeftTrigger / 127.5f - 1.f);
_glfwInputJoystickAxis(js, 5, xis.Gamepad.bRightTrigger / 127.5f - 1.f);
for (i = 0; i < 10; i++)
{
const char value = (xis.Gamepad.wButtons & buttons[i]) ? 1 : 0;
_glfwInputJoystickButton(js, i, value);
}
if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP)
dpad |= GLFW_HAT_UP;
if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT)
dpad |= GLFW_HAT_RIGHT;
if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN)
dpad |= GLFW_HAT_DOWN;
if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT)
dpad |= GLFW_HAT_LEFT;
_glfwInputJoystickHat(js, 0, dpad);
}
return GLFW_TRUE;
}
void _glfwPlatformUpdateGamepadGUID(char* guid)
{
if (strcmp(guid + 20, "504944564944") == 0)
{
char original[33];
strcpy(original, guid);
sprintf(guid, "03000000%.4s0000%.4s000000000000",
original, original + 4);
}
}

56
glfw/win32_joystick.h vendored Normal file
View File

@@ -0,0 +1,56 @@
//========================================================================
// GLFW 3.3 Win32 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickWin32 win32
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE int dummy
#define _GLFW_PLATFORM_MAPPING_NAME "Windows"
// Joystick element (axis, button or slider)
//
typedef struct _GLFWjoyobjectWin32
{
int offset;
int type;
} _GLFWjoyobjectWin32;
// Win32-specific per-joystick data
//
typedef struct _GLFWjoystickWin32
{
_GLFWjoyobjectWin32* objects;
int objectCount;
IDirectInputDevice8W* device;
DWORD index;
GUID guid;
} _GLFWjoystickWin32;
void _glfwInitJoysticksWin32(void);
void _glfwTerminateJoysticksWin32(void);
void _glfwDetectJoystickConnectionWin32(void);
void _glfwDetectJoystickDisconnectionWin32(void);

513
glfw/win32_monitor.c vendored Normal file
View File

@@ -0,0 +1,513 @@
//========================================================================
// GLFW 3.3 Win32 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <malloc.h>
// Callback for EnumDisplayMonitors in createMonitor
//
static BOOL CALLBACK monitorCallback(HMONITOR handle,
HDC dc,
RECT* rect,
LPARAM data)
{
MONITORINFOEXW mi;
ZeroMemory(&mi, sizeof(mi));
mi.cbSize = sizeof(mi);
if (GetMonitorInfoW(handle, (MONITORINFO*) &mi))
{
_GLFWmonitor* monitor = (_GLFWmonitor*) data;
if (wcscmp(mi.szDevice, monitor->win32.adapterName) == 0)
monitor->win32.handle = handle;
}
return TRUE;
}
// Create monitor from an adapter and (optionally) a display
//
static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter,
DISPLAY_DEVICEW* display)
{
_GLFWmonitor* monitor;
int widthMM, heightMM;
char* name;
HDC dc;
DEVMODEW dm;
RECT rect;
if (display)
name = _glfwCreateUTF8FromWideStringWin32(display->DeviceString);
else
name = _glfwCreateUTF8FromWideStringWin32(adapter->DeviceString);
if (!name)
return NULL;
ZeroMemory(&dm, sizeof(dm));
dm.dmSize = sizeof(dm);
EnumDisplaySettingsW(adapter->DeviceName, ENUM_CURRENT_SETTINGS, &dm);
dc = CreateDCW(L"DISPLAY", adapter->DeviceName, NULL, NULL);
if (IsWindows8Point1OrGreater())
{
widthMM = GetDeviceCaps(dc, HORZSIZE);
heightMM = GetDeviceCaps(dc, VERTSIZE);
}
else
{
widthMM = (int) (dm.dmPelsWidth * 25.4f / GetDeviceCaps(dc, LOGPIXELSX));
heightMM = (int) (dm.dmPelsHeight * 25.4f / GetDeviceCaps(dc, LOGPIXELSY));
}
DeleteDC(dc);
monitor = _glfwAllocMonitor(name, widthMM, heightMM);
free(name);
if (adapter->StateFlags & DISPLAY_DEVICE_MODESPRUNED)
monitor->win32.modesPruned = GLFW_TRUE;
wcscpy(monitor->win32.adapterName, adapter->DeviceName);
WideCharToMultiByte(CP_UTF8, 0,
adapter->DeviceName, -1,
monitor->win32.publicAdapterName,
sizeof(monitor->win32.publicAdapterName),
NULL, NULL);
if (display)
{
wcscpy(monitor->win32.displayName, display->DeviceName);
WideCharToMultiByte(CP_UTF8, 0,
display->DeviceName, -1,
monitor->win32.publicDisplayName,
sizeof(monitor->win32.publicDisplayName),
NULL, NULL);
}
rect.left = dm.dmPosition.x;
rect.top = dm.dmPosition.y;
rect.right = dm.dmPosition.x + dm.dmPelsWidth;
rect.bottom = dm.dmPosition.y + dm.dmPelsHeight;
EnumDisplayMonitors(NULL, &rect, monitorCallback, (LPARAM) monitor);
return monitor;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
// Poll for changes in the set of connected monitors
//
void _glfwPollMonitorsWin32(void)
{
int i, disconnectedCount;
_GLFWmonitor** disconnected = NULL;
DWORD adapterIndex, displayIndex;
DISPLAY_DEVICEW adapter, display;
_GLFWmonitor* monitor;
disconnectedCount = _glfw.monitorCount;
if (disconnectedCount)
{
disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*));
memcpy(disconnected,
_glfw.monitors,
_glfw.monitorCount * sizeof(_GLFWmonitor*));
}
for (adapterIndex = 0; ; adapterIndex++)
{
int type = _GLFW_INSERT_LAST;
ZeroMemory(&adapter, sizeof(adapter));
adapter.cb = sizeof(adapter);
if (!EnumDisplayDevicesW(NULL, adapterIndex, &adapter, 0))
break;
if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE))
continue;
if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
type = _GLFW_INSERT_FIRST;
for (displayIndex = 0; ; displayIndex++)
{
ZeroMemory(&display, sizeof(display));
display.cb = sizeof(display);
if (!EnumDisplayDevicesW(adapter.DeviceName, displayIndex, &display, 0))
break;
if (!(display.StateFlags & DISPLAY_DEVICE_ACTIVE))
continue;
for (i = 0; i < disconnectedCount; i++)
{
if (disconnected[i] &&
wcscmp(disconnected[i]->win32.displayName,
display.DeviceName) == 0)
{
disconnected[i] = NULL;
break;
}
}
if (i < disconnectedCount)
continue;
monitor = createMonitor(&adapter, &display);
if (!monitor)
{
free(disconnected);
return;
}
_glfwInputMonitor(monitor, GLFW_CONNECTED, type);
type = _GLFW_INSERT_LAST;
}
// HACK: If an active adapter does not have any display devices
// (as sometimes happens), add it directly as a monitor
if (displayIndex == 0)
{
for (i = 0; i < disconnectedCount; i++)
{
if (disconnected[i] &&
wcscmp(disconnected[i]->win32.adapterName,
adapter.DeviceName) == 0)
{
disconnected[i] = NULL;
break;
}
}
if (i < disconnectedCount)
continue;
monitor = createMonitor(&adapter, NULL);
if (!monitor)
{
free(disconnected);
return;
}
_glfwInputMonitor(monitor, GLFW_CONNECTED, type);
}
}
for (i = 0; i < disconnectedCount; i++)
{
if (disconnected[i])
_glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0);
}
free(disconnected);
}
// Change the current video mode
//
void _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired)
{
GLFWvidmode current;
const GLFWvidmode* best;
DEVMODEW dm;
LONG result;
best = _glfwChooseVideoMode(monitor, desired);
_glfwPlatformGetVideoMode(monitor, &current);
if (_glfwCompareVideoModes(&current, best) == 0)
return;
ZeroMemory(&dm, sizeof(dm));
dm.dmSize = sizeof(dm);
dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL |
DM_DISPLAYFREQUENCY;
dm.dmPelsWidth = best->width;
dm.dmPelsHeight = best->height;
dm.dmBitsPerPel = best->redBits + best->greenBits + best->blueBits;
dm.dmDisplayFrequency = best->refreshRate;
if (dm.dmBitsPerPel < 15 || dm.dmBitsPerPel >= 24)
dm.dmBitsPerPel = 32;
result = ChangeDisplaySettingsExW(monitor->win32.adapterName,
&dm,
NULL,
CDS_FULLSCREEN,
NULL);
if (result == DISP_CHANGE_SUCCESSFUL)
monitor->win32.modeChanged = GLFW_TRUE;
else
{
const char* description = "Unknown error";
if (result == DISP_CHANGE_BADDUALVIEW)
description = "The system uses DualView";
else if (result == DISP_CHANGE_BADFLAGS)
description = "Invalid flags";
else if (result == DISP_CHANGE_BADMODE)
description = "Graphics mode not supported";
else if (result == DISP_CHANGE_BADPARAM)
description = "Invalid parameter";
else if (result == DISP_CHANGE_FAILED)
description = "Graphics mode failed";
else if (result == DISP_CHANGE_NOTUPDATED)
description = "Failed to write to registry";
else if (result == DISP_CHANGE_RESTART)
description = "Computer restart required";
_glfwInputError(GLFW_PLATFORM_ERROR,
"Win32: Failed to set video mode: %s",
description);
}
}
// Restore the previously saved (original) video mode
//
void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor)
{
if (monitor->win32.modeChanged)
{
ChangeDisplaySettingsExW(monitor->win32.adapterName,
NULL, NULL, CDS_FULLSCREEN, NULL);
monitor->win32.modeChanged = GLFW_FALSE;
}
}
void _glfwGetMonitorContentScaleWin32(HMONITOR handle, float* xscale, float* yscale)
{
UINT xdpi, ydpi;
if (IsWindows8Point1OrGreater())
GetDpiForMonitor(handle, MDT_EFFECTIVE_DPI, &xdpi, &ydpi);
else
{
const HDC dc = GetDC(NULL);
xdpi = GetDeviceCaps(dc, LOGPIXELSX);
ydpi = GetDeviceCaps(dc, LOGPIXELSY);
ReleaseDC(NULL, dc);
}
if (xscale)
*xscale = xdpi / 96.f;
if (yscale)
*yscale = ydpi / 96.f;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
{
}
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
{
DEVMODEW dm;
ZeroMemory(&dm, sizeof(dm));
dm.dmSize = sizeof(dm);
EnumDisplaySettingsExW(monitor->win32.adapterName,
ENUM_CURRENT_SETTINGS,
&dm,
EDS_ROTATEDMODE);
if (xpos)
*xpos = dm.dmPosition.x;
if (ypos)
*ypos = dm.dmPosition.y;
}
void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
float* xscale, float* yscale)
{
_glfwGetMonitorContentScaleWin32(monitor->win32.handle, xscale, yscale);
}
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
{
int modeIndex = 0, size = 0;
GLFWvidmode* result = NULL;
*count = 0;
for (;;)
{
int i;
GLFWvidmode mode;
DEVMODEW dm;
ZeroMemory(&dm, sizeof(dm));
dm.dmSize = sizeof(dm);
if (!EnumDisplaySettingsW(monitor->win32.adapterName, modeIndex, &dm))
break;
modeIndex++;
// Skip modes with less than 15 BPP
if (dm.dmBitsPerPel < 15)
continue;
mode.width = dm.dmPelsWidth;
mode.height = dm.dmPelsHeight;
mode.refreshRate = dm.dmDisplayFrequency;
_glfwSplitBPP(dm.dmBitsPerPel,
&mode.redBits,
&mode.greenBits,
&mode.blueBits);
for (i = 0; i < *count; i++)
{
if (_glfwCompareVideoModes(result + i, &mode) == 0)
break;
}
// Skip duplicate modes
if (i < *count)
continue;
if (monitor->win32.modesPruned)
{
// Skip modes not supported by the connected displays
if (ChangeDisplaySettingsExW(monitor->win32.adapterName,
&dm,
NULL,
CDS_TEST,
NULL) != DISP_CHANGE_SUCCESSFUL)
{
continue;
}
}
if (*count == size)
{
size += 128;
result = (GLFWvidmode*) realloc(result, size * sizeof(GLFWvidmode));
}
(*count)++;
result[*count - 1] = mode;
}
if (!*count)
{
// HACK: Report the current mode if no valid modes were found
result = calloc(1, sizeof(GLFWvidmode));
_glfwPlatformGetVideoMode(monitor, result);
*count = 1;
}
return result;
}
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
{
DEVMODEW dm;
ZeroMemory(&dm, sizeof(dm));
dm.dmSize = sizeof(dm);
EnumDisplaySettingsW(monitor->win32.adapterName, ENUM_CURRENT_SETTINGS, &dm);
mode->width = dm.dmPelsWidth;
mode->height = dm.dmPelsHeight;
mode->refreshRate = dm.dmDisplayFrequency;
_glfwSplitBPP(dm.dmBitsPerPel,
&mode->redBits,
&mode->greenBits,
&mode->blueBits);
}
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{
HDC dc;
WORD values[768];
dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);
GetDeviceGammaRamp(dc, values);
DeleteDC(dc);
_glfwAllocGammaArrays(ramp, 256);
memcpy(ramp->red, values + 0, 256 * sizeof(unsigned short));
memcpy(ramp->green, values + 256, 256 * sizeof(unsigned short));
memcpy(ramp->blue, values + 512, 256 * sizeof(unsigned short));
}
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
{
HDC dc;
WORD values[768];
if (ramp->size != 256)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Win32: Gamma ramp size must be 256");
return;
}
memcpy(values + 0, ramp->red, 256 * sizeof(unsigned short));
memcpy(values + 256, ramp->green, 256 * sizeof(unsigned short));
memcpy(values + 512, ramp->blue, 256 * sizeof(unsigned short));
dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);
SetDeviceGammaRamp(dc, values);
DeleteDC(dc);
}
//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////
//////////////////////////////////////////////////////////////////////////
GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* handle)
{
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
return monitor->win32.publicAdapterName;
}
GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* handle)
{
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
return monitor->win32.publicDisplayName;
}

404
glfw/win32_platform.h vendored Normal file
View File

@@ -0,0 +1,404 @@
//========================================================================
// GLFW 3.3 Win32 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
// We don't need all the fancy stuff
#ifndef NOMINMAX
#define NOMINMAX
#endif
#ifndef VC_EXTRALEAN
#define VC_EXTRALEAN
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
// This is a workaround for the fact that glfw3.h needs to export APIENTRY (for
// example to allow applications to correctly declare a GL_ARB_debug_output
// callback) but windows.h assumes no one will define APIENTRY before it does
#undef APIENTRY
// GLFW on Windows is Unicode only and does not work in MBCS mode
#ifndef UNICODE
#define UNICODE
#endif
// GLFW requires Windows XP or later
#if WINVER < 0x0501
#undef WINVER
#define WINVER 0x0501
#endif
#if _WIN32_WINNT < 0x0501
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#endif
// GLFW uses DirectInput8 interfaces
#define DIRECTINPUT_VERSION 0x0800
#include <wctype.h>
#include <windows.h>
#include <dinput.h>
#include <xinput.h>
#include <dbt.h>
// HACK: Define macros that some windows.h variants don't
#ifndef WM_MOUSEHWHEEL
#define WM_MOUSEHWHEEL 0x020E
#endif
#ifndef WM_DWMCOMPOSITIONCHANGED
#define WM_DWMCOMPOSITIONCHANGED 0x031E
#endif
#ifndef WM_COPYGLOBALDATA
#define WM_COPYGLOBALDATA 0x0049
#endif
#ifndef WM_UNICHAR
#define WM_UNICHAR 0x0109
#endif
#ifndef UNICODE_NOCHAR
#define UNICODE_NOCHAR 0xFFFF
#endif
#ifndef WM_DPICHANGED
#define WM_DPICHANGED 0x02E0
#endif
#ifndef GET_XBUTTON_WPARAM
#define GET_XBUTTON_WPARAM(w) (HIWORD(w))
#endif
#ifndef EDS_ROTATEDMODE
#define EDS_ROTATEDMODE 0x00000004
#endif
#ifndef DISPLAY_DEVICE_ACTIVE
#define DISPLAY_DEVICE_ACTIVE 0x00000001
#endif
#ifndef _WIN32_WINNT_WINBLUE
#define _WIN32_WINNT_WINBLUE 0x0602
#endif
#if WINVER < 0x0601
typedef struct
{
DWORD cbSize;
DWORD ExtStatus;
} CHANGEFILTERSTRUCT;
#ifndef MSGFLT_ALLOW
#define MSGFLT_ALLOW 1
#endif
#endif /*Windows 7*/
#if WINVER < 0x0600
#define DWM_BB_ENABLE 0x00000001
#define DWM_BB_BLURREGION 0x00000002
typedef struct
{
DWORD dwFlags;
BOOL fEnable;
HRGN hRgnBlur;
BOOL fTransitionOnMaximized;
} DWM_BLURBEHIND;
#endif /*Windows Vista*/
#ifndef DPI_ENUMS_DECLARED
typedef enum
{
PROCESS_DPI_UNAWARE = 0,
PROCESS_SYSTEM_DPI_AWARE = 1,
PROCESS_PER_MONITOR_DPI_AWARE = 2
} PROCESS_DPI_AWARENESS;
typedef enum
{
MDT_EFFECTIVE_DPI = 0,
MDT_ANGULAR_DPI = 1,
MDT_RAW_DPI = 2,
MDT_DEFAULT = MDT_EFFECTIVE_DPI
} MONITOR_DPI_TYPE;
#endif /*DPI_ENUMS_DECLARED*/
// HACK: Define versionhelpers.h functions manually as MinGW lacks the header
BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp);
#define IsWindowsVistaOrGreater() \
IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), \
LOBYTE(_WIN32_WINNT_VISTA), 0)
#define IsWindows7OrGreater() \
IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), \
LOBYTE(_WIN32_WINNT_WIN7), 0)
#define IsWindows8OrGreater() \
IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), \
LOBYTE(_WIN32_WINNT_WIN8), 0)
#define IsWindows8Point1OrGreater() \
IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINBLUE), \
LOBYTE(_WIN32_WINNT_WINBLUE), 0)
// HACK: Define macros that some xinput.h variants don't
#ifndef XINPUT_CAPS_WIRELESS
#define XINPUT_CAPS_WIRELESS 0x0002
#endif
#ifndef XINPUT_DEVSUBTYPE_WHEEL
#define XINPUT_DEVSUBTYPE_WHEEL 0x02
#endif
#ifndef XINPUT_DEVSUBTYPE_ARCADE_STICK
#define XINPUT_DEVSUBTYPE_ARCADE_STICK 0x03
#endif
#ifndef XINPUT_DEVSUBTYPE_FLIGHT_STICK
#define XINPUT_DEVSUBTYPE_FLIGHT_STICK 0x04
#endif
#ifndef XINPUT_DEVSUBTYPE_DANCE_PAD
#define XINPUT_DEVSUBTYPE_DANCE_PAD 0x05
#endif
#ifndef XINPUT_DEVSUBTYPE_GUITAR
#define XINPUT_DEVSUBTYPE_GUITAR 0x06
#endif
#ifndef XINPUT_DEVSUBTYPE_DRUM_KIT
#define XINPUT_DEVSUBTYPE_DRUM_KIT 0x08
#endif
#ifndef XINPUT_DEVSUBTYPE_ARCADE_PAD
#define XINPUT_DEVSUBTYPE_ARCADE_PAD 0x13
#endif
#ifndef XUSER_MAX_COUNT
#define XUSER_MAX_COUNT 4
#endif
// HACK: Define macros that some dinput.h variants don't
#ifndef DIDFT_OPTIONAL
#define DIDFT_OPTIONAL 0x80000000
#endif
// winmm.dll function pointer typedefs
typedef DWORD (WINAPI * PFN_timeGetTime)(void);
#define timeGetTime _glfw.win32.winmm.GetTime
// xinput.dll function pointer typedefs
typedef DWORD (WINAPI * PFN_XInputGetCapabilities)(DWORD,DWORD,XINPUT_CAPABILITIES*);
typedef DWORD (WINAPI * PFN_XInputGetState)(DWORD,XINPUT_STATE*);
#define XInputGetCapabilities _glfw.win32.xinput.GetCapabilities
#define XInputGetState _glfw.win32.xinput.GetState
// dinput8.dll function pointer typedefs
typedef HRESULT (WINAPI * PFN_DirectInput8Create)(HINSTANCE,DWORD,REFIID,LPVOID*,LPUNKNOWN);
#define DirectInput8Create _glfw.win32.dinput8.Create
// user32.dll function pointer typedefs
typedef BOOL (WINAPI * PFN_SetProcessDPIAware)(void);
typedef BOOL (WINAPI * PFN_ChangeWindowMessageFilterEx)(HWND,UINT,DWORD,CHANGEFILTERSTRUCT*);
#define SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware_
#define ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx_
// dwmapi.dll function pointer typedefs
typedef HRESULT (WINAPI * PFN_DwmIsCompositionEnabled)(BOOL*);
typedef HRESULT (WINAPI * PFN_DwmFlush)(VOID);
typedef HRESULT(WINAPI * PFN_DwmEnableBlurBehindWindow)(HWND,const DWM_BLURBEHIND*);
#define DwmIsCompositionEnabled _glfw.win32.dwmapi.IsCompositionEnabled
#define DwmFlush _glfw.win32.dwmapi.Flush
#define DwmEnableBlurBehindWindow _glfw.win32.dwmapi.EnableBlurBehindWindow
// shcore.dll function pointer typedefs
typedef HRESULT (WINAPI * PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS);
typedef HRESULT (WINAPI * PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*,UINT*);
#define SetProcessDpiAwareness _glfw.win32.shcore.SetProcessDpiAwareness_
#define GetDpiForMonitor _glfw.win32.shcore.GetDpiForMonitor_
typedef VkFlags VkWin32SurfaceCreateFlagsKHR;
typedef struct VkWin32SurfaceCreateInfoKHR
{
VkStructureType sType;
const void* pNext;
VkWin32SurfaceCreateFlagsKHR flags;
HINSTANCE hinstance;
HWND hwnd;
} VkWin32SurfaceCreateInfoKHR;
typedef VkResult (APIENTRY *PFN_vkCreateWin32SurfaceKHR)(VkInstance,const VkWin32SurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*);
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice,uint32_t);
#include "win32_joystick.h"
#include "wgl_context.h"
#include "egl_context.h"
#include "osmesa_context.h"
#define _GLFW_WNDCLASSNAME L"GLFW30"
#define _glfw_dlopen(name) LoadLibraryA(name)
#define _glfw_dlclose(handle) FreeLibrary((HMODULE) handle)
#define _glfw_dlsym(handle, name) GetProcAddress((HMODULE) handle, name)
#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->win32.handle)
#define _GLFW_EGL_NATIVE_DISPLAY EGL_DEFAULT_DISPLAY
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWin32 win32
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWin32 win32
#define _GLFW_PLATFORM_LIBRARY_TIMER_STATE _GLFWtimerWin32 win32
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWin32 win32
#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorWin32 win32
#define _GLFW_PLATFORM_TLS_STATE _GLFWtlsWin32 win32
#define _GLFW_PLATFORM_MUTEX_STATE _GLFWmutexWin32 win32
// Win32-specific per-window data
//
typedef struct _GLFWwindowWin32
{
HWND handle;
HICON bigIcon;
HICON smallIcon;
GLFWbool cursorTracked;
GLFWbool frameAction;
GLFWbool iconified;
GLFWbool maximized;
// Whether to enable framebuffer transparency on DWM
GLFWbool transparent;
// The last received cursor position, regardless of source
int lastCursorPosX, lastCursorPosY;
} _GLFWwindowWin32;
// Win32-specific global data
//
typedef struct _GLFWlibraryWin32
{
HWND helperWindowHandle;
HDEVNOTIFY deviceNotificationHandle;
DWORD foregroundLockTimeout;
int acquiredMonitorCount;
char* clipboardString;
short int keycodes[512];
short int scancodes[GLFW_KEY_LAST + 1];
char keynames[GLFW_KEY_LAST + 1][5];
// Where to place the cursor when re-enabled
double restoreCursorPosX, restoreCursorPosY;
// The window whose disabled cursor mode is active
_GLFWwindow* disabledCursorWindow;
RAWINPUT* rawInput;
int rawInputSize;
struct {
HINSTANCE instance;
PFN_timeGetTime GetTime;
} winmm;
struct {
HINSTANCE instance;
PFN_DirectInput8Create Create;
IDirectInput8W* api;
} dinput8;
struct {
HINSTANCE instance;
PFN_XInputGetCapabilities GetCapabilities;
PFN_XInputGetState GetState;
} xinput;
struct {
HINSTANCE instance;
PFN_SetProcessDPIAware SetProcessDPIAware_;
PFN_ChangeWindowMessageFilterEx ChangeWindowMessageFilterEx_;
} user32;
struct {
HINSTANCE instance;
PFN_DwmIsCompositionEnabled IsCompositionEnabled;
PFN_DwmFlush Flush;
PFN_DwmEnableBlurBehindWindow EnableBlurBehindWindow;
} dwmapi;
struct {
HINSTANCE instance;
PFN_SetProcessDpiAwareness SetProcessDpiAwareness_;
PFN_GetDpiForMonitor GetDpiForMonitor_;
} shcore;
} _GLFWlibraryWin32;
// Win32-specific per-monitor data
//
typedef struct _GLFWmonitorWin32
{
HMONITOR handle;
// This size matches the static size of DISPLAY_DEVICE.DeviceName
WCHAR adapterName[32];
WCHAR displayName[32];
char publicAdapterName[32];
char publicDisplayName[32];
GLFWbool modesPruned;
GLFWbool modeChanged;
} _GLFWmonitorWin32;
// Win32-specific per-cursor data
//
typedef struct _GLFWcursorWin32
{
HCURSOR handle;
} _GLFWcursorWin32;
// Win32-specific global timer data
//
typedef struct _GLFWtimerWin32
{
GLFWbool hasPC;
uint64_t frequency;
} _GLFWtimerWin32;
// Win32-specific thread local storage data
//
typedef struct _GLFWtlsWin32
{
GLFWbool allocated;
DWORD index;
} _GLFWtlsWin32;
// Win32-specific mutex data
//
typedef struct _GLFWmutexWin32
{
GLFWbool allocated;
CRITICAL_SECTION section;
} _GLFWmutexWin32;
GLFWbool _glfwRegisterWindowClassWin32(void);
void _glfwUnregisterWindowClassWin32(void);
GLFWbool _glfwIsCompositionEnabledWin32(void);
WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source);
char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source);
void _glfwInputErrorWin32(int error, const char* description);
void _glfwUpdateKeyNamesWin32(void);
void _glfwInitTimerWin32(void);
void _glfwPollMonitorsWin32(void);
void _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired);
void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor);
void _glfwGetMonitorContentScaleWin32(HMONITOR handle, float* xscale, float* yscale);

97
glfw/win32_thread.c vendored Normal file
View File

@@ -0,0 +1,97 @@
//========================================================================
// GLFW 3.3 Win32 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <assert.h>
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls)
{
assert(tls->win32.allocated == GLFW_FALSE);
tls->win32.index = TlsAlloc();
if (tls->win32.index == TLS_OUT_OF_INDEXES)
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"Win32: Failed to allocate TLS index");
return GLFW_FALSE;
}
tls->win32.allocated = GLFW_TRUE;
return GLFW_TRUE;
}
void _glfwPlatformDestroyTls(_GLFWtls* tls)
{
if (tls->win32.allocated)
TlsFree(tls->win32.index);
memset(tls, 0, sizeof(_GLFWtls));
}
void* _glfwPlatformGetTls(_GLFWtls* tls)
{
assert(tls->win32.allocated == GLFW_TRUE);
return TlsGetValue(tls->win32.index);
}
void _glfwPlatformSetTls(_GLFWtls* tls, void* value)
{
assert(tls->win32.allocated == GLFW_TRUE);
TlsSetValue(tls->win32.index, value);
}
GLFWbool _glfwPlatformCreateMutex(_GLFWmutex* mutex)
{
assert(mutex->win32.allocated == GLFW_FALSE);
InitializeCriticalSection(&mutex->win32.section);
return mutex->win32.allocated = GLFW_TRUE;
}
void _glfwPlatformDestroyMutex(_GLFWmutex* mutex)
{
if (mutex->win32.allocated)
DeleteCriticalSection(&mutex->win32.section);
memset(mutex, 0, sizeof(_GLFWmutex));
}
void _glfwPlatformLockMutex(_GLFWmutex* mutex)
{
assert(mutex->win32.allocated == GLFW_TRUE);
EnterCriticalSection(&mutex->win32.section);
}
void _glfwPlatformUnlockMutex(_GLFWmutex* mutex)
{
assert(mutex->win32.allocated == GLFW_TRUE);
LeaveCriticalSection(&mutex->win32.section);
}

74
glfw/win32_time.c vendored Normal file
View File

@@ -0,0 +1,74 @@
//========================================================================
// GLFW 3.3 Win32 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
// Initialise timer
//
void _glfwInitTimerWin32(void)
{
uint64_t frequency;
if (QueryPerformanceFrequency((LARGE_INTEGER*) &frequency))
{
_glfw.timer.win32.hasPC = GLFW_TRUE;
_glfw.timer.win32.frequency = frequency;
}
else
{
_glfw.timer.win32.hasPC = GLFW_FALSE;
_glfw.timer.win32.frequency = 1000;
}
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
uint64_t _glfwPlatformGetTimerValue(void)
{
if (_glfw.timer.win32.hasPC)
{
uint64_t value;
QueryPerformanceCounter((LARGE_INTEGER*) &value);
return value;
}
else
return (uint64_t) timeGetTime();
}
uint64_t _glfwPlatformGetTimerFrequency(void)
{
return _glfw.timer.win32.frequency;
}

2016
glfw/win32_window.c vendored Normal file

File diff suppressed because it is too large Load Diff

1108
glfw/window.c vendored Normal file

File diff suppressed because it is too large Load Diff

828
glfw/wl_init.c vendored Normal file
View File

@@ -0,0 +1,828 @@
//========================================================================
// GLFW 3.3 Wayland - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <assert.h>
#include <linux/input.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <wayland-client.h>
static inline int min(int n1, int n2)
{
return n1 < n2 ? n1 : n2;
}
static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface, int* which)
{
int focus;
_GLFWwindow* window = _glfw.windowListHead;
if (!which)
which = &focus;
while (window)
{
if (surface == window->wl.decorations.top.surface)
{
*which = topDecoration;
break;
}
if (surface == window->wl.decorations.left.surface)
{
*which = leftDecoration;
break;
}
if (surface == window->wl.decorations.right.surface)
{
*which = rightDecoration;
break;
}
if (surface == window->wl.decorations.bottom.surface)
{
*which = bottomDecoration;
break;
}
window = window->next;
}
return window;
}
static void pointerHandleEnter(void* data,
struct wl_pointer* pointer,
uint32_t serial,
struct wl_surface* surface,
wl_fixed_t sx,
wl_fixed_t sy)
{
// Happens in the case we just destroyed the surface.
if (!surface)
return;
int focus = 0;
_GLFWwindow* window = wl_surface_get_user_data(surface);
if (!window)
{
window = findWindowFromDecorationSurface(surface, &focus);
if (!window)
return;
}
window->wl.decorations.focus = focus;
_glfw.wl.pointerSerial = serial;
_glfw.wl.pointerFocus = window;
window->wl.hovered = GLFW_TRUE;
_glfwPlatformSetCursor(window, window->wl.currentCursor);
_glfwInputCursorEnter(window, GLFW_TRUE);
}
static void pointerHandleLeave(void* data,
struct wl_pointer* pointer,
uint32_t serial,
struct wl_surface* surface)
{
_GLFWwindow* window = _glfw.wl.pointerFocus;
if (!window)
return;
window->wl.hovered = GLFW_FALSE;
_glfw.wl.pointerSerial = serial;
_glfw.wl.pointerFocus = NULL;
_glfwInputCursorEnter(window, GLFW_FALSE);
}
static void setCursor(const char* name)
{
struct wl_buffer* buffer;
struct wl_cursor* cursor;
struct wl_cursor_image* image;
struct wl_surface* surface = _glfw.wl.cursorSurface;
cursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme,
name);
if (!cursor)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Standard cursor not found");
return;
}
image = cursor->images[0];
if (!image)
return;
buffer = wl_cursor_image_get_buffer(image);
if (!buffer)
return;
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial,
surface,
image->hotspot_x,
image->hotspot_y);
wl_surface_attach(surface, buffer, 0, 0);
wl_surface_damage(surface, 0, 0,
image->width, image->height);
wl_surface_commit(surface);
}
static void pointerHandleMotion(void* data,
struct wl_pointer* pointer,
uint32_t time,
wl_fixed_t sx,
wl_fixed_t sy)
{
_GLFWwindow* window = _glfw.wl.pointerFocus;
const char* cursorName;
if (!window)
return;
if (window->cursorMode == GLFW_CURSOR_DISABLED)
return;
else
{
window->wl.cursorPosX = wl_fixed_to_double(sx);
window->wl.cursorPosY = wl_fixed_to_double(sy);
}
switch (window->wl.decorations.focus)
{
case mainWindow:
_glfwInputCursorPos(window,
wl_fixed_to_double(sx),
wl_fixed_to_double(sy));
return;
case topDecoration:
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
cursorName = "n-resize";
else
cursorName = "left_ptr";
break;
case leftDecoration:
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
cursorName = "nw-resize";
else
cursorName = "w-resize";
break;
case rightDecoration:
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
cursorName = "ne-resize";
else
cursorName = "e-resize";
break;
case bottomDecoration:
if (window->wl.cursorPosX < _GLFW_DECORATION_WIDTH)
cursorName = "sw-resize";
else if (window->wl.cursorPosX > window->wl.width + _GLFW_DECORATION_WIDTH)
cursorName = "se-resize";
else
cursorName = "s-resize";
break;
default:
assert(0);
}
setCursor(cursorName);
}
static void pointerHandleButton(void* data,
struct wl_pointer* pointer,
uint32_t serial,
uint32_t time,
uint32_t button,
uint32_t state)
{
_GLFWwindow* window = _glfw.wl.pointerFocus;
int glfwButton;
// Both xdg-shell and wl_shell use the same values.
uint32_t edges = WL_SHELL_SURFACE_RESIZE_NONE;
if (!window)
return;
if (button == BTN_LEFT)
{
switch (window->wl.decorations.focus)
{
case mainWindow:
break;
case topDecoration:
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
edges = WL_SHELL_SURFACE_RESIZE_TOP;
else
{
if (window->wl.xdg.toplevel)
xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial);
else
wl_shell_surface_move(window->wl.shellSurface, _glfw.wl.seat, serial);
}
break;
case leftDecoration:
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
edges = WL_SHELL_SURFACE_RESIZE_TOP_LEFT;
else
edges = WL_SHELL_SURFACE_RESIZE_LEFT;
break;
case rightDecoration:
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
edges = WL_SHELL_SURFACE_RESIZE_TOP_RIGHT;
else
edges = WL_SHELL_SURFACE_RESIZE_RIGHT;
break;
case bottomDecoration:
if (window->wl.cursorPosX < _GLFW_DECORATION_WIDTH)
edges = WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT;
else if (window->wl.cursorPosX > window->wl.width + _GLFW_DECORATION_WIDTH)
edges = WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT;
else
edges = WL_SHELL_SURFACE_RESIZE_BOTTOM;
break;
default:
assert(0);
}
if (edges != WL_SHELL_SURFACE_RESIZE_NONE)
{
if (window->wl.xdg.toplevel)
xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat,
serial, edges);
else
wl_shell_surface_resize(window->wl.shellSurface, _glfw.wl.seat,
serial, edges);
}
}
else if (button == BTN_RIGHT)
{
if (window->wl.decorations.focus != mainWindow && window->wl.xdg.toplevel)
{
xdg_toplevel_show_window_menu(window->wl.xdg.toplevel,
_glfw.wl.seat, serial,
window->wl.cursorPosX,
window->wl.cursorPosY);
return;
}
}
// Dont pass the button to the user if it was related to a decoration.
if (window->wl.decorations.focus != mainWindow)
return;
_glfw.wl.pointerSerial = serial;
/* Makes left, right and middle 0, 1 and 2. Overall order follows evdev
* codes. */
glfwButton = button - BTN_LEFT;
_glfwInputMouseClick(window,
glfwButton,
state == WL_POINTER_BUTTON_STATE_PRESSED
? GLFW_PRESS
: GLFW_RELEASE,
_glfw.wl.xkb.modifiers);
}
static void pointerHandleAxis(void* data,
struct wl_pointer* pointer,
uint32_t time,
uint32_t axis,
wl_fixed_t value)
{
_GLFWwindow* window = _glfw.wl.pointerFocus;
double x = 0.0, y = 0.0;
// Wayland scroll events are in pointer motion coordinate space (think two
// finger scroll). The factor 10 is commonly used to convert to "scroll
// step means 1.0.
const double scrollFactor = 1.0 / 10.0;
if (!window)
return;
assert(axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL ||
axis == WL_POINTER_AXIS_VERTICAL_SCROLL);
if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
x = wl_fixed_to_double(value) * scrollFactor;
else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
y = wl_fixed_to_double(value) * scrollFactor;
_glfwInputScroll(window, x, y);
}
static const struct wl_pointer_listener pointerListener = {
pointerHandleEnter,
pointerHandleLeave,
pointerHandleMotion,
pointerHandleButton,
pointerHandleAxis,
};
static void keyboardHandleKeymap(void* data,
struct wl_keyboard* keyboard,
uint32_t format,
int fd,
uint32_t size)
{
char* mapStr;
if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
{
close(fd);
return;
}
mapStr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
if (mapStr == MAP_FAILED) {
close(fd);
return;
}
xkb_glfw_compile_keymap(mapStr);
munmap(mapStr, size);
close(fd);
}
static void keyboardHandleEnter(void* data,
struct wl_keyboard* keyboard,
uint32_t serial,
struct wl_surface* surface,
struct wl_array* keys)
{
// Happens in the case we just destroyed the surface.
if (!surface)
return;
_GLFWwindow* window = wl_surface_get_user_data(surface);
if (!window)
{
window = findWindowFromDecorationSurface(surface, NULL);
if (!window)
return;
}
_glfw.wl.keyboardFocus = window;
_glfwInputWindowFocus(window, GLFW_TRUE);
}
static void keyboardHandleLeave(void* data,
struct wl_keyboard* keyboard,
uint32_t serial,
struct wl_surface* surface)
{
_GLFWwindow* window = _glfw.wl.keyboardFocus;
if (!window)
return;
_glfw.wl.keyboardFocus = NULL;
_glfwInputWindowFocus(window, GLFW_FALSE);
}
static xkb_keysym_t composeSymbol(xkb_keysym_t sym)
{
if (sym == XKB_KEY_NoSymbol || !_glfw.wl.xkb.composeState)
return sym;
if (xkb_compose_state_feed(_glfw.wl.xkb.composeState, sym)
!= XKB_COMPOSE_FEED_ACCEPTED)
return sym;
switch (xkb_compose_state_get_status(_glfw.wl.xkb.composeState))
{
case XKB_COMPOSE_COMPOSED:
return xkb_compose_state_get_one_sym(_glfw.wl.xkb.composeState);
case XKB_COMPOSE_COMPOSING:
case XKB_COMPOSE_CANCELLED:
return XKB_KEY_NoSymbol;
case XKB_COMPOSE_NOTHING:
default:
return sym;
}
}
static void inputChar(_GLFWwindow* window, uint32_t key, GLFWbool *shouldRepeat)
{
uint32_t code, numSyms;
long cp;
const xkb_keysym_t *syms;
xkb_keysym_t sym;
code = key + 8;
numSyms = xkb_state_key_get_syms(_glfw.wl.xkb.state, code, &syms);
*shouldRepeat = xkb_keymap_key_repeats(_glfw.wl.xkb.keymap, code);
if (numSyms == 1)
{
sym = composeSymbol(syms[0]);
cp = _glfwKeySym2Unicode(sym);
if (cp != -1)
{
const int mods = _glfw.wl.xkb.modifiers;
const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
if (*shouldRepeat) {
_glfw.wl.keyRepeatInfo.codepoint = cp;
_glfw.wl.keyRepeatInfo.plain = plain;
}
_glfwInputChar(window, cp, mods, plain);
}
}
}
static void keyboardHandleKey(void* data,
struct wl_keyboard* keyboard,
uint32_t serial,
uint32_t time,
uint32_t key,
uint32_t state)
{
int keyCode;
int action;
_GLFWwindow* window = _glfw.wl.keyboardFocus;
if (!window)
return;
keyCode = xkb_glfw_to_glfw_key_code(key);
action = state == WL_KEYBOARD_KEY_STATE_PRESSED
? GLFW_PRESS : GLFW_RELEASE;
_glfw.wl.keyRepeatInfo.nextRepeatAt = 0;
_glfw.wl.keyRepeatInfo.codepoint = -1;
_glfwInputKey(window, keyCode, key, action,
_glfw.wl.xkb.modifiers);
if (action == GLFW_PRESS)
{
GLFWbool shouldRepeat = GLFW_FALSE;
inputChar(window, key, &shouldRepeat);
if (shouldRepeat && _glfw.wl.keyboardRepeatRate > 0)
{
_glfw.wl.keyRepeatInfo.glfwKeyCode = keyCode;
_glfw.wl.keyRepeatInfo.scancode = key;
_glfw.wl.keyRepeatInfo.nextRepeatAt = glfwGetTime() + (double)(_glfw.wl.keyboardRepeatDelay) / 1000.0;
_glfw.wl.keyRepeatInfo.keyboardFocus = window;
}
}
}
static void keyboardHandleModifiers(void* data,
struct wl_keyboard* keyboard,
uint32_t serial,
uint32_t modsDepressed,
uint32_t modsLatched,
uint32_t modsLocked,
uint32_t group)
{
xkb_glfw_update_modifiers(modsDepressed, modsLatched, modsLocked, group);
}
static void keyboardHandleRepeatInfo(void* data,
struct wl_keyboard* keyboard,
int32_t rate,
int32_t delay)
{
if (keyboard != _glfw.wl.keyboard)
return;
_glfw.wl.keyboardRepeatRate = rate;
_glfw.wl.keyboardRepeatDelay = delay;
}
static const struct wl_keyboard_listener keyboardListener = {
keyboardHandleKeymap,
keyboardHandleEnter,
keyboardHandleLeave,
keyboardHandleKey,
keyboardHandleModifiers,
keyboardHandleRepeatInfo,
};
static void seatHandleCapabilities(void* data,
struct wl_seat* seat,
enum wl_seat_capability caps)
{
if ((caps & WL_SEAT_CAPABILITY_POINTER) && !_glfw.wl.pointer)
{
_glfw.wl.pointer = wl_seat_get_pointer(seat);
wl_pointer_add_listener(_glfw.wl.pointer, &pointerListener, NULL);
}
else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && _glfw.wl.pointer)
{
wl_pointer_destroy(_glfw.wl.pointer);
_glfw.wl.pointer = NULL;
}
if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !_glfw.wl.keyboard)
{
_glfw.wl.keyboard = wl_seat_get_keyboard(seat);
wl_keyboard_add_listener(_glfw.wl.keyboard, &keyboardListener, NULL);
}
else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && _glfw.wl.keyboard)
{
wl_keyboard_destroy(_glfw.wl.keyboard);
_glfw.wl.keyboard = NULL;
}
}
static void seatHandleName(void* data,
struct wl_seat* seat,
const char* name)
{
}
static const struct wl_seat_listener seatListener = {
seatHandleCapabilities,
seatHandleName,
};
static void wmBaseHandlePing(void* data,
struct xdg_wm_base* wmBase,
uint32_t serial)
{
xdg_wm_base_pong(wmBase, serial);
}
static const struct xdg_wm_base_listener wmBaseListener = {
wmBaseHandlePing
};
static void registryHandleGlobal(void* data,
struct wl_registry* registry,
uint32_t name,
const char* interface,
uint32_t version)
{
if (strcmp(interface, "wl_compositor") == 0)
{
_glfw.wl.compositorVersion = min(3, version);
_glfw.wl.compositor =
wl_registry_bind(registry, name, &wl_compositor_interface,
_glfw.wl.compositorVersion);
}
else if (strcmp(interface, "wl_subcompositor") == 0)
{
_glfw.wl.subcompositor =
wl_registry_bind(registry, name, &wl_subcompositor_interface, 1);
}
else if (strcmp(interface, "wl_shm") == 0)
{
_glfw.wl.shm =
wl_registry_bind(registry, name, &wl_shm_interface, 1);
}
else if (strcmp(interface, "wl_shell") == 0)
{
_glfw.wl.shell =
wl_registry_bind(registry, name, &wl_shell_interface, 1);
}
else if (strcmp(interface, "wl_output") == 0)
{
_glfwAddOutputWayland(name, version);
}
else if (strcmp(interface, "wl_seat") == 0)
{
if (!_glfw.wl.seat)
{
_glfw.wl.seatVersion = min(4, version);
_glfw.wl.seat =
wl_registry_bind(registry, name, &wl_seat_interface,
_glfw.wl.seatVersion);
wl_seat_add_listener(_glfw.wl.seat, &seatListener, NULL);
}
}
else if (strcmp(interface, "xdg_wm_base") == 0)
{
_glfw.wl.wmBase =
wl_registry_bind(registry, name, &xdg_wm_base_interface, 1);
xdg_wm_base_add_listener(_glfw.wl.wmBase, &wmBaseListener, NULL);
}
else if (strcmp(interface, "wp_viewporter") == 0)
{
_glfw.wl.viewporter =
wl_registry_bind(registry, name, &wp_viewporter_interface, 1);
}
else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0)
{
_glfw.wl.relativePointerManager =
wl_registry_bind(registry, name,
&zwp_relative_pointer_manager_v1_interface,
1);
}
else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0)
{
_glfw.wl.pointerConstraints =
wl_registry_bind(registry, name,
&zwp_pointer_constraints_v1_interface,
1);
}
else if (strcmp(interface, "zwp_idle_inhibit_manager_v1") == 0)
{
_glfw.wl.idleInhibitManager =
wl_registry_bind(registry, name,
&zwp_idle_inhibit_manager_v1_interface,
1);
}
}
static void registryHandleGlobalRemove(void *data,
struct wl_registry *registry,
uint32_t name)
{
int i;
_GLFWmonitor* monitor;
for (i = 0; i < _glfw.monitorCount; ++i)
{
monitor = _glfw.monitors[i];
if (monitor->wl.name == name)
{
_glfwInputMonitor(monitor, GLFW_DISCONNECTED, 0);
return;
}
}
}
static const struct wl_registry_listener registryListener = {
registryHandleGlobal,
registryHandleGlobalRemove
};
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
int _glfwPlatformInit(void)
{
_glfw.wl.cursor.handle = _glfw_dlopen("libwayland-cursor.so.0");
if (!_glfw.wl.cursor.handle)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Failed to open libwayland-cursor");
return GLFW_FALSE;
}
_glfw.wl.cursor.theme_load = (PFN_wl_cursor_theme_load)
_glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_load");
_glfw.wl.cursor.theme_destroy = (PFN_wl_cursor_theme_destroy)
_glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_destroy");
_glfw.wl.cursor.theme_get_cursor = (PFN_wl_cursor_theme_get_cursor)
_glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_get_cursor");
_glfw.wl.cursor.image_get_buffer = (PFN_wl_cursor_image_get_buffer)
_glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_image_get_buffer");
_glfw.wl.egl.handle = _glfw_dlopen("libwayland-egl.so.1");
if (!_glfw.wl.egl.handle)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Failed to open libwayland-egl");
return GLFW_FALSE;
}
_glfw.wl.egl.window_create = (PFN_wl_egl_window_create)
_glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_create");
_glfw.wl.egl.window_destroy = (PFN_wl_egl_window_destroy)
_glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_destroy");
_glfw.wl.egl.window_resize = (PFN_wl_egl_window_resize)
_glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_resize");
load_glfw_xkb();
_glfw.wl.display = wl_display_connect(NULL);
if (!_glfw.wl.display)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Failed to connect to display");
return GLFW_FALSE;
}
_glfw.wl.registry = wl_display_get_registry(_glfw.wl.display);
wl_registry_add_listener(_glfw.wl.registry, &registryListener, NULL);
create_glfw_xkb_context();
// Sync so we got all registry objects
wl_display_roundtrip(_glfw.wl.display);
// Sync so we got all initial output events
wl_display_roundtrip(_glfw.wl.display);
#ifdef __linux__
if (!_glfwInitJoysticksLinux())
return GLFW_FALSE;
#endif
_glfwInitTimerPOSIX();
if (_glfw.wl.pointer && _glfw.wl.shm)
{
_glfw.wl.cursorTheme = wl_cursor_theme_load(NULL, 32, _glfw.wl.shm);
if (!_glfw.wl.cursorTheme)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Unable to load default cursor theme");
return GLFW_FALSE;
}
_glfw.wl.cursorSurface =
wl_compositor_create_surface(_glfw.wl.compositor);
}
return GLFW_TRUE;
}
void _glfwPlatformTerminate(void)
{
#ifdef __linux__
_glfwTerminateJoysticksLinux();
#endif
_glfwTerminateEGL();
if (_glfw.wl.egl.handle)
{
_glfw_dlclose(_glfw.wl.egl.handle);
_glfw.wl.egl.handle = NULL;
}
release_glfw_xkb();
if (_glfw.wl.cursorTheme)
wl_cursor_theme_destroy(_glfw.wl.cursorTheme);
if (_glfw.wl.cursor.handle)
{
_glfw_dlclose(_glfw.wl.cursor.handle);
_glfw.wl.cursor.handle = NULL;
}
if (_glfw.wl.cursorSurface)
wl_surface_destroy(_glfw.wl.cursorSurface);
if (_glfw.wl.subcompositor)
wl_subcompositor_destroy(_glfw.wl.subcompositor);
if (_glfw.wl.compositor)
wl_compositor_destroy(_glfw.wl.compositor);
if (_glfw.wl.shm)
wl_shm_destroy(_glfw.wl.shm);
if (_glfw.wl.shell)
wl_shell_destroy(_glfw.wl.shell);
if (_glfw.wl.viewporter)
wp_viewporter_destroy(_glfw.wl.viewporter);
if (_glfw.wl.wmBase)
xdg_wm_base_destroy(_glfw.wl.wmBase);
if (_glfw.wl.pointer)
wl_pointer_destroy(_glfw.wl.pointer);
if (_glfw.wl.keyboard)
wl_keyboard_destroy(_glfw.wl.keyboard);
if (_glfw.wl.seat)
wl_seat_destroy(_glfw.wl.seat);
if (_glfw.wl.relativePointerManager)
zwp_relative_pointer_manager_v1_destroy(_glfw.wl.relativePointerManager);
if (_glfw.wl.pointerConstraints)
zwp_pointer_constraints_v1_destroy(_glfw.wl.pointerConstraints);
if (_glfw.wl.idleInhibitManager)
zwp_idle_inhibit_manager_v1_destroy(_glfw.wl.idleInhibitManager);
if (_glfw.wl.registry)
wl_registry_destroy(_glfw.wl.registry);
if (_glfw.wl.display)
{
wl_display_flush(_glfw.wl.display);
wl_display_disconnect(_glfw.wl.display);
}
}
const char* _glfwPlatformGetVersionString(void)
{
return _GLFW_VERSION_NUMBER " Wayland EGL"
#if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK)
" clock_gettime"
#else
" gettimeofday"
#endif
" evdev"
#if defined(_GLFW_BUILD_DLL)
" shared"
#endif
;
}

208
glfw/wl_monitor.c vendored Normal file
View File

@@ -0,0 +1,208 @@
//========================================================================
// GLFW 3.3 Wayland - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
static void geometry(void* data,
struct wl_output* output,
int32_t x,
int32_t y,
int32_t physicalWidth,
int32_t physicalHeight,
int32_t subpixel,
const char* make,
const char* model,
int32_t transform)
{
struct _GLFWmonitor *monitor = data;
char name[1024];
monitor->wl.x = x;
monitor->wl.y = y;
monitor->widthMM = physicalWidth;
monitor->heightMM = physicalHeight;
snprintf(name, sizeof(name), "%s %s", make, model);
monitor->name = _glfw_strdup(name);
}
static void mode(void* data,
struct wl_output* output,
uint32_t flags,
int32_t width,
int32_t height,
int32_t refresh)
{
struct _GLFWmonitor *monitor = data;
GLFWvidmode mode;
mode.width = width;
mode.height = height;
mode.redBits = 8;
mode.greenBits = 8;
mode.blueBits = 8;
mode.refreshRate = refresh / 1000;
monitor->modeCount++;
monitor->modes =
realloc(monitor->modes, monitor->modeCount * sizeof(GLFWvidmode));
monitor->modes[monitor->modeCount - 1] = mode;
if (flags & WL_OUTPUT_MODE_CURRENT)
monitor->wl.currentMode = monitor->modeCount - 1;
}
static void done(void* data, struct wl_output* output)
{
struct _GLFWmonitor *monitor = data;
_glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST);
}
static void scale(void* data,
struct wl_output* output,
int32_t factor)
{
struct _GLFWmonitor *monitor = data;
monitor->wl.scale = factor;
}
static const struct wl_output_listener outputListener = {
geometry,
mode,
done,
scale,
};
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
void _glfwAddOutputWayland(uint32_t name, uint32_t version)
{
_GLFWmonitor *monitor;
struct wl_output *output;
if (version < 2)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Unsupported output interface version");
return;
}
// The actual name of this output will be set in the geometry handler.
monitor = _glfwAllocMonitor(NULL, 0, 0);
output = wl_registry_bind(_glfw.wl.registry,
name,
&wl_output_interface,
2);
if (!output)
{
_glfwFreeMonitor(monitor);
return;
}
monitor->wl.scale = 1;
monitor->wl.output = output;
monitor->wl.name = name;
wl_output_add_listener(output, &outputListener, monitor);
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
{
if (monitor->wl.output)
wl_output_destroy(monitor->wl.output);
}
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
{
if (xpos)
*xpos = monitor->wl.x;
if (ypos)
*ypos = monitor->wl.y;
}
void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
float* xscale, float* yscale)
{
if (xscale)
*xscale = (float) monitor->wl.scale;
if (yscale)
*yscale = (float) monitor->wl.scale;
}
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
{
*found = monitor->modeCount;
return monitor->modes;
}
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
{
*mode = monitor->modes[monitor->wl.currentMode];
}
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{
// TODO
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Gamma ramp getting not supported yet");
}
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
{
// TODO
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Gamma ramp setting not supported yet");
}
//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////
//////////////////////////////////////////////////////////////////////////
GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* handle)
{
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
return monitor->wl.output;
}

263
glfw/wl_platform.h vendored Normal file
View File

@@ -0,0 +1,263 @@
//========================================================================
// GLFW 3.3 Wayland - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include <wayland-client.h>
#include <dlfcn.h>
typedef VkFlags VkWaylandSurfaceCreateFlagsKHR;
typedef struct VkWaylandSurfaceCreateInfoKHR
{
VkStructureType sType;
const void* pNext;
VkWaylandSurfaceCreateFlagsKHR flags;
struct wl_display* display;
struct wl_surface* surface;
} VkWaylandSurfaceCreateInfoKHR;
typedef VkResult (APIENTRY *PFN_vkCreateWaylandSurfaceKHR)(VkInstance,const VkWaylandSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*);
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice,uint32_t,struct wl_display*);
#include "posix_thread.h"
#include "posix_time.h"
#ifdef __linux__
#include "linux_joystick.h"
#else
#include "null_joystick.h"
#endif
#define GLFW_XKB_GLOBAL_NAME _glfw.wl.xkb
#include "xkb_glfw.h"
#include "xkb_unicode.h"
#include "egl_context.h"
#include "osmesa_context.h"
#include "wayland-xdg-shell-client-protocol.h"
#include "wayland-viewporter-client-protocol.h"
#include "wayland-relative-pointer-unstable-v1-client-protocol.h"
#include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
#include "wayland-idle-inhibit-unstable-v1-client-protocol.h"
#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
#define _glfw_dlclose(handle) dlclose(handle)
#define _glfw_dlsym(handle, name) dlsym(handle, name)
#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->wl.native)
#define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.wl.display)
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWayland wl
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWayland wl
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWayland wl
#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorWayland wl
#define _GLFW_PLATFORM_CONTEXT_STATE
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE
struct wl_cursor_image {
uint32_t width;
uint32_t height;
uint32_t hotspot_x;
uint32_t hotspot_y;
uint32_t delay;
};
struct wl_cursor {
unsigned int image_count;
struct wl_cursor_image** images;
char* name;
};
typedef struct wl_cursor_theme* (* PFN_wl_cursor_theme_load)(const char*, int, struct wl_shm*);
typedef void (* PFN_wl_cursor_theme_destroy)(struct wl_cursor_theme*);
typedef struct wl_cursor* (* PFN_wl_cursor_theme_get_cursor)(struct wl_cursor_theme*, const char*);
typedef struct wl_buffer* (* PFN_wl_cursor_image_get_buffer)(struct wl_cursor_image*);
#define wl_cursor_theme_load _glfw.wl.cursor.theme_load
#define wl_cursor_theme_destroy _glfw.wl.cursor.theme_destroy
#define wl_cursor_theme_get_cursor _glfw.wl.cursor.theme_get_cursor
#define wl_cursor_image_get_buffer _glfw.wl.cursor.image_get_buffer
typedef struct wl_egl_window* (* PFN_wl_egl_window_create)(struct wl_surface*, int, int);
typedef void (* PFN_wl_egl_window_destroy)(struct wl_egl_window*);
typedef void (* PFN_wl_egl_window_resize)(struct wl_egl_window*, int, int, int, int);
#define wl_egl_window_create _glfw.wl.egl.window_create
#define wl_egl_window_destroy _glfw.wl.egl.window_destroy
#define wl_egl_window_resize _glfw.wl.egl.window_resize
#define _GLFW_DECORATION_WIDTH 4
#define _GLFW_DECORATION_TOP 24
#define _GLFW_DECORATION_VERTICAL (_GLFW_DECORATION_TOP + _GLFW_DECORATION_WIDTH)
#define _GLFW_DECORATION_HORIZONTAL (2 * _GLFW_DECORATION_WIDTH)
typedef enum _GLFWdecorationSideWayland
{
mainWindow,
topDecoration,
leftDecoration,
rightDecoration,
bottomDecoration,
} _GLFWdecorationSideWayland;
typedef struct _GLFWdecorationWayland
{
struct wl_surface* surface;
struct wl_subsurface* subsurface;
struct wp_viewport* viewport;
} _GLFWdecorationWayland;
// Wayland-specific per-window data
//
typedef struct _GLFWwindowWayland
{
int width, height;
GLFWbool visible;
GLFWbool maximized;
GLFWbool hovered;
GLFWbool transparent;
struct wl_surface* surface;
struct wl_egl_window* native;
struct wl_shell_surface* shellSurface;
struct wl_callback* callback;
struct {
struct xdg_surface* surface;
struct xdg_toplevel* toplevel;
} xdg;
_GLFWcursor* currentCursor;
double cursorPosX, cursorPosY;
char* title;
// We need to track the monitors the window spans on to calculate the
// optimal scaling factor.
int scale;
_GLFWmonitor** monitors;
int monitorsCount;
int monitorsSize;
struct {
struct zwp_relative_pointer_v1* relativePointer;
struct zwp_locked_pointer_v1* lockedPointer;
} pointerLock;
struct zwp_idle_inhibitor_v1* idleInhibitor;
// This is a hack to prevent auto-iconification on creation.
GLFWbool justCreated;
struct {
struct wl_buffer* buffer;
_GLFWdecorationWayland top, left, right, bottom;
int focus;
} decorations;
} _GLFWwindowWayland;
// Wayland-specific global data
//
typedef struct _GLFWlibraryWayland
{
struct wl_display* display;
struct wl_registry* registry;
struct wl_compositor* compositor;
struct wl_subcompositor* subcompositor;
struct wl_shell* shell;
struct wl_shm* shm;
struct wl_seat* seat;
struct wl_pointer* pointer;
struct wl_keyboard* keyboard;
struct xdg_wm_base* wmBase;
struct wp_viewporter* viewporter;
struct zwp_relative_pointer_manager_v1* relativePointerManager;
struct zwp_pointer_constraints_v1* pointerConstraints;
struct zwp_idle_inhibit_manager_v1* idleInhibitManager;
int compositorVersion;
int seatVersion;
struct wl_cursor_theme* cursorTheme;
struct wl_surface* cursorSurface;
uint32_t pointerSerial;
int32_t keyboardRepeatRate;
int32_t keyboardRepeatDelay;
struct {
long codepoint;
int plain;
int glfwKeyCode;
int scancode;
double nextRepeatAt;
_GLFWwindow* keyboardFocus;
} keyRepeatInfo;
_GLFWXKBData xkb;
_GLFWwindow* pointerFocus;
_GLFWwindow* keyboardFocus;
struct {
void* handle;
PFN_wl_cursor_theme_load theme_load;
PFN_wl_cursor_theme_destroy theme_destroy;
PFN_wl_cursor_theme_get_cursor theme_get_cursor;
PFN_wl_cursor_image_get_buffer image_get_buffer;
} cursor;
struct {
void* handle;
PFN_wl_egl_window_create window_create;
PFN_wl_egl_window_destroy window_destroy;
PFN_wl_egl_window_resize window_resize;
} egl;
} _GLFWlibraryWayland;
// Wayland-specific per-monitor data
//
typedef struct _GLFWmonitorWayland
{
struct wl_output* output;
int name;
int currentMode;
int x;
int y;
int scale;
} _GLFWmonitorWayland;
// Wayland-specific per-cursor data
//
typedef struct _GLFWcursorWayland
{
struct wl_cursor_image* image;
struct wl_buffer* buffer;
int width, height;
int xhot, yhot;
} _GLFWcursorWayland;
void _glfwAddOutputWayland(uint32_t name, uint32_t version);

1563
glfw/wl_window.c vendored Normal file

File diff suppressed because it is too large Load Diff

1053
glfw/x11_init.c vendored Normal file

File diff suppressed because it is too large Load Diff

504
glfw/x11_monitor.c vendored Normal file
View File

@@ -0,0 +1,504 @@
//========================================================================
// GLFW 3.3 X11 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <limits.h>
#include <stdlib.h>
#include <string.h>
// Check whether the display mode should be included in enumeration
//
static GLFWbool modeIsGood(const XRRModeInfo* mi)
{
return (mi->modeFlags & RR_Interlace) == 0;
}
// Calculates the refresh rate, in Hz, from the specified RandR mode info
//
static int calculateRefreshRate(const XRRModeInfo* mi)
{
if (mi->hTotal && mi->vTotal)
return (int) ((double) mi->dotClock / ((double) mi->hTotal * (double) mi->vTotal));
else
return 0;
}
// Returns the mode info for a RandR mode XID
//
static const XRRModeInfo* getModeInfo(const XRRScreenResources* sr, RRMode id)
{
int i;
for (i = 0; i < sr->nmode; i++)
{
if (sr->modes[i].id == id)
return sr->modes + i;
}
return NULL;
}
// Convert RandR mode info to GLFW video mode
//
static GLFWvidmode vidmodeFromModeInfo(const XRRModeInfo* mi,
const XRRCrtcInfo* ci)
{
GLFWvidmode mode;
if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270)
{
mode.width = mi->height;
mode.height = mi->width;
}
else
{
mode.width = mi->width;
mode.height = mi->height;
}
mode.refreshRate = calculateRefreshRate(mi);
_glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen),
&mode.redBits, &mode.greenBits, &mode.blueBits);
return mode;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
// Poll for changes in the set of connected monitors
//
void _glfwPollMonitorsX11(void)
{
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
{
int i, j, disconnectedCount, screenCount = 0;
_GLFWmonitor** disconnected = NULL;
XineramaScreenInfo* screens = NULL;
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display,
_glfw.x11.root);
RROutput primary = XRRGetOutputPrimary(_glfw.x11.display,
_glfw.x11.root);
if (_glfw.x11.xinerama.available)
screens = XineramaQueryScreens(_glfw.x11.display, &screenCount);
disconnectedCount = _glfw.monitorCount;
if (disconnectedCount)
{
disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*));
memcpy(disconnected,
_glfw.monitors,
_glfw.monitorCount * sizeof(_GLFWmonitor*));
}
for (i = 0; i < sr->noutput; i++)
{
int type, widthMM, heightMM;
XRROutputInfo* oi;
XRRCrtcInfo* ci;
_GLFWmonitor* monitor;
oi = XRRGetOutputInfo(_glfw.x11.display, sr, sr->outputs[i]);
if (oi->connection != RR_Connected || oi->crtc == None)
{
XRRFreeOutputInfo(oi);
continue;
}
for (j = 0; j < disconnectedCount; j++)
{
if (disconnected[j] &&
disconnected[j]->x11.output == sr->outputs[i])
{
disconnected[j] = NULL;
break;
}
}
if (j < disconnectedCount)
{
XRRFreeOutputInfo(oi);
continue;
}
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, oi->crtc);
if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270)
{
widthMM = oi->mm_height;
heightMM = oi->mm_width;
}
else
{
widthMM = oi->mm_width;
heightMM = oi->mm_height;
}
monitor = _glfwAllocMonitor(oi->name, widthMM, heightMM);
monitor->x11.output = sr->outputs[i];
monitor->x11.crtc = oi->crtc;
for (j = 0; j < screenCount; j++)
{
if (screens[j].x_org == ci->x &&
screens[j].y_org == ci->y &&
screens[j].width == ci->width &&
screens[j].height == ci->height)
{
monitor->x11.index = j;
break;
}
}
if (monitor->x11.output == primary)
type = _GLFW_INSERT_FIRST;
else
type = _GLFW_INSERT_LAST;
_glfwInputMonitor(monitor, GLFW_CONNECTED, type);
XRRFreeOutputInfo(oi);
XRRFreeCrtcInfo(ci);
}
XRRFreeScreenResources(sr);
if (screens)
XFree(screens);
for (i = 0; i < disconnectedCount; i++)
{
if (disconnected[i])
_glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0);
}
free(disconnected);
}
else
{
const int widthMM = DisplayWidthMM(_glfw.x11.display, _glfw.x11.screen);
const int heightMM = DisplayHeightMM(_glfw.x11.display, _glfw.x11.screen);
_glfwInputMonitor(_glfwAllocMonitor("Display", widthMM, heightMM),
GLFW_CONNECTED,
_GLFW_INSERT_FIRST);
}
}
// Set the current video mode for the specified monitor
//
void _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired)
{
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
{
XRRScreenResources* sr;
XRRCrtcInfo* ci;
XRROutputInfo* oi;
GLFWvidmode current;
const GLFWvidmode* best;
RRMode native = None;
int i;
best = _glfwChooseVideoMode(monitor, desired);
_glfwPlatformGetVideoMode(monitor, &current);
if (_glfwCompareVideoModes(&current, best) == 0)
return;
sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);
for (i = 0; i < oi->nmode; i++)
{
const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]);
if (!modeIsGood(mi))
continue;
const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci);
if (_glfwCompareVideoModes(best, &mode) == 0)
{
native = mi->id;
break;
}
}
if (native)
{
if (monitor->x11.oldMode == None)
monitor->x11.oldMode = ci->mode;
XRRSetCrtcConfig(_glfw.x11.display,
sr, monitor->x11.crtc,
CurrentTime,
ci->x, ci->y,
native,
ci->rotation,
ci->outputs,
ci->noutput);
}
XRRFreeOutputInfo(oi);
XRRFreeCrtcInfo(ci);
XRRFreeScreenResources(sr);
}
}
// Restore the saved (original) video mode for the specified monitor
//
void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor)
{
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
{
XRRScreenResources* sr;
XRRCrtcInfo* ci;
if (monitor->x11.oldMode == None)
return;
sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
XRRSetCrtcConfig(_glfw.x11.display,
sr, monitor->x11.crtc,
CurrentTime,
ci->x, ci->y,
monitor->x11.oldMode,
ci->rotation,
ci->outputs,
ci->noutput);
XRRFreeCrtcInfo(ci);
XRRFreeScreenResources(sr);
monitor->x11.oldMode = None;
}
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
{
}
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
{
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
{
XRRScreenResources* sr;
XRRCrtcInfo* ci;
sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
if (xpos)
*xpos = ci->x;
if (ypos)
*ypos = ci->y;
XRRFreeCrtcInfo(ci);
XRRFreeScreenResources(sr);
}
}
void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
float* xscale, float* yscale)
{
if (xscale)
*xscale = _glfw.x11.contentScaleX;
if (yscale)
*yscale = _glfw.x11.contentScaleY;
}
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
{
GLFWvidmode* result;
*count = 0;
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
{
int i, j;
XRRScreenResources* sr;
XRRCrtcInfo* ci;
XRROutputInfo* oi;
sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);
result = calloc(oi->nmode, sizeof(GLFWvidmode));
for (i = 0; i < oi->nmode; i++)
{
const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]);
if (!modeIsGood(mi))
continue;
const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci);
for (j = 0; j < *count; j++)
{
if (_glfwCompareVideoModes(result + j, &mode) == 0)
break;
}
// Skip duplicate modes
if (j < *count)
continue;
(*count)++;
result[*count - 1] = mode;
}
XRRFreeOutputInfo(oi);
XRRFreeCrtcInfo(ci);
XRRFreeScreenResources(sr);
}
else
{
*count = 1;
result = calloc(1, sizeof(GLFWvidmode));
_glfwPlatformGetVideoMode(monitor, result);
}
return result;
}
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
{
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
{
XRRScreenResources* sr;
XRRCrtcInfo* ci;
sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
*mode = vidmodeFromModeInfo(getModeInfo(sr, ci->mode), ci);
XRRFreeCrtcInfo(ci);
XRRFreeScreenResources(sr);
}
else
{
mode->width = DisplayWidth(_glfw.x11.display, _glfw.x11.screen);
mode->height = DisplayHeight(_glfw.x11.display, _glfw.x11.screen);
mode->refreshRate = 0;
_glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen),
&mode->redBits, &mode->greenBits, &mode->blueBits);
}
}
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{
if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken)
{
const size_t size = XRRGetCrtcGammaSize(_glfw.x11.display,
monitor->x11.crtc);
XRRCrtcGamma* gamma = XRRGetCrtcGamma(_glfw.x11.display,
monitor->x11.crtc);
_glfwAllocGammaArrays(ramp, size);
memcpy(ramp->red, gamma->red, size * sizeof(unsigned short));
memcpy(ramp->green, gamma->green, size * sizeof(unsigned short));
memcpy(ramp->blue, gamma->blue, size * sizeof(unsigned short));
XRRFreeGamma(gamma);
}
else if (_glfw.x11.vidmode.available)
{
int size;
XF86VidModeGetGammaRampSize(_glfw.x11.display, _glfw.x11.screen, &size);
_glfwAllocGammaArrays(ramp, size);
XF86VidModeGetGammaRamp(_glfw.x11.display,
_glfw.x11.screen,
ramp->size, ramp->red, ramp->green, ramp->blue);
}
}
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
{
if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken)
{
if (XRRGetCrtcGammaSize(_glfw.x11.display, monitor->x11.crtc) != ramp->size)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"X11: Gamma ramp size must match current ramp size");
return;
}
XRRCrtcGamma* gamma = XRRAllocGamma(ramp->size);
memcpy(gamma->red, ramp->red, ramp->size * sizeof(unsigned short));
memcpy(gamma->green, ramp->green, ramp->size * sizeof(unsigned short));
memcpy(gamma->blue, ramp->blue, ramp->size * sizeof(unsigned short));
XRRSetCrtcGamma(_glfw.x11.display, monitor->x11.crtc, gamma);
XRRFreeGamma(gamma);
}
else if (_glfw.x11.vidmode.available)
{
XF86VidModeSetGammaRamp(_glfw.x11.display,
_glfw.x11.screen,
ramp->size,
(unsigned short*) ramp->red,
(unsigned short*) ramp->green,
(unsigned short*) ramp->blue);
}
}
//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////
//////////////////////////////////////////////////////////////////////////
GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* handle)
{
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
_GLFW_REQUIRE_INIT_OR_RETURN(None);
return monitor->x11.crtc;
}
GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* handle)
{
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
_GLFW_REQUIRE_INIT_OR_RETURN(None);
return monitor->x11.output;
}

444
glfw/x11_platform.h vendored Normal file
View File

@@ -0,0 +1,444 @@
//========================================================================
// GLFW 3.3 X11 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include <unistd.h>
#include <signal.h>
#include <stdint.h>
#include <dlfcn.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <X11/Xatom.h>
#include <X11/Xcursor/Xcursor.h>
// The XRandR extension provides mode setting and gamma control
#include <X11/extensions/Xrandr.h>
// The Xkb extension provides improved keyboard support
#include <X11/XKBlib.h>
// The Xinerama extension provides legacy monitor indices
#include <X11/extensions/Xinerama.h>
// The XInput extension provides raw mouse motion input
#include <X11/extensions/XInput2.h>
typedef XRRCrtcGamma* (* PFN_XRRAllocGamma)(int);
typedef void (* PFN_XRRFreeCrtcInfo)(XRRCrtcInfo*);
typedef void (* PFN_XRRFreeGamma)(XRRCrtcGamma*);
typedef void (* PFN_XRRFreeOutputInfo)(XRROutputInfo*);
typedef void (* PFN_XRRFreeScreenResources)(XRRScreenResources*);
typedef XRRCrtcGamma* (* PFN_XRRGetCrtcGamma)(Display*,RRCrtc);
typedef int (* PFN_XRRGetCrtcGammaSize)(Display*,RRCrtc);
typedef XRRCrtcInfo* (* PFN_XRRGetCrtcInfo) (Display*,XRRScreenResources*,RRCrtc);
typedef XRROutputInfo* (* PFN_XRRGetOutputInfo)(Display*,XRRScreenResources*,RROutput);
typedef RROutput (* PFN_XRRGetOutputPrimary)(Display*,Window);
typedef XRRScreenResources* (* PFN_XRRGetScreenResourcesCurrent)(Display*,Window);
typedef Bool (* PFN_XRRQueryExtension)(Display*,int*,int*);
typedef Status (* PFN_XRRQueryVersion)(Display*,int*,int*);
typedef void (* PFN_XRRSelectInput)(Display*,Window,int);
typedef Status (* PFN_XRRSetCrtcConfig)(Display*,XRRScreenResources*,RRCrtc,Time,int,int,RRMode,Rotation,RROutput*,int);
typedef void (* PFN_XRRSetCrtcGamma)(Display*,RRCrtc,XRRCrtcGamma*);
typedef int (* PFN_XRRUpdateConfiguration)(XEvent*);
#define XRRAllocGamma _glfw.x11.randr.AllocGamma
#define XRRFreeCrtcInfo _glfw.x11.randr.FreeCrtcInfo
#define XRRFreeGamma _glfw.x11.randr.FreeGamma
#define XRRFreeOutputInfo _glfw.x11.randr.FreeOutputInfo
#define XRRFreeScreenResources _glfw.x11.randr.FreeScreenResources
#define XRRGetCrtcGamma _glfw.x11.randr.GetCrtcGamma
#define XRRGetCrtcGammaSize _glfw.x11.randr.GetCrtcGammaSize
#define XRRGetCrtcInfo _glfw.x11.randr.GetCrtcInfo
#define XRRGetOutputInfo _glfw.x11.randr.GetOutputInfo
#define XRRGetOutputPrimary _glfw.x11.randr.GetOutputPrimary
#define XRRGetScreenResourcesCurrent _glfw.x11.randr.GetScreenResourcesCurrent
#define XRRQueryExtension _glfw.x11.randr.QueryExtension
#define XRRQueryVersion _glfw.x11.randr.QueryVersion
#define XRRSelectInput _glfw.x11.randr.SelectInput
#define XRRSetCrtcConfig _glfw.x11.randr.SetCrtcConfig
#define XRRSetCrtcGamma _glfw.x11.randr.SetCrtcGamma
#define XRRUpdateConfiguration _glfw.x11.randr.UpdateConfiguration
typedef XcursorImage* (* PFN_XcursorImageCreate)(int,int);
typedef void (* PFN_XcursorImageDestroy)(XcursorImage*);
typedef Cursor (* PFN_XcursorImageLoadCursor)(Display*,const XcursorImage*);
#define XcursorImageCreate _glfw.x11.xcursor.ImageCreate
#define XcursorImageDestroy _glfw.x11.xcursor.ImageDestroy
#define XcursorImageLoadCursor _glfw.x11.xcursor.ImageLoadCursor
typedef Bool (* PFN_XineramaIsActive)(Display*);
typedef Bool (* PFN_XineramaQueryExtension)(Display*,int*,int*);
typedef XineramaScreenInfo* (* PFN_XineramaQueryScreens)(Display*,int*);
#define XineramaIsActive _glfw.x11.xinerama.IsActive
#define XineramaQueryExtension _glfw.x11.xinerama.QueryExtension
#define XineramaQueryScreens _glfw.x11.xinerama.QueryScreens
typedef XID xcb_window_t;
typedef XID xcb_visualid_t;
typedef struct xcb_connection_t xcb_connection_t;
typedef xcb_connection_t* (* PFN_XGetXCBConnection)(Display*);
#define XGetXCBConnection _glfw.x11.x11xcb.GetXCBConnection
typedef Bool (* PFN_XF86VidModeQueryExtension)(Display*,int*,int*);
typedef Bool (* PFN_XF86VidModeGetGammaRamp)(Display*,int,int,unsigned short*,unsigned short*,unsigned short*);
typedef Bool (* PFN_XF86VidModeSetGammaRamp)(Display*,int,int,unsigned short*,unsigned short*,unsigned short*);
typedef Bool (* PFN_XF86VidModeGetGammaRampSize)(Display*,int,int*);
#define XF86VidModeQueryExtension _glfw.x11.vidmode.QueryExtension
#define XF86VidModeGetGammaRamp _glfw.x11.vidmode.GetGammaRamp
#define XF86VidModeSetGammaRamp _glfw.x11.vidmode.SetGammaRamp
#define XF86VidModeGetGammaRampSize _glfw.x11.vidmode.GetGammaRampSize
typedef Status (* PFN_XIQueryVersion)(Display*,int*,int*);
typedef int (* PFN_XISelectEvents)(Display*,Window,XIEventMask*,int);
#define XIQueryVersion _glfw.x11.xi.QueryVersion
#define XISelectEvents _glfw.x11.xi.SelectEvents
typedef Bool (* PFN_XRenderQueryExtension)(Display*,int*,int*);
typedef Status (* PFN_XRenderQueryVersion)(Display*dpy,int*,int*);
typedef XRenderPictFormat* (* PFN_XRenderFindVisualFormat)(Display*,Visual const*);
#define XRenderQueryExtension _glfw.x11.xrender.QueryExtension
#define XRenderQueryVersion _glfw.x11.xrender.QueryVersion
#define XRenderFindVisualFormat _glfw.x11.xrender.FindVisualFormat
typedef VkFlags VkXlibSurfaceCreateFlagsKHR;
typedef VkFlags VkXcbSurfaceCreateFlagsKHR;
typedef struct VkXlibSurfaceCreateInfoKHR
{
VkStructureType sType;
const void* pNext;
VkXlibSurfaceCreateFlagsKHR flags;
Display* dpy;
Window window;
} VkXlibSurfaceCreateInfoKHR;
typedef struct VkXcbSurfaceCreateInfoKHR
{
VkStructureType sType;
const void* pNext;
VkXcbSurfaceCreateFlagsKHR flags;
xcb_connection_t* connection;
xcb_window_t window;
} VkXcbSurfaceCreateInfoKHR;
typedef VkResult (APIENTRY *PFN_vkCreateXlibSurfaceKHR)(VkInstance,const VkXlibSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*);
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice,uint32_t,Display*,VisualID);
typedef VkResult (APIENTRY *PFN_vkCreateXcbSurfaceKHR)(VkInstance,const VkXcbSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*);
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice,uint32_t,xcb_connection_t*,xcb_visualid_t);
#include "posix_thread.h"
#include "posix_time.h"
#include "xkb_unicode.h"
#include "glx_context.h"
#include "egl_context.h"
#include "osmesa_context.h"
#if defined(__linux__)
#include "linux_joystick.h"
#else
#include "null_joystick.h"
#endif
#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
#define _glfw_dlclose(handle) dlclose(handle)
#define _glfw_dlsym(handle, name) dlsym(handle, name)
#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->x11.handle)
#define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.x11.display)
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowX11 x11
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorX11 x11
#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorX11 x11
// X11-specific per-window data
//
typedef struct _GLFWwindowX11
{
Colormap colormap;
Window handle;
XIC ic;
GLFWbool overrideRedirect;
GLFWbool iconified;
GLFWbool maximized;
// Whether the visual supports framebuffer transparency
GLFWbool transparent;
// Cached position and size used to filter out duplicate events
int width, height;
int xpos, ypos;
// The last received cursor position, regardless of source
int lastCursorPosX, lastCursorPosY;
// The last position the cursor was warped to by GLFW
int warpCursorPosX, warpCursorPosY;
// The time of the last KeyPress event
Time lastKeyTime;
} _GLFWwindowX11;
// X11-specific global data
//
typedef struct _GLFWlibraryX11
{
Display* display;
int screen;
Window root;
// System content scale
float contentScaleX, contentScaleY;
// Helper window for IPC
Window helperWindowHandle;
// Invisible cursor for hidden cursor mode
Cursor hiddenCursorHandle;
// Context for mapping window XIDs to _GLFWwindow pointers
XContext context;
// XIM input method
XIM im;
// Most recent error code received by X error handler
int errorCode;
// Primary selection string (while the primary selection is owned)
char* primarySelectionString;
// Clipboard string (while the selection is owned)
char* clipboardString;
// Key name string
char keyName[5];
// X11 keycode to GLFW key LUT
short int keycodes[256];
// GLFW key to X11 keycode LUT
short int scancodes[GLFW_KEY_LAST + 1];
// Where to place the cursor when re-enabled
double restoreCursorPosX, restoreCursorPosY;
// The window whose disabled cursor mode is active
_GLFWwindow* disabledCursorWindow;
// Window manager atoms
Atom WM_PROTOCOLS;
Atom WM_STATE;
Atom WM_DELETE_WINDOW;
Atom NET_WM_NAME;
Atom NET_WM_ICON_NAME;
Atom NET_WM_ICON;
Atom NET_WM_PID;
Atom NET_WM_PING;
Atom NET_WM_WINDOW_TYPE;
Atom NET_WM_WINDOW_TYPE_NORMAL;
Atom NET_WM_STATE;
Atom NET_WM_STATE_ABOVE;
Atom NET_WM_STATE_FULLSCREEN;
Atom NET_WM_STATE_MAXIMIZED_VERT;
Atom NET_WM_STATE_MAXIMIZED_HORZ;
Atom NET_WM_STATE_DEMANDS_ATTENTION;
Atom NET_WM_BYPASS_COMPOSITOR;
Atom NET_WM_FULLSCREEN_MONITORS;
Atom NET_WM_WINDOW_OPACITY;
Atom NET_WM_CM_Sx;
Atom NET_ACTIVE_WINDOW;
Atom NET_FRAME_EXTENTS;
Atom NET_REQUEST_FRAME_EXTENTS;
Atom MOTIF_WM_HINTS;
// Xdnd (drag and drop) atoms
Atom XdndAware;
Atom XdndEnter;
Atom XdndPosition;
Atom XdndStatus;
Atom XdndActionCopy;
Atom XdndDrop;
Atom XdndFinished;
Atom XdndSelection;
Atom XdndTypeList;
Atom text_uri_list;
// Selection (clipboard) atoms
Atom TARGETS;
Atom MULTIPLE;
Atom INCR;
Atom CLIPBOARD;
Atom PRIMARY;
Atom CLIPBOARD_MANAGER;
Atom SAVE_TARGETS;
Atom NULL_;
Atom UTF8_STRING;
Atom COMPOUND_STRING;
Atom ATOM_PAIR;
Atom GLFW_SELECTION;
struct {
GLFWbool available;
void* handle;
int eventBase;
int errorBase;
int major;
int minor;
GLFWbool gammaBroken;
GLFWbool monitorBroken;
PFN_XRRAllocGamma AllocGamma;
PFN_XRRFreeCrtcInfo FreeCrtcInfo;
PFN_XRRFreeGamma FreeGamma;
PFN_XRRFreeOutputInfo FreeOutputInfo;
PFN_XRRFreeScreenResources FreeScreenResources;
PFN_XRRGetCrtcGamma GetCrtcGamma;
PFN_XRRGetCrtcGammaSize GetCrtcGammaSize;
PFN_XRRGetCrtcInfo GetCrtcInfo;
PFN_XRRGetOutputInfo GetOutputInfo;
PFN_XRRGetOutputPrimary GetOutputPrimary;
PFN_XRRGetScreenResourcesCurrent GetScreenResourcesCurrent;
PFN_XRRQueryExtension QueryExtension;
PFN_XRRQueryVersion QueryVersion;
PFN_XRRSelectInput SelectInput;
PFN_XRRSetCrtcConfig SetCrtcConfig;
PFN_XRRSetCrtcGamma SetCrtcGamma;
PFN_XRRUpdateConfiguration UpdateConfiguration;
} randr;
struct {
GLFWbool available;
GLFWbool detectable;
int majorOpcode;
int eventBase;
int errorBase;
int major;
int minor;
} xkb;
struct {
int count;
int timeout;
int interval;
int blanking;
int exposure;
} saver;
struct {
int version;
Window source;
Atom format;
} xdnd;
struct {
void* handle;
PFN_XcursorImageCreate ImageCreate;
PFN_XcursorImageDestroy ImageDestroy;
PFN_XcursorImageLoadCursor ImageLoadCursor;
} xcursor;
struct {
GLFWbool available;
void* handle;
int major;
int minor;
PFN_XineramaIsActive IsActive;
PFN_XineramaQueryExtension QueryExtension;
PFN_XineramaQueryScreens QueryScreens;
} xinerama;
struct {
void* handle;
PFN_XGetXCBConnection GetXCBConnection;
} x11xcb;
struct {
GLFWbool available;
void* handle;
int eventBase;
int errorBase;
PFN_XF86VidModeQueryExtension QueryExtension;
PFN_XF86VidModeGetGammaRamp GetGammaRamp;
PFN_XF86VidModeSetGammaRamp SetGammaRamp;
PFN_XF86VidModeGetGammaRampSize GetGammaRampSize;
} vidmode;
struct {
GLFWbool available;
void* handle;
int majorOpcode;
int eventBase;
int errorBase;
int major;
int minor;
PFN_XIQueryVersion QueryVersion;
PFN_XISelectEvents SelectEvents;
} xi;
struct {
GLFWbool available;
void* handle;
int major;
int minor;
int eventBase;
int errorBase;
PFN_XRenderQueryExtension QueryExtension;
PFN_XRenderQueryVersion QueryVersion;
PFN_XRenderFindVisualFormat FindVisualFormat;
} xrender;
} _GLFWlibraryX11;
// X11-specific per-monitor data
//
typedef struct _GLFWmonitorX11
{
RROutput output;
RRCrtc crtc;
RRMode oldMode;
// Index of corresponding Xinerama screen,
// for EWMH full screen window placement
int index;
} _GLFWmonitorX11;
// X11-specific per-cursor data
//
typedef struct _GLFWcursorX11
{
Cursor handle;
} _GLFWcursorX11;
void _glfwPollMonitorsX11(void);
void _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired);
void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor);
Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot);
unsigned long _glfwGetWindowPropertyX11(Window window,
Atom property,
Atom type,
unsigned char** value);
GLFWbool _glfwIsVisualTransparentX11(Visual* visual);
void _glfwGrabErrorHandlerX11(void);
void _glfwReleaseErrorHandlerX11(void);
void _glfwInputErrorX11(int error, const char* message);
void _glfwPushSelectionToManagerX11(void);

3046
glfw/x11_window.c vendored Normal file

File diff suppressed because it is too large Load Diff

374
glfw/xkb_glfw.h vendored Normal file
View File

@@ -0,0 +1,374 @@
//========================================================================
// GLFW 3.3 XKB - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Kovid Goyal <kovid@kovidgoyal.net>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#pragma once
#include <xkbcommon/xkbcommon.h>
#include <xkbcommon/xkbcommon-compose.h>
typedef struct xkb_context* (* PFN_xkb_context_new)(enum xkb_context_flags);
typedef void (* PFN_xkb_context_unref)(struct xkb_context*);
typedef struct xkb_keymap* (* PFN_xkb_keymap_new_from_string)(struct xkb_context*, const char*, enum xkb_keymap_format, enum xkb_keymap_compile_flags);
typedef void (* PFN_xkb_keymap_unref)(struct xkb_keymap*);
typedef xkb_mod_index_t (* PFN_xkb_keymap_mod_get_index)(struct xkb_keymap*, const char*);
typedef int (* PFN_xkb_keymap_key_repeats)(struct xkb_keymap*, xkb_keycode_t);
typedef struct xkb_state* (* PFN_xkb_state_new)(struct xkb_keymap*);
typedef void (* PFN_xkb_state_unref)(struct xkb_state*);
typedef int (* PFN_xkb_state_key_get_syms)(struct xkb_state*, xkb_keycode_t, const xkb_keysym_t**);
typedef enum xkb_state_component (* PFN_xkb_state_update_mask)(struct xkb_state*, xkb_mod_mask_t, xkb_mod_mask_t, xkb_mod_mask_t, xkb_layout_index_t, xkb_layout_index_t, xkb_layout_index_t);
typedef xkb_mod_mask_t (* PFN_xkb_state_serialize_mods)(struct xkb_state*, enum xkb_state_component);
#define xkb_context_new GLFW_XKB_GLOBAL_NAME.context_new
#define xkb_context_unref GLFW_XKB_GLOBAL_NAME.context_unref
#define xkb_keymap_new_from_string GLFW_XKB_GLOBAL_NAME.keymap_new_from_string
#define xkb_keymap_unref GLFW_XKB_GLOBAL_NAME.keymap_unref
#define xkb_keymap_mod_get_index GLFW_XKB_GLOBAL_NAME.keymap_mod_get_index
#define xkb_keymap_key_repeats GLFW_XKB_GLOBAL_NAME.keymap_key_repeats
#define xkb_state_new GLFW_XKB_GLOBAL_NAME.state_new
#define xkb_state_unref GLFW_XKB_GLOBAL_NAME.state_unref
#define xkb_state_key_get_syms GLFW_XKB_GLOBAL_NAME.state_key_get_syms
#define xkb_state_update_mask GLFW_XKB_GLOBAL_NAME.state_update_mask
#define xkb_state_serialize_mods GLFW_XKB_GLOBAL_NAME.state_serialize_mods
typedef struct xkb_compose_table* (* PFN_xkb_compose_table_new_from_locale)(struct xkb_context*, const char*, enum xkb_compose_compile_flags);
typedef void (* PFN_xkb_compose_table_unref)(struct xkb_compose_table*);
typedef struct xkb_compose_state* (* PFN_xkb_compose_state_new)(struct xkb_compose_table*, enum xkb_compose_state_flags);
typedef void (* PFN_xkb_compose_state_unref)(struct xkb_compose_state*);
typedef enum xkb_compose_feed_result (* PFN_xkb_compose_state_feed)(struct xkb_compose_state*, xkb_keysym_t);
typedef enum xkb_compose_status (* PFN_xkb_compose_state_get_status)(struct xkb_compose_state*);
typedef xkb_keysym_t (* PFN_xkb_compose_state_get_one_sym)(struct xkb_compose_state*);
#define xkb_compose_table_new_from_locale GLFW_XKB_GLOBAL_NAME.compose_table_new_from_locale
#define xkb_compose_table_unref GLFW_XKB_GLOBAL_NAME.compose_table_unref
#define xkb_compose_state_new GLFW_XKB_GLOBAL_NAME.compose_state_new
#define xkb_compose_state_unref GLFW_XKB_GLOBAL_NAME.compose_state_unref
#define xkb_compose_state_feed GLFW_XKB_GLOBAL_NAME.compose_state_feed
#define xkb_compose_state_get_status GLFW_XKB_GLOBAL_NAME.compose_state_get_status
#define xkb_compose_state_get_one_sym GLFW_XKB_GLOBAL_NAME.compose_state_get_one_sym
typedef struct {
void* handle;
struct xkb_context* context;
struct xkb_keymap* keymap;
struct xkb_state* state;
struct xkb_compose_state* composeState;
short int keycodes[256];
short int scancodes[GLFW_KEY_LAST + 1];
xkb_mod_mask_t controlMask;
xkb_mod_mask_t altMask;
xkb_mod_mask_t shiftMask;
xkb_mod_mask_t superMask;
xkb_mod_mask_t capsLockMask;
xkb_mod_mask_t numLockMask;
unsigned int modifiers;
PFN_xkb_context_new context_new;
PFN_xkb_context_unref context_unref;
PFN_xkb_keymap_new_from_string keymap_new_from_string;
PFN_xkb_keymap_unref keymap_unref;
PFN_xkb_keymap_mod_get_index keymap_mod_get_index;
PFN_xkb_keymap_key_repeats keymap_key_repeats;
PFN_xkb_state_new state_new;
PFN_xkb_state_unref state_unref;
PFN_xkb_state_key_get_syms state_key_get_syms;
PFN_xkb_state_update_mask state_update_mask;
PFN_xkb_state_serialize_mods state_serialize_mods;
PFN_xkb_compose_table_new_from_locale compose_table_new_from_locale;
PFN_xkb_compose_table_unref compose_table_unref;
PFN_xkb_compose_state_new compose_state_new;
PFN_xkb_compose_state_unref compose_state_unref;
PFN_xkb_compose_state_feed compose_state_feed;
PFN_xkb_compose_state_get_status compose_state_get_status;
PFN_xkb_compose_state_get_one_sym compose_state_get_one_sym;
} _GLFWXKBData;
#define bind_xkb_sym(name) GLFW_XKB_GLOBAL_NAME.name = (PFN_xkb_##name) _glfw_dlsym(GLFW_XKB_GLOBAL_NAME.handle, "xkb_" #name)
#define load_glfw_xkb() {\
GLFW_XKB_GLOBAL_NAME.handle = _glfw_dlopen("libxkbcommon.so.0"); \
if (!GLFW_XKB_GLOBAL_NAME.handle) \
{ \
_glfwInputError(GLFW_PLATFORM_ERROR, \
"Failed to open libxkbcommon"); \
return GLFW_FALSE; \
} \
bind_xkb_sym(context_new); \
bind_xkb_sym(context_unref); \
bind_xkb_sym(keymap_new_from_string); \
bind_xkb_sym(keymap_unref); \
bind_xkb_sym(keymap_mod_get_index); \
bind_xkb_sym(keymap_key_repeats); \
bind_xkb_sym(state_new); \
bind_xkb_sym(state_unref); \
bind_xkb_sym(state_key_get_syms); \
bind_xkb_sym(state_update_mask); \
bind_xkb_sym(state_serialize_mods); \
bind_xkb_sym(compose_table_new_from_locale); \
bind_xkb_sym(compose_table_unref); \
bind_xkb_sym(compose_state_new); \
bind_xkb_sym(compose_state_unref); \
bind_xkb_sym(compose_state_feed); \
bind_xkb_sym(compose_state_get_status); \
bind_xkb_sym(compose_state_get_one_sym); \
}
#define release_glfw_xkb() {\
if (GLFW_XKB_GLOBAL_NAME.composeState) { \
xkb_compose_state_unref(GLFW_XKB_GLOBAL_NAME.composeState); \
GLFW_XKB_GLOBAL_NAME.composeState = NULL; \
} \
if (GLFW_XKB_GLOBAL_NAME.keymap) { \
xkb_keymap_unref(GLFW_XKB_GLOBAL_NAME.keymap); \
GLFW_XKB_GLOBAL_NAME.keymap = NULL; \
} \
if (GLFW_XKB_GLOBAL_NAME.state) { \
xkb_state_unref(GLFW_XKB_GLOBAL_NAME.state); \
GLFW_XKB_GLOBAL_NAME.state = NULL; \
} \
if (GLFW_XKB_GLOBAL_NAME.context) { \
xkb_context_unref(GLFW_XKB_GLOBAL_NAME.context); \
GLFW_XKB_GLOBAL_NAME.context = NULL; \
} \
if (GLFW_XKB_GLOBAL_NAME.handle) { \
_glfw_dlclose(GLFW_XKB_GLOBAL_NAME.handle); \
GLFW_XKB_GLOBAL_NAME.handle = NULL; \
} \
}
#define create_glfw_xkb_context() {\
GLFW_XKB_GLOBAL_NAME.context = xkb_context_new(0); \
if (!GLFW_XKB_GLOBAL_NAME.context) \
{ \
_glfwInputError(GLFW_PLATFORM_ERROR, \
"Failed to initialize XKB context"); \
return GLFW_FALSE; \
} \
int scancode; \
memset(GLFW_XKB_GLOBAL_NAME.keycodes, -1, sizeof(GLFW_XKB_GLOBAL_NAME.keycodes)); \
memset(GLFW_XKB_GLOBAL_NAME.scancodes, -1, sizeof(GLFW_XKB_GLOBAL_NAME.scancodes)); \
\
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_GRAVE] = GLFW_KEY_GRAVE_ACCENT; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_1] = GLFW_KEY_1; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_2] = GLFW_KEY_2; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_3] = GLFW_KEY_3; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_4] = GLFW_KEY_4; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_5] = GLFW_KEY_5; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_6] = GLFW_KEY_6; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_7] = GLFW_KEY_7; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_8] = GLFW_KEY_8; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_9] = GLFW_KEY_9; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_0] = GLFW_KEY_0; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_SPACE] = GLFW_KEY_SPACE; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_MINUS] = GLFW_KEY_MINUS; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_EQUAL] = GLFW_KEY_EQUAL; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_Q] = GLFW_KEY_Q; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_W] = GLFW_KEY_W; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_E] = GLFW_KEY_E; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_R] = GLFW_KEY_R; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_T] = GLFW_KEY_T; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_Y] = GLFW_KEY_Y; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_U] = GLFW_KEY_U; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_I] = GLFW_KEY_I; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_O] = GLFW_KEY_O; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_P] = GLFW_KEY_P; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_LEFTBRACE] = GLFW_KEY_LEFT_BRACKET; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_RIGHTBRACE] = GLFW_KEY_RIGHT_BRACKET; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_A] = GLFW_KEY_A; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_S] = GLFW_KEY_S; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_D] = GLFW_KEY_D; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F] = GLFW_KEY_F; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_G] = GLFW_KEY_G; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_H] = GLFW_KEY_H; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_J] = GLFW_KEY_J; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_K] = GLFW_KEY_K; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_L] = GLFW_KEY_L; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_SEMICOLON] = GLFW_KEY_SEMICOLON; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_APOSTROPHE] = GLFW_KEY_APOSTROPHE; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_Z] = GLFW_KEY_Z; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_X] = GLFW_KEY_X; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_C] = GLFW_KEY_C; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_V] = GLFW_KEY_V; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_B] = GLFW_KEY_B; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_N] = GLFW_KEY_N; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_M] = GLFW_KEY_M; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_COMMA] = GLFW_KEY_COMMA; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_DOT] = GLFW_KEY_PERIOD; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_SLASH] = GLFW_KEY_SLASH; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_BACKSLASH] = GLFW_KEY_BACKSLASH; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_ESC] = GLFW_KEY_ESCAPE; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_TAB] = GLFW_KEY_TAB; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_LEFTSHIFT] = GLFW_KEY_LEFT_SHIFT; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_RIGHTSHIFT] = GLFW_KEY_RIGHT_SHIFT; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_LEFTCTRL] = GLFW_KEY_LEFT_CONTROL; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_RIGHTCTRL] = GLFW_KEY_RIGHT_CONTROL; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_LEFTALT] = GLFW_KEY_LEFT_ALT; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_RIGHTALT] = GLFW_KEY_RIGHT_ALT; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_LEFTMETA] = GLFW_KEY_LEFT_SUPER; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_RIGHTMETA] = GLFW_KEY_RIGHT_SUPER; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_MENU] = GLFW_KEY_MENU; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_NUMLOCK] = GLFW_KEY_NUM_LOCK; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_CAPSLOCK] = GLFW_KEY_CAPS_LOCK; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_PRINT] = GLFW_KEY_PRINT_SCREEN; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_SCROLLLOCK] = GLFW_KEY_SCROLL_LOCK; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_PAUSE] = GLFW_KEY_PAUSE; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_DELETE] = GLFW_KEY_DELETE; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_BACKSPACE] = GLFW_KEY_BACKSPACE; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_ENTER] = GLFW_KEY_ENTER; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_HOME] = GLFW_KEY_HOME; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_END] = GLFW_KEY_END; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_PAGEUP] = GLFW_KEY_PAGE_UP; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_PAGEDOWN] = GLFW_KEY_PAGE_DOWN; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_INSERT] = GLFW_KEY_INSERT; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_LEFT] = GLFW_KEY_LEFT; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_RIGHT] = GLFW_KEY_RIGHT; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_DOWN] = GLFW_KEY_DOWN; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_UP] = GLFW_KEY_UP; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F1] = GLFW_KEY_F1; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F2] = GLFW_KEY_F2; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F3] = GLFW_KEY_F3; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F4] = GLFW_KEY_F4; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F5] = GLFW_KEY_F5; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F6] = GLFW_KEY_F6; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F7] = GLFW_KEY_F7; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F8] = GLFW_KEY_F8; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F9] = GLFW_KEY_F9; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F10] = GLFW_KEY_F10; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F11] = GLFW_KEY_F11; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F12] = GLFW_KEY_F12; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F13] = GLFW_KEY_F13; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F14] = GLFW_KEY_F14; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F15] = GLFW_KEY_F15; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F16] = GLFW_KEY_F16; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F17] = GLFW_KEY_F17; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F18] = GLFW_KEY_F18; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F19] = GLFW_KEY_F19; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F20] = GLFW_KEY_F20; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F21] = GLFW_KEY_F21; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F22] = GLFW_KEY_F22; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F23] = GLFW_KEY_F23; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_F24] = GLFW_KEY_F24; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KPSLASH] = GLFW_KEY_KP_DIVIDE; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KPDOT] = GLFW_KEY_KP_MULTIPLY; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KPMINUS] = GLFW_KEY_KP_SUBTRACT; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KPPLUS] = GLFW_KEY_KP_ADD; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KP0] = GLFW_KEY_KP_0; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KP1] = GLFW_KEY_KP_1; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KP2] = GLFW_KEY_KP_2; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KP3] = GLFW_KEY_KP_3; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KP4] = GLFW_KEY_KP_4; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KP5] = GLFW_KEY_KP_5; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KP6] = GLFW_KEY_KP_6; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KP7] = GLFW_KEY_KP_7; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KP8] = GLFW_KEY_KP_8; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KP9] = GLFW_KEY_KP_9; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KPCOMMA] = GLFW_KEY_KP_DECIMAL; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KPEQUAL] = GLFW_KEY_KP_EQUAL; \
GLFW_XKB_GLOBAL_NAME.keycodes[KEY_KPENTER] = GLFW_KEY_KP_ENTER; \
\
for (scancode = 0; scancode < 256; scancode++) \
{ \
if (GLFW_XKB_GLOBAL_NAME.keycodes[scancode] > 0) \
GLFW_XKB_GLOBAL_NAME.scancodes[GLFW_XKB_GLOBAL_NAME.keycodes[scancode]] = scancode; \
} \
\
}
#define xkb_glfw_compile_keymap(map_str) { \
const char* locale = NULL; \
struct xkb_state* state = NULL; \
struct xkb_keymap* keymap = NULL; \
struct xkb_compose_table* compose_table = NULL; \
struct xkb_compose_state* compose_state = NULL; \
\
keymap = xkb_keymap_new_from_string(GLFW_XKB_GLOBAL_NAME.context, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, 0); \
if (!keymap) _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to compile XKB keymap"); \
else { \
state = xkb_state_new(keymap); \
if (!state) { \
_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to create XKB state"); \
xkb_keymap_unref(keymap); keymap = NULL; \
} else { \
/* Look up the preferred locale, falling back to "C" as default. */ \
locale = getenv("LC_ALL"); \
if (!locale) locale = getenv("LC_CTYPE"); \
if (!locale) locale = getenv("LANG"); \
if (!locale) locale = "C"; \
compose_table = xkb_compose_table_new_from_locale(GLFW_XKB_GLOBAL_NAME.context, locale, XKB_COMPOSE_COMPILE_NO_FLAGS); \
if (!compose_table) { \
_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to create XKB compose table"); \
xkb_keymap_unref(keymap); keymap = NULL; \
xkb_state_unref(state); state = NULL; \
} else { \
compose_state = xkb_compose_state_new(compose_table, XKB_COMPOSE_STATE_NO_FLAGS); \
xkb_compose_table_unref(compose_table); compose_table = NULL; \
if (!compose_state) { \
_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to create XKB compose state"); \
xkb_keymap_unref(keymap); keymap = NULL; \
xkb_state_unref(state); state = NULL; \
}\
} \
} \
} \
if (keymap && state && compose_state) { \
if (GLFW_XKB_GLOBAL_NAME.composeState) xkb_compose_state_unref(GLFW_XKB_GLOBAL_NAME.composeState); \
GLFW_XKB_GLOBAL_NAME.composeState = compose_state; \
if (GLFW_XKB_GLOBAL_NAME.keymap) xkb_keymap_unref(GLFW_XKB_GLOBAL_NAME.keymap); \
GLFW_XKB_GLOBAL_NAME.keymap = keymap; \
if (GLFW_XKB_GLOBAL_NAME.state) xkb_state_unref(GLFW_XKB_GLOBAL_NAME.state); \
GLFW_XKB_GLOBAL_NAME.state = state; \
}\
if (GLFW_XKB_GLOBAL_NAME.keymap) { \
GLFW_XKB_GLOBAL_NAME.controlMask = 1 << xkb_keymap_mod_get_index(GLFW_XKB_GLOBAL_NAME.keymap, "Control"); \
GLFW_XKB_GLOBAL_NAME.altMask = 1 << xkb_keymap_mod_get_index(GLFW_XKB_GLOBAL_NAME.keymap, "Mod1"); \
GLFW_XKB_GLOBAL_NAME.shiftMask = 1 << xkb_keymap_mod_get_index(GLFW_XKB_GLOBAL_NAME.keymap, "Shift"); \
GLFW_XKB_GLOBAL_NAME.superMask = 1 << xkb_keymap_mod_get_index(GLFW_XKB_GLOBAL_NAME.keymap, "Mod4"); \
GLFW_XKB_GLOBAL_NAME.capsLockMask = 1 << xkb_keymap_mod_get_index(GLFW_XKB_GLOBAL_NAME.keymap, "Lock"); \
GLFW_XKB_GLOBAL_NAME.numLockMask = 1 << xkb_keymap_mod_get_index(GLFW_XKB_GLOBAL_NAME.keymap, "Mod2"); \
} \
}
#define xkb_glfw_update_modifiers(depressed, latched, locked, group) {\
xkb_mod_mask_t mask; \
unsigned int modifiers = 0; \
if (!GLFW_XKB_GLOBAL_NAME.keymap) return; \
xkb_state_update_mask(GLFW_XKB_GLOBAL_NAME.state, depressed, latched, locked, 0, 0, group); \
mask = xkb_state_serialize_mods(GLFW_XKB_GLOBAL_NAME.state, XKB_STATE_MODS_DEPRESSED | XKB_STATE_LAYOUT_DEPRESSED | XKB_STATE_MODS_LATCHED | XKB_STATE_LAYOUT_LATCHED); \
if (mask & GLFW_XKB_GLOBAL_NAME.controlMask) modifiers |= GLFW_MOD_CONTROL; \
if (mask & GLFW_XKB_GLOBAL_NAME.altMask) modifiers |= GLFW_MOD_ALT; \
if (mask & GLFW_XKB_GLOBAL_NAME.shiftMask) modifiers |= GLFW_MOD_SHIFT; \
if (mask & GLFW_XKB_GLOBAL_NAME.superMask) modifiers |= GLFW_MOD_SUPER; \
if (mask & GLFW_XKB_GLOBAL_NAME.capsLockMask) modifiers |= GLFW_MOD_CAPS_LOCK; \
if (mask & GLFW_XKB_GLOBAL_NAME.numLockMask) modifiers |= GLFW_MOD_NUM_LOCK; \
GLFW_XKB_GLOBAL_NAME.modifiers = modifiers; \
}
#define xkb_glfw_to_glfw_key_code(key) \
((key < sizeof(GLFW_XKB_GLOBAL_NAME.keycodes) / sizeof(GLFW_XKB_GLOBAL_NAME.keycodes[0])) ? GLFW_XKB_GLOBAL_NAME.keycodes[key] : GLFW_KEY_UNKNOWN)

940
glfw/xkb_unicode.c vendored Normal file
View File

@@ -0,0 +1,940 @@
//========================================================================
// GLFW 3.3 X11 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
/*
* Marcus: This code was originally written by Markus G. Kuhn.
* I have made some slight changes (trimmed it down a bit from >60 KB to
* 20 KB), but the functionality is the same.
*/
/*
* This module converts keysym values into the corresponding ISO 10646
* (UCS, Unicode) values.
*
* The array keysymtab[] contains pairs of X11 keysym values for graphical
* characters and the corresponding Unicode value. The function
* _glfwKeySym2Unicode() maps a keysym onto a Unicode value using a binary
* search, therefore keysymtab[] must remain SORTED by keysym value.
*
* We allow to represent any UCS character in the range U-00000000 to
* U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff.
* This admittedly does not cover the entire 31-bit space of UCS, but
* it does cover all of the characters up to U-10FFFF, which can be
* represented by UTF-16, and more, and it is very unlikely that higher
* UCS codes will ever be assigned by ISO. So to get Unicode character
* U+ABCD you can directly use keysym 0x0100abcd.
*
* Original author: Markus G. Kuhn <mkuhn@acm.org>, University of
* Cambridge, April 2001
*
* Special thanks to Richard Verhoeven <river@win.tue.nl> for preparing
* an initial draft of the mapping table.
*
*/
//************************************************************************
//**** KeySym to Unicode mapping table ****
//************************************************************************
static const struct codepair {
unsigned short keysym;
unsigned short ucs;
} keysymtab[] = {
{ 0x01a1, 0x0104 },
{ 0x01a2, 0x02d8 },
{ 0x01a3, 0x0141 },
{ 0x01a5, 0x013d },
{ 0x01a6, 0x015a },
{ 0x01a9, 0x0160 },
{ 0x01aa, 0x015e },
{ 0x01ab, 0x0164 },
{ 0x01ac, 0x0179 },
{ 0x01ae, 0x017d },
{ 0x01af, 0x017b },
{ 0x01b1, 0x0105 },
{ 0x01b2, 0x02db },
{ 0x01b3, 0x0142 },
{ 0x01b5, 0x013e },
{ 0x01b6, 0x015b },
{ 0x01b7, 0x02c7 },
{ 0x01b9, 0x0161 },
{ 0x01ba, 0x015f },
{ 0x01bb, 0x0165 },
{ 0x01bc, 0x017a },
{ 0x01bd, 0x02dd },
{ 0x01be, 0x017e },
{ 0x01bf, 0x017c },
{ 0x01c0, 0x0154 },
{ 0x01c3, 0x0102 },
{ 0x01c5, 0x0139 },
{ 0x01c6, 0x0106 },
{ 0x01c8, 0x010c },
{ 0x01ca, 0x0118 },
{ 0x01cc, 0x011a },
{ 0x01cf, 0x010e },
{ 0x01d0, 0x0110 },
{ 0x01d1, 0x0143 },
{ 0x01d2, 0x0147 },
{ 0x01d5, 0x0150 },
{ 0x01d8, 0x0158 },
{ 0x01d9, 0x016e },
{ 0x01db, 0x0170 },
{ 0x01de, 0x0162 },
{ 0x01e0, 0x0155 },
{ 0x01e3, 0x0103 },
{ 0x01e5, 0x013a },
{ 0x01e6, 0x0107 },
{ 0x01e8, 0x010d },
{ 0x01ea, 0x0119 },
{ 0x01ec, 0x011b },
{ 0x01ef, 0x010f },
{ 0x01f0, 0x0111 },
{ 0x01f1, 0x0144 },
{ 0x01f2, 0x0148 },
{ 0x01f5, 0x0151 },
{ 0x01f8, 0x0159 },
{ 0x01f9, 0x016f },
{ 0x01fb, 0x0171 },
{ 0x01fe, 0x0163 },
{ 0x01ff, 0x02d9 },
{ 0x02a1, 0x0126 },
{ 0x02a6, 0x0124 },
{ 0x02a9, 0x0130 },
{ 0x02ab, 0x011e },
{ 0x02ac, 0x0134 },
{ 0x02b1, 0x0127 },
{ 0x02b6, 0x0125 },
{ 0x02b9, 0x0131 },
{ 0x02bb, 0x011f },
{ 0x02bc, 0x0135 },
{ 0x02c5, 0x010a },
{ 0x02c6, 0x0108 },
{ 0x02d5, 0x0120 },
{ 0x02d8, 0x011c },
{ 0x02dd, 0x016c },
{ 0x02de, 0x015c },
{ 0x02e5, 0x010b },
{ 0x02e6, 0x0109 },
{ 0x02f5, 0x0121 },
{ 0x02f8, 0x011d },
{ 0x02fd, 0x016d },
{ 0x02fe, 0x015d },
{ 0x03a2, 0x0138 },
{ 0x03a3, 0x0156 },
{ 0x03a5, 0x0128 },
{ 0x03a6, 0x013b },
{ 0x03aa, 0x0112 },
{ 0x03ab, 0x0122 },
{ 0x03ac, 0x0166 },
{ 0x03b3, 0x0157 },
{ 0x03b5, 0x0129 },
{ 0x03b6, 0x013c },
{ 0x03ba, 0x0113 },
{ 0x03bb, 0x0123 },
{ 0x03bc, 0x0167 },
{ 0x03bd, 0x014a },
{ 0x03bf, 0x014b },
{ 0x03c0, 0x0100 },
{ 0x03c7, 0x012e },
{ 0x03cc, 0x0116 },
{ 0x03cf, 0x012a },
{ 0x03d1, 0x0145 },
{ 0x03d2, 0x014c },
{ 0x03d3, 0x0136 },
{ 0x03d9, 0x0172 },
{ 0x03dd, 0x0168 },
{ 0x03de, 0x016a },
{ 0x03e0, 0x0101 },
{ 0x03e7, 0x012f },
{ 0x03ec, 0x0117 },
{ 0x03ef, 0x012b },
{ 0x03f1, 0x0146 },
{ 0x03f2, 0x014d },
{ 0x03f3, 0x0137 },
{ 0x03f9, 0x0173 },
{ 0x03fd, 0x0169 },
{ 0x03fe, 0x016b },
{ 0x047e, 0x203e },
{ 0x04a1, 0x3002 },
{ 0x04a2, 0x300c },
{ 0x04a3, 0x300d },
{ 0x04a4, 0x3001 },
{ 0x04a5, 0x30fb },
{ 0x04a6, 0x30f2 },
{ 0x04a7, 0x30a1 },
{ 0x04a8, 0x30a3 },
{ 0x04a9, 0x30a5 },
{ 0x04aa, 0x30a7 },
{ 0x04ab, 0x30a9 },
{ 0x04ac, 0x30e3 },
{ 0x04ad, 0x30e5 },
{ 0x04ae, 0x30e7 },
{ 0x04af, 0x30c3 },
{ 0x04b0, 0x30fc },
{ 0x04b1, 0x30a2 },
{ 0x04b2, 0x30a4 },
{ 0x04b3, 0x30a6 },
{ 0x04b4, 0x30a8 },
{ 0x04b5, 0x30aa },
{ 0x04b6, 0x30ab },
{ 0x04b7, 0x30ad },
{ 0x04b8, 0x30af },
{ 0x04b9, 0x30b1 },
{ 0x04ba, 0x30b3 },
{ 0x04bb, 0x30b5 },
{ 0x04bc, 0x30b7 },
{ 0x04bd, 0x30b9 },
{ 0x04be, 0x30bb },
{ 0x04bf, 0x30bd },
{ 0x04c0, 0x30bf },
{ 0x04c1, 0x30c1 },
{ 0x04c2, 0x30c4 },
{ 0x04c3, 0x30c6 },
{ 0x04c4, 0x30c8 },
{ 0x04c5, 0x30ca },
{ 0x04c6, 0x30cb },
{ 0x04c7, 0x30cc },
{ 0x04c8, 0x30cd },
{ 0x04c9, 0x30ce },
{ 0x04ca, 0x30cf },
{ 0x04cb, 0x30d2 },
{ 0x04cc, 0x30d5 },
{ 0x04cd, 0x30d8 },
{ 0x04ce, 0x30db },
{ 0x04cf, 0x30de },
{ 0x04d0, 0x30df },
{ 0x04d1, 0x30e0 },
{ 0x04d2, 0x30e1 },
{ 0x04d3, 0x30e2 },
{ 0x04d4, 0x30e4 },
{ 0x04d5, 0x30e6 },
{ 0x04d6, 0x30e8 },
{ 0x04d7, 0x30e9 },
{ 0x04d8, 0x30ea },
{ 0x04d9, 0x30eb },
{ 0x04da, 0x30ec },
{ 0x04db, 0x30ed },
{ 0x04dc, 0x30ef },
{ 0x04dd, 0x30f3 },
{ 0x04de, 0x309b },
{ 0x04df, 0x309c },
{ 0x05ac, 0x060c },
{ 0x05bb, 0x061b },
{ 0x05bf, 0x061f },
{ 0x05c1, 0x0621 },
{ 0x05c2, 0x0622 },
{ 0x05c3, 0x0623 },
{ 0x05c4, 0x0624 },
{ 0x05c5, 0x0625 },
{ 0x05c6, 0x0626 },
{ 0x05c7, 0x0627 },
{ 0x05c8, 0x0628 },
{ 0x05c9, 0x0629 },
{ 0x05ca, 0x062a },
{ 0x05cb, 0x062b },
{ 0x05cc, 0x062c },
{ 0x05cd, 0x062d },
{ 0x05ce, 0x062e },
{ 0x05cf, 0x062f },
{ 0x05d0, 0x0630 },
{ 0x05d1, 0x0631 },
{ 0x05d2, 0x0632 },
{ 0x05d3, 0x0633 },
{ 0x05d4, 0x0634 },
{ 0x05d5, 0x0635 },
{ 0x05d6, 0x0636 },
{ 0x05d7, 0x0637 },
{ 0x05d8, 0x0638 },
{ 0x05d9, 0x0639 },
{ 0x05da, 0x063a },
{ 0x05e0, 0x0640 },
{ 0x05e1, 0x0641 },
{ 0x05e2, 0x0642 },
{ 0x05e3, 0x0643 },
{ 0x05e4, 0x0644 },
{ 0x05e5, 0x0645 },
{ 0x05e6, 0x0646 },
{ 0x05e7, 0x0647 },
{ 0x05e8, 0x0648 },
{ 0x05e9, 0x0649 },
{ 0x05ea, 0x064a },
{ 0x05eb, 0x064b },
{ 0x05ec, 0x064c },
{ 0x05ed, 0x064d },
{ 0x05ee, 0x064e },
{ 0x05ef, 0x064f },
{ 0x05f0, 0x0650 },
{ 0x05f1, 0x0651 },
{ 0x05f2, 0x0652 },
{ 0x06a1, 0x0452 },
{ 0x06a2, 0x0453 },
{ 0x06a3, 0x0451 },
{ 0x06a4, 0x0454 },
{ 0x06a5, 0x0455 },
{ 0x06a6, 0x0456 },
{ 0x06a7, 0x0457 },
{ 0x06a8, 0x0458 },
{ 0x06a9, 0x0459 },
{ 0x06aa, 0x045a },
{ 0x06ab, 0x045b },
{ 0x06ac, 0x045c },
{ 0x06ae, 0x045e },
{ 0x06af, 0x045f },
{ 0x06b0, 0x2116 },
{ 0x06b1, 0x0402 },
{ 0x06b2, 0x0403 },
{ 0x06b3, 0x0401 },
{ 0x06b4, 0x0404 },
{ 0x06b5, 0x0405 },
{ 0x06b6, 0x0406 },
{ 0x06b7, 0x0407 },
{ 0x06b8, 0x0408 },
{ 0x06b9, 0x0409 },
{ 0x06ba, 0x040a },
{ 0x06bb, 0x040b },
{ 0x06bc, 0x040c },
{ 0x06be, 0x040e },
{ 0x06bf, 0x040f },
{ 0x06c0, 0x044e },
{ 0x06c1, 0x0430 },
{ 0x06c2, 0x0431 },
{ 0x06c3, 0x0446 },
{ 0x06c4, 0x0434 },
{ 0x06c5, 0x0435 },
{ 0x06c6, 0x0444 },
{ 0x06c7, 0x0433 },
{ 0x06c8, 0x0445 },
{ 0x06c9, 0x0438 },
{ 0x06ca, 0x0439 },
{ 0x06cb, 0x043a },
{ 0x06cc, 0x043b },
{ 0x06cd, 0x043c },
{ 0x06ce, 0x043d },
{ 0x06cf, 0x043e },
{ 0x06d0, 0x043f },
{ 0x06d1, 0x044f },
{ 0x06d2, 0x0440 },
{ 0x06d3, 0x0441 },
{ 0x06d4, 0x0442 },
{ 0x06d5, 0x0443 },
{ 0x06d6, 0x0436 },
{ 0x06d7, 0x0432 },
{ 0x06d8, 0x044c },
{ 0x06d9, 0x044b },
{ 0x06da, 0x0437 },
{ 0x06db, 0x0448 },
{ 0x06dc, 0x044d },
{ 0x06dd, 0x0449 },
{ 0x06de, 0x0447 },
{ 0x06df, 0x044a },
{ 0x06e0, 0x042e },
{ 0x06e1, 0x0410 },
{ 0x06e2, 0x0411 },
{ 0x06e3, 0x0426 },
{ 0x06e4, 0x0414 },
{ 0x06e5, 0x0415 },
{ 0x06e6, 0x0424 },
{ 0x06e7, 0x0413 },
{ 0x06e8, 0x0425 },
{ 0x06e9, 0x0418 },
{ 0x06ea, 0x0419 },
{ 0x06eb, 0x041a },
{ 0x06ec, 0x041b },
{ 0x06ed, 0x041c },
{ 0x06ee, 0x041d },
{ 0x06ef, 0x041e },
{ 0x06f0, 0x041f },
{ 0x06f1, 0x042f },
{ 0x06f2, 0x0420 },
{ 0x06f3, 0x0421 },
{ 0x06f4, 0x0422 },
{ 0x06f5, 0x0423 },
{ 0x06f6, 0x0416 },
{ 0x06f7, 0x0412 },
{ 0x06f8, 0x042c },
{ 0x06f9, 0x042b },
{ 0x06fa, 0x0417 },
{ 0x06fb, 0x0428 },
{ 0x06fc, 0x042d },
{ 0x06fd, 0x0429 },
{ 0x06fe, 0x0427 },
{ 0x06ff, 0x042a },
{ 0x07a1, 0x0386 },
{ 0x07a2, 0x0388 },
{ 0x07a3, 0x0389 },
{ 0x07a4, 0x038a },
{ 0x07a5, 0x03aa },
{ 0x07a7, 0x038c },
{ 0x07a8, 0x038e },
{ 0x07a9, 0x03ab },
{ 0x07ab, 0x038f },
{ 0x07ae, 0x0385 },
{ 0x07af, 0x2015 },
{ 0x07b1, 0x03ac },
{ 0x07b2, 0x03ad },
{ 0x07b3, 0x03ae },
{ 0x07b4, 0x03af },
{ 0x07b5, 0x03ca },
{ 0x07b6, 0x0390 },
{ 0x07b7, 0x03cc },
{ 0x07b8, 0x03cd },
{ 0x07b9, 0x03cb },
{ 0x07ba, 0x03b0 },
{ 0x07bb, 0x03ce },
{ 0x07c1, 0x0391 },
{ 0x07c2, 0x0392 },
{ 0x07c3, 0x0393 },
{ 0x07c4, 0x0394 },
{ 0x07c5, 0x0395 },
{ 0x07c6, 0x0396 },
{ 0x07c7, 0x0397 },
{ 0x07c8, 0x0398 },
{ 0x07c9, 0x0399 },
{ 0x07ca, 0x039a },
{ 0x07cb, 0x039b },
{ 0x07cc, 0x039c },
{ 0x07cd, 0x039d },
{ 0x07ce, 0x039e },
{ 0x07cf, 0x039f },
{ 0x07d0, 0x03a0 },
{ 0x07d1, 0x03a1 },
{ 0x07d2, 0x03a3 },
{ 0x07d4, 0x03a4 },
{ 0x07d5, 0x03a5 },
{ 0x07d6, 0x03a6 },
{ 0x07d7, 0x03a7 },
{ 0x07d8, 0x03a8 },
{ 0x07d9, 0x03a9 },
{ 0x07e1, 0x03b1 },
{ 0x07e2, 0x03b2 },
{ 0x07e3, 0x03b3 },
{ 0x07e4, 0x03b4 },
{ 0x07e5, 0x03b5 },
{ 0x07e6, 0x03b6 },
{ 0x07e7, 0x03b7 },
{ 0x07e8, 0x03b8 },
{ 0x07e9, 0x03b9 },
{ 0x07ea, 0x03ba },
{ 0x07eb, 0x03bb },
{ 0x07ec, 0x03bc },
{ 0x07ed, 0x03bd },
{ 0x07ee, 0x03be },
{ 0x07ef, 0x03bf },
{ 0x07f0, 0x03c0 },
{ 0x07f1, 0x03c1 },
{ 0x07f2, 0x03c3 },
{ 0x07f3, 0x03c2 },
{ 0x07f4, 0x03c4 },
{ 0x07f5, 0x03c5 },
{ 0x07f6, 0x03c6 },
{ 0x07f7, 0x03c7 },
{ 0x07f8, 0x03c8 },
{ 0x07f9, 0x03c9 },
{ 0x08a1, 0x23b7 },
{ 0x08a2, 0x250c },
{ 0x08a3, 0x2500 },
{ 0x08a4, 0x2320 },
{ 0x08a5, 0x2321 },
{ 0x08a6, 0x2502 },
{ 0x08a7, 0x23a1 },
{ 0x08a8, 0x23a3 },
{ 0x08a9, 0x23a4 },
{ 0x08aa, 0x23a6 },
{ 0x08ab, 0x239b },
{ 0x08ac, 0x239d },
{ 0x08ad, 0x239e },
{ 0x08ae, 0x23a0 },
{ 0x08af, 0x23a8 },
{ 0x08b0, 0x23ac },
{ 0x08bc, 0x2264 },
{ 0x08bd, 0x2260 },
{ 0x08be, 0x2265 },
{ 0x08bf, 0x222b },
{ 0x08c0, 0x2234 },
{ 0x08c1, 0x221d },
{ 0x08c2, 0x221e },
{ 0x08c5, 0x2207 },
{ 0x08c8, 0x223c },
{ 0x08c9, 0x2243 },
{ 0x08cd, 0x21d4 },
{ 0x08ce, 0x21d2 },
{ 0x08cf, 0x2261 },
{ 0x08d6, 0x221a },
{ 0x08da, 0x2282 },
{ 0x08db, 0x2283 },
{ 0x08dc, 0x2229 },
{ 0x08dd, 0x222a },
{ 0x08de, 0x2227 },
{ 0x08df, 0x2228 },
{ 0x08ef, 0x2202 },
{ 0x08f6, 0x0192 },
{ 0x08fb, 0x2190 },
{ 0x08fc, 0x2191 },
{ 0x08fd, 0x2192 },
{ 0x08fe, 0x2193 },
{ 0x09e0, 0x25c6 },
{ 0x09e1, 0x2592 },
{ 0x09e2, 0x2409 },
{ 0x09e3, 0x240c },
{ 0x09e4, 0x240d },
{ 0x09e5, 0x240a },
{ 0x09e8, 0x2424 },
{ 0x09e9, 0x240b },
{ 0x09ea, 0x2518 },
{ 0x09eb, 0x2510 },
{ 0x09ec, 0x250c },
{ 0x09ed, 0x2514 },
{ 0x09ee, 0x253c },
{ 0x09ef, 0x23ba },
{ 0x09f0, 0x23bb },
{ 0x09f1, 0x2500 },
{ 0x09f2, 0x23bc },
{ 0x09f3, 0x23bd },
{ 0x09f4, 0x251c },
{ 0x09f5, 0x2524 },
{ 0x09f6, 0x2534 },
{ 0x09f7, 0x252c },
{ 0x09f8, 0x2502 },
{ 0x0aa1, 0x2003 },
{ 0x0aa2, 0x2002 },
{ 0x0aa3, 0x2004 },
{ 0x0aa4, 0x2005 },
{ 0x0aa5, 0x2007 },
{ 0x0aa6, 0x2008 },
{ 0x0aa7, 0x2009 },
{ 0x0aa8, 0x200a },
{ 0x0aa9, 0x2014 },
{ 0x0aaa, 0x2013 },
{ 0x0aae, 0x2026 },
{ 0x0aaf, 0x2025 },
{ 0x0ab0, 0x2153 },
{ 0x0ab1, 0x2154 },
{ 0x0ab2, 0x2155 },
{ 0x0ab3, 0x2156 },
{ 0x0ab4, 0x2157 },
{ 0x0ab5, 0x2158 },
{ 0x0ab6, 0x2159 },
{ 0x0ab7, 0x215a },
{ 0x0ab8, 0x2105 },
{ 0x0abb, 0x2012 },
{ 0x0abc, 0x2329 },
{ 0x0abe, 0x232a },
{ 0x0ac3, 0x215b },
{ 0x0ac4, 0x215c },
{ 0x0ac5, 0x215d },
{ 0x0ac6, 0x215e },
{ 0x0ac9, 0x2122 },
{ 0x0aca, 0x2613 },
{ 0x0acc, 0x25c1 },
{ 0x0acd, 0x25b7 },
{ 0x0ace, 0x25cb },
{ 0x0acf, 0x25af },
{ 0x0ad0, 0x2018 },
{ 0x0ad1, 0x2019 },
{ 0x0ad2, 0x201c },
{ 0x0ad3, 0x201d },
{ 0x0ad4, 0x211e },
{ 0x0ad6, 0x2032 },
{ 0x0ad7, 0x2033 },
{ 0x0ad9, 0x271d },
{ 0x0adb, 0x25ac },
{ 0x0adc, 0x25c0 },
{ 0x0add, 0x25b6 },
{ 0x0ade, 0x25cf },
{ 0x0adf, 0x25ae },
{ 0x0ae0, 0x25e6 },
{ 0x0ae1, 0x25ab },
{ 0x0ae2, 0x25ad },
{ 0x0ae3, 0x25b3 },
{ 0x0ae4, 0x25bd },
{ 0x0ae5, 0x2606 },
{ 0x0ae6, 0x2022 },
{ 0x0ae7, 0x25aa },
{ 0x0ae8, 0x25b2 },
{ 0x0ae9, 0x25bc },
{ 0x0aea, 0x261c },
{ 0x0aeb, 0x261e },
{ 0x0aec, 0x2663 },
{ 0x0aed, 0x2666 },
{ 0x0aee, 0x2665 },
{ 0x0af0, 0x2720 },
{ 0x0af1, 0x2020 },
{ 0x0af2, 0x2021 },
{ 0x0af3, 0x2713 },
{ 0x0af4, 0x2717 },
{ 0x0af5, 0x266f },
{ 0x0af6, 0x266d },
{ 0x0af7, 0x2642 },
{ 0x0af8, 0x2640 },
{ 0x0af9, 0x260e },
{ 0x0afa, 0x2315 },
{ 0x0afb, 0x2117 },
{ 0x0afc, 0x2038 },
{ 0x0afd, 0x201a },
{ 0x0afe, 0x201e },
{ 0x0ba3, 0x003c },
{ 0x0ba6, 0x003e },
{ 0x0ba8, 0x2228 },
{ 0x0ba9, 0x2227 },
{ 0x0bc0, 0x00af },
{ 0x0bc2, 0x22a5 },
{ 0x0bc3, 0x2229 },
{ 0x0bc4, 0x230a },
{ 0x0bc6, 0x005f },
{ 0x0bca, 0x2218 },
{ 0x0bcc, 0x2395 },
{ 0x0bce, 0x22a4 },
{ 0x0bcf, 0x25cb },
{ 0x0bd3, 0x2308 },
{ 0x0bd6, 0x222a },
{ 0x0bd8, 0x2283 },
{ 0x0bda, 0x2282 },
{ 0x0bdc, 0x22a2 },
{ 0x0bfc, 0x22a3 },
{ 0x0cdf, 0x2017 },
{ 0x0ce0, 0x05d0 },
{ 0x0ce1, 0x05d1 },
{ 0x0ce2, 0x05d2 },
{ 0x0ce3, 0x05d3 },
{ 0x0ce4, 0x05d4 },
{ 0x0ce5, 0x05d5 },
{ 0x0ce6, 0x05d6 },
{ 0x0ce7, 0x05d7 },
{ 0x0ce8, 0x05d8 },
{ 0x0ce9, 0x05d9 },
{ 0x0cea, 0x05da },
{ 0x0ceb, 0x05db },
{ 0x0cec, 0x05dc },
{ 0x0ced, 0x05dd },
{ 0x0cee, 0x05de },
{ 0x0cef, 0x05df },
{ 0x0cf0, 0x05e0 },
{ 0x0cf1, 0x05e1 },
{ 0x0cf2, 0x05e2 },
{ 0x0cf3, 0x05e3 },
{ 0x0cf4, 0x05e4 },
{ 0x0cf5, 0x05e5 },
{ 0x0cf6, 0x05e6 },
{ 0x0cf7, 0x05e7 },
{ 0x0cf8, 0x05e8 },
{ 0x0cf9, 0x05e9 },
{ 0x0cfa, 0x05ea },
{ 0x0da1, 0x0e01 },
{ 0x0da2, 0x0e02 },
{ 0x0da3, 0x0e03 },
{ 0x0da4, 0x0e04 },
{ 0x0da5, 0x0e05 },
{ 0x0da6, 0x0e06 },
{ 0x0da7, 0x0e07 },
{ 0x0da8, 0x0e08 },
{ 0x0da9, 0x0e09 },
{ 0x0daa, 0x0e0a },
{ 0x0dab, 0x0e0b },
{ 0x0dac, 0x0e0c },
{ 0x0dad, 0x0e0d },
{ 0x0dae, 0x0e0e },
{ 0x0daf, 0x0e0f },
{ 0x0db0, 0x0e10 },
{ 0x0db1, 0x0e11 },
{ 0x0db2, 0x0e12 },
{ 0x0db3, 0x0e13 },
{ 0x0db4, 0x0e14 },
{ 0x0db5, 0x0e15 },
{ 0x0db6, 0x0e16 },
{ 0x0db7, 0x0e17 },
{ 0x0db8, 0x0e18 },
{ 0x0db9, 0x0e19 },
{ 0x0dba, 0x0e1a },
{ 0x0dbb, 0x0e1b },
{ 0x0dbc, 0x0e1c },
{ 0x0dbd, 0x0e1d },
{ 0x0dbe, 0x0e1e },
{ 0x0dbf, 0x0e1f },
{ 0x0dc0, 0x0e20 },
{ 0x0dc1, 0x0e21 },
{ 0x0dc2, 0x0e22 },
{ 0x0dc3, 0x0e23 },
{ 0x0dc4, 0x0e24 },
{ 0x0dc5, 0x0e25 },
{ 0x0dc6, 0x0e26 },
{ 0x0dc7, 0x0e27 },
{ 0x0dc8, 0x0e28 },
{ 0x0dc9, 0x0e29 },
{ 0x0dca, 0x0e2a },
{ 0x0dcb, 0x0e2b },
{ 0x0dcc, 0x0e2c },
{ 0x0dcd, 0x0e2d },
{ 0x0dce, 0x0e2e },
{ 0x0dcf, 0x0e2f },
{ 0x0dd0, 0x0e30 },
{ 0x0dd1, 0x0e31 },
{ 0x0dd2, 0x0e32 },
{ 0x0dd3, 0x0e33 },
{ 0x0dd4, 0x0e34 },
{ 0x0dd5, 0x0e35 },
{ 0x0dd6, 0x0e36 },
{ 0x0dd7, 0x0e37 },
{ 0x0dd8, 0x0e38 },
{ 0x0dd9, 0x0e39 },
{ 0x0dda, 0x0e3a },
{ 0x0ddf, 0x0e3f },
{ 0x0de0, 0x0e40 },
{ 0x0de1, 0x0e41 },
{ 0x0de2, 0x0e42 },
{ 0x0de3, 0x0e43 },
{ 0x0de4, 0x0e44 },
{ 0x0de5, 0x0e45 },
{ 0x0de6, 0x0e46 },
{ 0x0de7, 0x0e47 },
{ 0x0de8, 0x0e48 },
{ 0x0de9, 0x0e49 },
{ 0x0dea, 0x0e4a },
{ 0x0deb, 0x0e4b },
{ 0x0dec, 0x0e4c },
{ 0x0ded, 0x0e4d },
{ 0x0df0, 0x0e50 },
{ 0x0df1, 0x0e51 },
{ 0x0df2, 0x0e52 },
{ 0x0df3, 0x0e53 },
{ 0x0df4, 0x0e54 },
{ 0x0df5, 0x0e55 },
{ 0x0df6, 0x0e56 },
{ 0x0df7, 0x0e57 },
{ 0x0df8, 0x0e58 },
{ 0x0df9, 0x0e59 },
{ 0x0ea1, 0x3131 },
{ 0x0ea2, 0x3132 },
{ 0x0ea3, 0x3133 },
{ 0x0ea4, 0x3134 },
{ 0x0ea5, 0x3135 },
{ 0x0ea6, 0x3136 },
{ 0x0ea7, 0x3137 },
{ 0x0ea8, 0x3138 },
{ 0x0ea9, 0x3139 },
{ 0x0eaa, 0x313a },
{ 0x0eab, 0x313b },
{ 0x0eac, 0x313c },
{ 0x0ead, 0x313d },
{ 0x0eae, 0x313e },
{ 0x0eaf, 0x313f },
{ 0x0eb0, 0x3140 },
{ 0x0eb1, 0x3141 },
{ 0x0eb2, 0x3142 },
{ 0x0eb3, 0x3143 },
{ 0x0eb4, 0x3144 },
{ 0x0eb5, 0x3145 },
{ 0x0eb6, 0x3146 },
{ 0x0eb7, 0x3147 },
{ 0x0eb8, 0x3148 },
{ 0x0eb9, 0x3149 },
{ 0x0eba, 0x314a },
{ 0x0ebb, 0x314b },
{ 0x0ebc, 0x314c },
{ 0x0ebd, 0x314d },
{ 0x0ebe, 0x314e },
{ 0x0ebf, 0x314f },
{ 0x0ec0, 0x3150 },
{ 0x0ec1, 0x3151 },
{ 0x0ec2, 0x3152 },
{ 0x0ec3, 0x3153 },
{ 0x0ec4, 0x3154 },
{ 0x0ec5, 0x3155 },
{ 0x0ec6, 0x3156 },
{ 0x0ec7, 0x3157 },
{ 0x0ec8, 0x3158 },
{ 0x0ec9, 0x3159 },
{ 0x0eca, 0x315a },
{ 0x0ecb, 0x315b },
{ 0x0ecc, 0x315c },
{ 0x0ecd, 0x315d },
{ 0x0ece, 0x315e },
{ 0x0ecf, 0x315f },
{ 0x0ed0, 0x3160 },
{ 0x0ed1, 0x3161 },
{ 0x0ed2, 0x3162 },
{ 0x0ed3, 0x3163 },
{ 0x0ed4, 0x11a8 },
{ 0x0ed5, 0x11a9 },
{ 0x0ed6, 0x11aa },
{ 0x0ed7, 0x11ab },
{ 0x0ed8, 0x11ac },
{ 0x0ed9, 0x11ad },
{ 0x0eda, 0x11ae },
{ 0x0edb, 0x11af },
{ 0x0edc, 0x11b0 },
{ 0x0edd, 0x11b1 },
{ 0x0ede, 0x11b2 },
{ 0x0edf, 0x11b3 },
{ 0x0ee0, 0x11b4 },
{ 0x0ee1, 0x11b5 },
{ 0x0ee2, 0x11b6 },
{ 0x0ee3, 0x11b7 },
{ 0x0ee4, 0x11b8 },
{ 0x0ee5, 0x11b9 },
{ 0x0ee6, 0x11ba },
{ 0x0ee7, 0x11bb },
{ 0x0ee8, 0x11bc },
{ 0x0ee9, 0x11bd },
{ 0x0eea, 0x11be },
{ 0x0eeb, 0x11bf },
{ 0x0eec, 0x11c0 },
{ 0x0eed, 0x11c1 },
{ 0x0eee, 0x11c2 },
{ 0x0eef, 0x316d },
{ 0x0ef0, 0x3171 },
{ 0x0ef1, 0x3178 },
{ 0x0ef2, 0x317f },
{ 0x0ef3, 0x3181 },
{ 0x0ef4, 0x3184 },
{ 0x0ef5, 0x3186 },
{ 0x0ef6, 0x318d },
{ 0x0ef7, 0x318e },
{ 0x0ef8, 0x11eb },
{ 0x0ef9, 0x11f0 },
{ 0x0efa, 0x11f9 },
{ 0x0eff, 0x20a9 },
{ 0x13a4, 0x20ac },
{ 0x13bc, 0x0152 },
{ 0x13bd, 0x0153 },
{ 0x13be, 0x0178 },
{ 0x20ac, 0x20ac },
{ 0xfe50, '`' },
{ 0xfe51, 0x00b4 },
{ 0xfe52, '^' },
{ 0xfe53, '~' },
{ 0xfe54, 0x00af },
{ 0xfe55, 0x02d8 },
{ 0xfe56, 0x02d9 },
{ 0xfe57, 0x00a8 },
{ 0xfe58, 0x02da },
{ 0xfe59, 0x02dd },
{ 0xfe5a, 0x02c7 },
{ 0xfe5b, 0x00b8 },
{ 0xfe5c, 0x02db },
{ 0xfe5d, 0x037a },
{ 0xfe5e, 0x309b },
{ 0xfe5f, 0x309c },
{ 0xfe63, '/' },
{ 0xfe64, 0x02bc },
{ 0xfe65, 0x02bd },
{ 0xfe66, 0x02f5 },
{ 0xfe67, 0x02f3 },
{ 0xfe68, 0x02cd },
{ 0xfe69, 0xa788 },
{ 0xfe6a, 0x02f7 },
{ 0xfe6e, ',' },
{ 0xfe6f, 0x00a4 },
{ 0xfe80, 'a' }, // XK_dead_a
{ 0xfe81, 'A' }, // XK_dead_A
{ 0xfe82, 'e' }, // XK_dead_e
{ 0xfe83, 'E' }, // XK_dead_E
{ 0xfe84, 'i' }, // XK_dead_i
{ 0xfe85, 'I' }, // XK_dead_I
{ 0xfe86, 'o' }, // XK_dead_o
{ 0xfe87, 'O' }, // XK_dead_O
{ 0xfe88, 'u' }, // XK_dead_u
{ 0xfe89, 'U' }, // XK_dead_U
{ 0xfe8a, 0x0259 },
{ 0xfe8b, 0x018f },
{ 0xfe8c, 0x00b5 },
{ 0xfe90, '_' },
{ 0xfe91, 0x02c8 },
{ 0xfe92, 0x02cc },
{ 0xff80 /*XKB_KEY_KP_Space*/, ' ' },
{ 0xff95 /*XKB_KEY_KP_7*/, 0x0037 },
{ 0xff96 /*XKB_KEY_KP_4*/, 0x0034 },
{ 0xff97 /*XKB_KEY_KP_8*/, 0x0038 },
{ 0xff98 /*XKB_KEY_KP_6*/, 0x0036 },
{ 0xff99 /*XKB_KEY_KP_2*/, 0x0032 },
{ 0xff9a /*XKB_KEY_KP_9*/, 0x0039 },
{ 0xff9b /*XKB_KEY_KP_3*/, 0x0033 },
{ 0xff9c /*XKB_KEY_KP_1*/, 0x0031 },
{ 0xff9d /*XKB_KEY_KP_5*/, 0x0035 },
{ 0xff9e /*XKB_KEY_KP_0*/, 0x0030 },
{ 0xffaa /*XKB_KEY_KP_Multiply*/, '*' },
{ 0xffab /*XKB_KEY_KP_Add*/, '+' },
{ 0xffac /*XKB_KEY_KP_Separator*/, ',' },
{ 0xffad /*XKB_KEY_KP_Subtract*/, '-' },
{ 0xffae /*XKB_KEY_KP_Decimal*/, '.' },
{ 0xffaf /*XKB_KEY_KP_Divide*/, '/' },
{ 0xffb0 /*XKB_KEY_KP_0*/, 0x0030 },
{ 0xffb1 /*XKB_KEY_KP_1*/, 0x0031 },
{ 0xffb2 /*XKB_KEY_KP_2*/, 0x0032 },
{ 0xffb3 /*XKB_KEY_KP_3*/, 0x0033 },
{ 0xffb4 /*XKB_KEY_KP_4*/, 0x0034 },
{ 0xffb5 /*XKB_KEY_KP_5*/, 0x0035 },
{ 0xffb6 /*XKB_KEY_KP_6*/, 0x0036 },
{ 0xffb7 /*XKB_KEY_KP_7*/, 0x0037 },
{ 0xffb8 /*XKB_KEY_KP_8*/, 0x0038 },
{ 0xffb9 /*XKB_KEY_KP_9*/, 0x0039 },
{ 0xffbd /*XKB_KEY_KP_Equal*/, '=' }
};
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
// Convert XKB KeySym to Unicode
//
long _glfwKeySym2Unicode(unsigned int keysym)
{
int min = 0;
int max = sizeof(keysymtab) / sizeof(struct codepair) - 1;
int mid;
// First check for Latin-1 characters (1:1 mapping)
if ((keysym >= 0x0020 && keysym <= 0x007e) ||
(keysym >= 0x00a0 && keysym <= 0x00ff))
{
return keysym;
}
// Also check for directly encoded 24-bit UCS characters
if ((keysym & 0xff000000) == 0x01000000)
return keysym & 0x00ffffff;
// Binary search in table
while (max >= min)
{
mid = (min + max) / 2;
if (keysymtab[mid].keysym < keysym)
min = mid + 1;
else if (keysymtab[mid].keysym > keysym)
max = mid - 1;
else
return keysymtab[mid].ucs;
}
// No matching Unicode value found
return -1;
}

28
glfw/xkb_unicode.h vendored Normal file
View File

@@ -0,0 +1,28 @@
//========================================================================
// GLFW 3.3 Linux - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
long _glfwKeySym2Unicode(unsigned int keysym);

385
graphics-protocol.asciidoc Normal file
View File

@@ -0,0 +1,385 @@
= The terminal graphics protocol
:toc:
:toc-placement!:
The goal of this specification is to create a flexible and performant protocol
that allows the program running in the terminal, hereafter called the _client_,
to render arbitrary pixel (raster) graphics to the screen of the terminal
emulator. The major design goals are
* Should not require terminal emulators to understand image formats.
* Should allow specifying graphics to be drawn at individual pixel positions.
* The graphics should integrate with the text, in particular it should be possible to draw graphics
below as well as above the text, with alpha blending. The graphics should also scroll with the text, automatically.
* Should use optimizations when the client is running on the same computer as the terminal emulator.
For some discussion regarding the design choices, see link:../../issues/33[#33].
To see a quick demo, inside a kitty terminal run:
```
kitty icat path/to/some/image.png
```
You can also see a screenshot with more sophisticated features such as alpha-blending and text over graphics
link:https://github.com/kovidgoyal/kitty/issues/33#issuecomment-334436100[here].
Some third-party programs that use the kitty graphics protocol:
* link:https://github.com/dsanson/termpdf[termdpf] - a terminal PDF/DJVU/CBR viewer
* link:https://github.com/ranger/ranger[ranger] - a terminal file manager, with image previews, see this link:https://github.com/ranger/ranger/pull/1077[PR]
toc::[]
== Getting the window size
In order to know what size of images to display and how to position them, the client must be able to get the
window size in pixels and the number of cells per row and column. This can be done by using the `TIOCGWINSZ` ioctl.
Some code to demonstrate its use
In C:
```C
struct ttysize ts;
ioctl(0, TIOCGWINSZ, &ts);
printf("number of columns: %i, number of rows: %i, screen width: %i, screen height: %i\n", sz.ws_col, sz.ws_row, sz.ws_xpixel, sz.ws_ypixel);
```
In Python:
```py
import array, fcntl, termios
buf = array.array('H', [0, 0, 0, 0])
fcntl.ioctl(sys.stdout, termios.TIOCGWINSZ, buf)
print('number of columns: {}, number of rows: {}, screen width: {}, screen height: {}'.format(*buf))
```
Note that some terminals return `0` for the width and height values. Such terminals should be modified to return the correct values.
Examples of terminals that return correct values: `kitty, xterm`
== The graphics escape code
All graphics escape codes are of the form:
```
<ESC>_G<control data>;<payload><ESC>\
```
This is a so-called _Application Programming Command (APC)_. Most terminal
emulators ignore APC codes, making it safe to use.
The control data is a comma-separated list of `key=value` pairs. The payload
is arbitrary binary data, base64-encoded to prevent interoperation problems
with legacy terminals that get confused by control codes within an APC code.
The meaning of the payload is interpreted based on the control data.
The first step is to transmit the actual image data.
== Transferring pixel data
The first consideration when transferring data between the client and the
terminal emulator is the format in which to do so. Since there is a vast and
growing number of image formats in existence, it does not make sense to have
every terminal emulator implement support for them. Instead, the client should
send simple pixel data to the terminal emulator. The obvious downside to this
is performance, especially when the client is running on a remote machine.
Techniques for remedying this limitation are discussed later. The terminal
emulator must understand pixel data in three formats, 24-bit RGB, 32-bit RGBA and
PNG. This is specified using the `f` key in the control data. `f=32` (which is the
default) indicates 32-bit RGBA data and `f=24` indicates 24-bit RGB data and `f=100`
indicates PNG data. The PNG format is supported for convenience and a compact way
of transmitting paletted images.
=== RGB and RGBA data
In these formats the pixel data is stored directly as 3 or 4 bytes per pixel, respectively.
When specifying images in this format, the image dimensions **must** be sent in the control data.
For example:
```
<ESC>_Gf=24,s=10,v=20;<payload><ESC>\
```
Here the width and height are specified using the `s` and `v` keys respectively. Since
`f=24` there are three bytes per pixel and therefore the pixel data must be `3 * 10 * 20 = 600`
bytes.
=== PNG data
In this format any PNG image can be transmitted directly. For example:
```
<ESC>_Gf=100;<payload><ESC>\
```
The PNG format is specified using the `f=100` key. The width and height of
the image will be read from the PNG data itself. Note that if you use both PNG and
compression, then you must provide the `S` key with the size of the PNG data.
=== Compression
The client can send compressed image data to the terminal emulator, by specifying the
`o` key. Currently, only zlib based deflate compression is supported, which is specified using
`o=z`. For example,
```
<ESC>_Gf=24,s=10,v=20,o=z;<payload><ESC>\
```
This is the same as the example from the RGB data section, except that the
payload is now compressed using deflate. The terminal emulator will decompress
it before rendering. You can specify compression for any format. The terminal
emulator will decompress before interpreting the pixel data.
=== The transmission medium
The transmission medium is specified using the `t` key. The `t` key defaults to `d`
and can take the values:
|===
| Value of `t` | Meaning
| d | Direct (the data is transmitted within the escape code itself)
| f | A simple file
| t | A temporary file, the terminal emulator will delete the file after reading the pixel data
| s | A http://man7.org/linux/man-pages/man7/shm_overview.7.html[POSIX shared memory object]. The terminal emulator will delete it after reading the pixel data
|===
==== Local client
First let us consider the local client techniques (files and shared memory). Some examples:
```
<ESC>_Gf=100,t=f;<encoded /path/to/file.png><ESC>\
```
Here we tell the terminal emulator to read PNG data from the specified file of
the specified size.
```
<ESC>_Gs=10,v=2,t=s,o=z;<encoded /some-shared-memory-name><ESC>\
```
Here we tell the terminal emulator to read compressed image data from
the specified shared memory object.
The client can also specify a size and offset to tell the terminal emulator
to only read a part of the specified file. The is done using the `S` and `O`
keys respectively. For example:
```
<ESC>_Gs=10,v=2,t=s,S=80,O=10;<encoded /some-shared-memory-name><ESC>\
```
This tells the terminal emulator to read `80` bytes starting from the offset `10`
inside the specified shared memory buffer.
==== Remote client
Remote clients, those that are unable to use the filesystem/shared memory to
transmit data, must send the pixel data directly using escape codes. Since
escape codes are of limited maximum length, the data will need to be chunked up
for transfer. This is done using the `m` key. The pixel data must first be
base64 encoded then chunked up into chunks no larger than `4096` bytes. The client
then sends the graphics escape code as usual, with the addition of an `m` key that
must have the value `1` for all but the last chunk, where it must be `0`. For example,
if the data is split into three chunks, the client would send the following
sequence of escape codes to the terminal emulator:
```
<ESC>_Gs=100,v=30,m=1;<encoded pixel data first chunk><ESC>\
<ESC>_Gm=1;<encoded pixel data second chunk><ESC>\
<ESC>_Gm=0;<encoded pixel data last chunk><ESC>\
```
Note that only the first escape code needs to have the full set of control
codes such as width, height, format etc. Subsequent chunks must have
only the `m` key. The client **must** finish sending all chunks for a single image
before sending any other graphics related escape codes.
=== Detecting available transmission mediums
Since a client has no a-priori knowledge of whether it shares a filesystem/shared memory
with the terminal emulator, it can send an id with the control data, using the `i` key
(which can be an arbitrary positive integer up to 4294967295, it must not be zero).
If it does so, the terminal emulator will reply after trying to load the image, saying
whether loading was successful or not. For example:
```
<ESC>_Gi=31,s=10,v=2,t=s;<encoded /some-shared-memory-name><ESC>\
```
to which the terminal emulator will reply (after trying to load the data):
```
<ESC>_Gi=31;error message or OK<ESC>\
```
Here the `i` value will be the same as was sent by the client in the original
request. The message data will be a ASCII encoded string containing only
printable characters and spaces. The string will be `OK` if reading the pixel
data succeeded or an error message.
Sometimes, using an id is not appropriate, for example, if you do not want to
replace a previously sent image with the same id, or if you are sending a dummy
image and do not want it stored by the terminal emulator. In that case, you can
use the *query action*, set `a=q`. Then the terminal emulator will try to load
the image and respond with either OK or an error, as above, but it will not
replace an existing image with the same id, nor will it store the image.
== Display images on screen
Every transmitted image can be displayed an arbitrary number of times on the
screen, in different locations, using different parts of the source image, as
needed. You can either simultaneously transmit and display an image using the
action `a=T`, or first transmit the image with a id, such as `i=10` and then display
it with `a=p,i=10` which will display the previously transmitted image at the current
cursor position. When specifying an image id, the terminal emulator will reply with an
acknowledgement code, which will be either:
```
<ESC>_Gi=<id>;OK<ESC>\
```
when the image referred to by id was found, or
```
<ESC>_Gi=<id>;ENOENT:<some detailed error msg><ESC>\
```
when the image with the specified id was not found. This is similar to the
scheme described above for querying available transmission media, except that
here we are querying if the image with the specified id is available or needs to
be re-transmitted.
=== Controlling displayed image layout
The image is rendered at the current cursor position, from the upper left corner of
the current cell. You can also specify extra `X=3` and `Y=4` pixel offsets to display from
a different origin within the cell. Note that the offsets must be smaller that the size of the cell.
By default, the entire image will be displayed (images wider than the available
width will be truncated on the right edge). You can choose a source rectangle (in pixels)
as the part of the image to display. This is done with the keys: `x, y, w, h` which specify
the top-left corner, width and height of the source rectangle.
You can also ask the terminal emulator to display the image in a specified rectangle
(num of columns / num of lines), using the control codes `c,r`. `c` is the number of columns
and `r` the number of rows. The image will be scaled (enlarged/shrunk) as needed to fit
the specified area. Note that if you specify a start cell offset via the `X,Y` keys, it is not
added to the number of rows/columns.
Finally, you can specify the image *z-index*, i.e. the vertical stacking order. Images
placed in the same location with different z-index values will be blended if
they are semi-transparent. You can specify z-index values using the `z` key.
Negative z-index values mean that the images will be drawn under the text. This
allows rendering of text on top of images.
== Deleting images
Images can be deleted by using the delete action `a=d`. If specified without any
other keys, it will delete all images visible on screen. To delete specific images,
use the `d` key as described in the table below. Note that each value of d has
both a lowercase and an uppercase variant. The lowercase variant only deletes the
images without necessarily freeing up the stored image data, so that the images can be
re-displayed without needing to resend the data. The uppercase variants will delete
the image data as well, provided that the image is not referenced elsewhere, such as in the
scrollback buffer. The values of the `x` and `y` keys are the same as cursor positions (i.e.
x=1, y=1 is the top left cell).
|===
| Value of `d` | Meaning
| `a` or `A` | Delete all images visible on screen
| `i` or `I` | Delete all images with the specified id, specified using the `i` key.
| `c` or `C` | Delete all images that intersect with the current cursor position.
| `p` or `P` | Delete all images that intersect a specific cell, the cell is specified using the `x` and `y` keys
| `q` or `Q` | Delete all images that intersect a specific cell having a specific z-index. The cell and z-index is specified using the `x`, `y` and `z` keys.
| `x` or `X` | Delete all images that intersect the specified column, specified using the `x` key.
| `y` or `Y` | Delete all images that intersect the specified row, specified using the `y` key.
| `z` or `Z` | Delete all images that have the specified z-index, specified using the `z` key.
|===
Some examples:
```
<ESC>_Ga=d<ESC>\ # delete all visible images
<ESC>_Ga=d,i=10<ESC>\ # delete the image with id=10
<ESC>_Ga=Z,z=-1<ESC>\ # delete the images with z-index -1, also freeing up image data
<ESC>_Ga=P,x=3,y=4<ESC>\ # delete all images that intersect the cell at (3, 4)
```
=== Image persistence and storage quotas
In order to avoid *Denial-of-Service* attacks, terminal emulators should have a
maximum storage quota for image data. It should allow at least a few full
screen images. For example the quota in kitty is 320MB per buffer. When adding
a new image, if the total size exceeds the quota, the terminal emulator should
delete older images to make space for the new one.
== Control data reference
The table below shows all the control data keys as well as what values they can
take, and the default value they take when missing. All integers are 32-bit.
[cols="^1,<3,^1,<6"]
|===
|Key | Value | Default | Description
| `a` | Single character. `(t, T, q, p, d)` | `t` | The overall action this graphics command is performing.
4+^.^h| Keys for image transmission
| `f` | Positive integer. `(24, 32, 100)`. | `32` | The format in which the image data is sent.
| `t` | Single character. `(d, f, t, s)`. | `d` | The transmission medium used.
| `s` | Positive integer. | `0` | The width of the image being sent.
| `v` | Positive integer. | `0` | The height of the image being sent.
| `S` | Positive integer. | `0` | The size of data to read from a file.
| `O` | Positive integer. | `0` | The offset from which to read data from a file.
| `i` | Positive integer. `(0 - 4294967295)` | `0` | The image id
| `o` | Single character. `only z` | `null` | The type of data compression.
| `m` | zero or one | `0` | Whether there is more chunked data available.
4+^.^h| Keys for image display
| `x` | Positive integer | `0` | The left edge (in pixels) of the image area to display
| `y` | Positive integer | `0` | The top edge (in pixels) of the image area to display
| `w` | Positive integer | `0` | The width (in pixels) of the image area to display. By default, the entire width is used.
| `h` | Positive integer | `0` | The height (in pixels) of the image area to display. By default, the entire height is used
| `X` | Positive integer | `0` | The x-offset within the first cell at which to start displaying the image
| `Y` | Positive integer | `0` | The y-offset within the first cell at which to start displaying the image
| `c` | Positive integer | `0` | The number of columns to display the image over
| `r` | Positive integer | `0` | The number of rows to display the image over
| `z` | Integer | `0` | The *z-index* vertical stacking order of the image
4+^.^h| Keys for deleting images
| `d` | Single character. `(a, A, c, C, p, P, q, Q, x, X, y, Y, z, Z)`. | `a` | What to delete.
|===
== Interaction with other terminal actions
When resetting the terminal, all images that are visible on the screen must be
cleared. When switching from the main screen to the alternate screen buffer
(1049 private mode) all images in the alternate screen must be cleared, just as
all text is cleared. The clear screen escape code (usually `<ESC>[2J`) should also
clear all images. This is so that the clear command works.
The other commands to erase text must have no effect on graphics.
The dedicated delete graphics commands must be used for those.
When scrolling the screen (such as when using index cursor movement commands,
or scrolling through the history buffer), images must be scrolled along with
text. When page margins are defined and the index commands are used, only
images that are entirely within the page area (between the margins) must be
scrolled. When scrolling them would cause them to extend outside the page area,
they must be clipped.

BIN
hints_mode.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

View File

@@ -1,6 +1,7 @@
= Key encoding for extended keyboard protocol
See link:protocol-extensions.asciidoc#keyboard-handling[Keyboard Handling protocol extension]
for more information and link:key_encoding.json[for this table in JSON format].
|===
| Name | Encoded representation (base64)

121
key_encoding.json Normal file
View File

@@ -0,0 +1,121 @@
{
"0": "G",
"1": "H",
"2": "I",
"3": "J",
"4": "K",
"5": "L",
"6": "M",
"7": "N",
"8": "O",
"9": "P",
"A": "S",
"APOSTROPHE": "B",
"B": "T",
"BACKSLASH": "t",
"BACKSPACE": "1",
"C": "U",
"CAPS LOCK": ":",
"COMMA": "C",
"D": "V",
"DELETE": "3",
"DOWN": "6",
"E": "W",
"END": "-",
"ENTER": "z",
"EQUAL": "R",
"ESCAPE": "y",
"F": "X",
"F1": "/",
"F10": "]",
"F11": "{",
"F12": "}",
"F13": "@",
"F14": "%",
"F15": "$",
"F16": "#",
"F17": "BA",
"F18": "BB",
"F19": "BC",
"F2": "*",
"F20": "BD",
"F21": "BE",
"F22": "BF",
"F23": "BG",
"F24": "BH",
"F25": "BI",
"F3": "?",
"F4": "&",
"F5": "<",
"F6": ">",
"F7": "(",
"F8": ")",
"F9": "[",
"G": "Y",
"GRAVE ACCENT": "v",
"H": "Z",
"HOME": ".",
"I": "a",
"INSERT": "2",
"J": "b",
"K": "c",
"KP 0": "BJ",
"KP 1": "BK",
"KP 2": "BL",
"KP 3": "BM",
"KP 4": "BN",
"KP 5": "BO",
"KP 6": "BP",
"KP 7": "BQ",
"KP 8": "BR",
"KP 9": "BS",
"KP ADD": "BX",
"KP DECIMAL": "BT",
"KP DIVIDE": "BU",
"KP ENTER": "BY",
"KP EQUAL": "BZ",
"KP MULTIPLY": "BV",
"KP SUBTRACT": "BW",
"L": "d",
"LEFT": "5",
"LEFT ALT": "Bc",
"LEFT BRACKET": "s",
"LEFT CONTROL": "Bb",
"LEFT SHIFT": "Ba",
"LEFT SUPER": "Bd",
"M": "e",
"MINUS": "D",
"N": "f",
"NUM LOCK": "=",
"O": "g",
"P": "h",
"PAGE DOWN": "9",
"PAGE UP": "8",
"PAUSE": "!",
"PERIOD": "E",
"PRINT SCREEN": "^",
"Q": "i",
"R": "j",
"RIGHT": "4",
"RIGHT ALT": "Bg",
"RIGHT BRACKET": "u",
"RIGHT CONTROL": "Bf",
"RIGHT SHIFT": "Be",
"RIGHT SUPER": "Bh",
"S": "k",
"SCROLL LOCK": "+",
"SEMICOLON": "Q",
"SLASH": "F",
"SPACE": "A",
"T": "l",
"TAB": "0",
"U": "m",
"UP": "7",
"V": "n",
"W": "o",
"WORLD 1": "w",
"WORLD 2": "x",
"X": "p",
"Y": "q",
"Z": "r"
}

0
kittens/__init__.py Normal file
View File

0
kittens/ask/__init__.py Normal file
View File

114
kittens/ask/main.py Normal file
View File

@@ -0,0 +1,114 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
import json
import os
import readline
import sys
from kitty.cli import parse_args
from kitty.constants import cache_dir
from ..tui.operations import alternate_screen, styled
def get_history_items():
return list(map(readline.get_history_item, range(1, readline.get_current_history_length() + 1)))
def sort_key(item):
return len(item), item.lower()
class HistoryCompleter:
def __init__(self, name=None):
self.matches = []
self.history_path = None
if name:
ddir = os.path.join(cache_dir(), 'ask')
try:
os.makedirs(ddir)
except FileExistsError:
pass
self.history_path = os.path.join(ddir, name)
def complete(self, text, state):
response = None
if state == 0:
history_values = get_history_items()
if text:
self.matches = sorted(
(h for h in history_values if h and h.startswith(text)), key=sort_key)
else:
self.matches = []
try:
response = self.matches[state]
except IndexError:
response = None
return response
def __enter__(self):
if self.history_path:
if os.path.exists(self.history_path):
readline.read_history_file(self.history_path)
readline.set_completer(self.complete)
readline.parse_and_bind('tab: complete')
return self
def __exit__(self, *a):
if self.history_path:
readline.write_history_file(self.history_path)
def option_text():
return '''\
--type -t
choices=line
default=line
Type of input. Defaults to asking for a line of text.
--message -m
The message to display to the user. If not specified a default
message is shown.
--name -n
The name for this question. Used to store history of previous answers which can
be used for completions and via the browse history readline bindings.
'''
def real_main(args):
msg = 'Ask the user for input'
try:
args, items = parse_args(args[1:], option_text, '', msg, 'kitty ask')
except SystemExit as e:
print(e.args[0])
input('Press enter to quit...')
raise SystemExit(1)
readline.read_init_file()
with alternate_screen(), HistoryCompleter(args.name):
if args.message:
print(styled(args.message, bold=True))
prompt = '> '
try:
ans = input(prompt)
except (KeyboardInterrupt, EOFError):
return
print('OK:', json.dumps(ans))
def main(args=sys.argv):
try:
real_main(args)
except Exception as e:
import traceback
traceback.print_exc(file=sys.stdout)
input('Press enter to quit...')
raise SystemExit(1)

0
kittens/tui/__init__.py Normal file
View File

43
kittens/tui/handler.py Normal file
View File

@@ -0,0 +1,43 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
class Handler:
def initialize(self, screen_size, quit_loop, wakeup):
self.screen_size, self.quit_loop = screen_size, quit_loop
self.wakeup = wakeup
def on_resize(self, screen_size):
self.screen_size = screen_size
def on_term(self):
self.quit_loop(1)
def on_text(self, text, in_bracketed_paste=False):
pass
def on_key(self, key_event):
pass
def on_mouse(self, mouse_event):
pass
def on_interrupt(self):
pass
def on_eot(self):
pass
def write(self, data):
if isinstance(data, str):
data = data.encode('utf-8')
self.write_buf.append(data)
def print(self, *args, sep=' ', end='\r\n'):
data = sep.join(map(str, args)) + end
self.write(data)
def suspend(self):
return self._term_manager.suspend()

374
kittens/tui/loop.py Normal file
View File

@@ -0,0 +1,374 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
import codecs
import fcntl
import io
import os
import re
import selectors
import signal
import sys
import termios
import tty
from collections import namedtuple
from contextlib import closing, contextmanager
from functools import partial
from kitty.fast_data_types import parse_input_from_terminal, safe_pipe
from kitty.icat import screen_size
from kitty.key_encoding import (
ALT, CTRL, PRESS, RELEASE, REPEAT, SHIFT, C, D, backspace_key,
decode_key_event, enter_key
)
from .handler import Handler
from .operations import init_state, reset_state, clear_screen
def log(*a, **kw):
fd = getattr(log, 'fd', None)
if fd is None:
fd = log.fd = open('/tmp/kitten-debug', 'w')
kw['file'] = fd
print(*a, **kw)
fd.flush()
def write_all(fd, data):
if isinstance(data, str):
data = data.encode('utf-8')
while data:
n = os.write(fd, data)
if not n:
break
data = data[n:]
class TermManager:
def __init__(self, input_fd, output_fd):
self.input_fd = input_fd
self.output_fd = output_fd
self.original_fl = fcntl.fcntl(self.input_fd, fcntl.F_GETFL)
self.isatty = os.isatty(self.input_fd)
if self.isatty:
self.original_termios = termios.tcgetattr(self.input_fd)
def set_state_for_loop(self):
write_all(self.output_fd, init_state())
fcntl.fcntl(self.input_fd, fcntl.F_SETFL, self.original_fl | os.O_NONBLOCK)
if self.isatty:
tty.setraw(self.input_fd)
def reset_state_to_original(self):
if self.isatty:
termios.tcsetattr(self.input_fd, termios.TCSADRAIN, self.original_termios)
fcntl.fcntl(self.input_fd, fcntl.F_SETFL, self.original_fl)
write_all(self.output_fd, reset_state())
@contextmanager
def suspend(self):
self.reset_state_to_original()
yield self
self.set_state_for_loop()
def __enter__(self):
self.set_state_for_loop()
return self
def __exit__(self, *a):
self.reset_state_to_original()
LEFT, MIDDLE, RIGHT, FOURTH, FIFTH = 1, 2, 4, 8, 16
DRAG = REPEAT
MouseEvent = namedtuple('MouseEvent', 'x y type buttons mods')
bmap = {0: LEFT, 1: MIDDLE, 2: RIGHT}
MOTION_INDICATOR = 1 << 5
EXTRA_BUTTON_INDICATOR = 1 << 6
SHIFT_INDICATOR = 1 << 2
ALT_INDICATOR = 1 << 3
CTRL_INDICATOR = 1 << 4
def decode_sgr_mouse(text):
cb, x, y = text.split(';')
m, y = y[-1], y[:-1]
cb, x, y = map(int, (cb, x, y))
typ = RELEASE if m == 'm' else (DRAG if cb & MOTION_INDICATOR else PRESS)
buttons = 0
cb3 = cb & 3
if cb3 != 3:
if cb & EXTRA_BUTTON_INDICATOR:
buttons |= FIFTH if cb3 & 1 else FOURTH
else:
buttons |= bmap[cb3]
mods = 0
if cb & SHIFT_INDICATOR:
mods |= SHIFT
if cb & ALT_INDICATOR:
mods |= ALT
if cb & CTRL_INDICATOR:
mods |= CTRL
return MouseEvent(x, y, typ, buttons, mods)
class UnhandledException(Handler):
def __init__(self, tb):
self.tb = tb
def initialize(self, screen_size, quit_loop, wakeup):
Handler.initialize(self, screen_size, quit_loop, wakeup)
self.write(clear_screen())
self.write(self.tb.replace('\n', '\r\n'))
self.write('\r\n')
self.write('Press the Enter key to quit')
def on_key(self, key_event):
if key_event is enter_key:
self.quit_loop(1)
def on_interrupt(self):
self.quit_loop(1)
def on_eot(self):
self.quit_loop(1)
class Loop:
def __init__(self, input_fd=None, output_fd=None,
sanitize_bracketed_paste='[\x03\x04\x0e\x0f\r\x07\x7f\x8d\x8e\x8f\x90\x9b\x9d\x9e\x9f]'):
self.input_fd = sys.stdin.fileno() if input_fd is None else input_fd
self.output_fd = sys.stdout.fileno() if output_fd is None else output_fd
self.wakeup_read_fd, self.wakeup_write_fd = safe_pipe()
# For some reason on macOS the DefaultSelector fails when input_fd is
# open('/dev/tty')
self.sel = s = selectors.PollSelector()
s.register(self.input_fd, selectors.EVENT_READ, self._read_ready)
s.register(
self.wakeup_read_fd, selectors.EVENT_READ, self._wakeup_ready
)
s.register(self.output_fd, selectors.EVENT_WRITE, self._write_ready)
self.return_code = 0
self.read_allowed = True
self.read_buf = ''
self.decoder = codecs.getincrementaldecoder('utf-8')('ignore')
try:
self.iov_limit = os.sysconf('SC_IOV_MAX') - 1
except Exception:
self.iov_limit = 255
self.parse_input_from_terminal = partial(parse_input_from_terminal, self._on_text, self._on_dcs, self._on_csi, self._on_osc, self._on_pm, self._on_apc)
self.ebs_pat = re.compile('([\177\r\x03\x04])')
self.in_bracketed_paste = False
self.sanitize_bracketed_paste = bool(sanitize_bracketed_paste)
if self.sanitize_bracketed_paste:
self.sanitize_ibp_pat = re.compile(sanitize_bracketed_paste)
def _read_ready(self, handler):
if not self.read_allowed:
return
try:
data = os.read(self.input_fd, io.DEFAULT_BUFFER_SIZE)
except BlockingIOError:
return
if not data:
raise EOFError('The input stream is closed')
data = self.decoder.decode(data)
if self.read_buf:
data = self.read_buf + data
self.read_buf = data
self.handler = handler
try:
self.read_buf = self.parse_input_from_terminal(self.read_buf, self.in_bracketed_paste)
except Exception:
self.read_buf = ''
raise
finally:
del self.handler
def _on_text(self, text):
if self.in_bracketed_paste and self.sanitize_bracketed_paste:
text = self.sanitize_ibp_pat.sub('', text)
for chunk in self.ebs_pat.split(text):
if len(chunk) == 1:
if chunk == '\r':
self.handler.on_key(enter_key)
elif chunk == '\177':
self.handler.on_key(backspace_key)
elif chunk == '\x03':
self.handler.on_interrupt()
elif chunk == '\x04':
self.handler.on_eot()
else:
self.handler.on_text(chunk, self.in_bracketed_paste)
else:
self.handler.on_text(chunk, self.in_bracketed_paste)
def _on_dcs(self, dcs):
pass
def _on_csi(self, csi):
q = csi[-1]
if q in 'mM':
if csi.startswith('<'):
# SGR mouse event
try:
ev = decode_sgr_mouse(csi[1:])
except Exception:
pass
else:
self.handler.on_mouse(ev)
elif q == '~':
if csi == '200~':
self.in_bracketed_paste = True
elif csi == '201~':
self.in_bracketed_paste = False
def _on_pm(self, pm):
pass
def _on_osc(self, osc):
pass
def _on_apc(self, apc):
if apc.startswith('K'):
try:
k = decode_key_event(apc)
except Exception:
pass
else:
if k.mods is CTRL and k.type is not RELEASE:
if k.key is C:
self.handler.on_interrupt()
return
if k.key is D:
self.handler.on_eot()
return
self.handler.on_key(k)
def _write_ready(self, handler):
if len(handler.write_buf) > self.iov_limit:
handler.write_buf[self.iov_limit - 1] = b''.join(handler.write_buf[self.iov_limit - 1:])
del handler.write_buf[self.iov_limit:]
sizes = tuple(map(len, handler.write_buf))
written = os.writev(self.output_fd, handler.write_buf)
if not written:
raise EOFError('The output stream is closed')
if written >= sum(sizes):
handler.write_buf = []
else:
consumed = 0
for i, buf in enumerate(handler.write_buf):
if not written:
break
if len(buf) <= written:
written -= len(buf)
consumed += 1
continue
handler.write_buf[i] = buf[written:]
break
del handler.write_buf[:consumed]
def _wakeup_ready(self, handler):
data = os.read(self.wakeup_read_fd, 1024)
if b'r' in data:
screen_size.changed = True
handler.on_resize(screen_size())
if b't' in data:
handler.on_term()
if b'i' in data:
handler.on_interrupt()
def _wakeup_write(self, val):
while not os.write(self.wakeup_write_fd, val):
pass
def _on_sigwinch(self, signum, frame):
self._wakeup_write(b'r')
def _on_sigterm(self, signum, frame):
self._wakeup_write(b't')
def _on_sigint(self, signum, frame):
self._wakeup_write(b'i')
def quit(self, return_code=None):
self.read_allowed = False
if return_code is not None:
self.return_code = return_code
def wakeup(self):
self._wakeup_write(b'1')
def _modify_output_selector(self, waiting_for_write):
if waiting_for_write:
try:
self.sel.register(self.output_fd, selectors.EVENT_WRITE, self._write_ready)
except KeyError:
pass
else:
try:
self.sel.unregister(self.output_fd)
except KeyError:
pass
def loop(self, handler):
select = self.sel.select
tb = None
waiting_for_write = True
with closing(self.sel), TermManager(self.input_fd, self.output_fd) as term_manager:
signal.signal(signal.SIGWINCH, self._on_sigwinch)
signal.signal(signal.SIGTERM, self._on_sigterm)
signal.signal(signal.SIGINT, self._on_sigint)
handler.write_buf = []
handler._term_manager = term_manager
keep_going = True
try:
handler.initialize(screen_size(), self.quit, self.wakeup)
except Exception:
import traceback
tb = traceback.format_exc()
self.return_code = 1
keep_going = False
while keep_going:
has_data_to_write = bool(handler.write_buf)
if not has_data_to_write and not self.read_allowed:
break
if has_data_to_write != waiting_for_write:
waiting_for_write = has_data_to_write
self._modify_output_selector(waiting_for_write)
events = select()
for key, mask in events:
try:
key.data(handler)
except Exception:
import traceback
tb = traceback.format_exc()
self.return_code = 1
keep_going = False
break
if tb is not None:
self._report_error_loop(tb, term_manager)
def _report_error_loop(self, tb, term_manager):
select = self.sel.select
waiting_for_write = False
handler = UnhandledException(tb)
handler.write_buf = []
handler._term_manager = term_manager
handler.initialize(screen_size(), self.quit, self.wakeup)
while True:
has_data_to_write = bool(handler.write_buf)
if not has_data_to_write and not self.read_allowed:
break
if has_data_to_write != waiting_for_write:
waiting_for_write = has_data_to_write
self._modify_output_selector(waiting_for_write)
events = select()
for key, mask in events:
key.data(handler)

162
kittens/tui/operations.py Normal file
View File

@@ -0,0 +1,162 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
import sys
from contextlib import contextmanager
from kitty.terminfo import string_capabilities
S7C1T = '\033 F'
SAVE_CURSOR = '\0337'
RESTORE_CURSOR = '\0338'
SAVE_PRIVATE_MODE_VALUES = '\033[?s'
RESTORE_PRIVATE_MODE_VALUES = '\033[?r'
MODES = dict(
LNM=(20, ''),
IRM=(4, ''),
DECKM=(1, '?'),
DECSCNM=(5, '?'),
DECOM=(6, '?'),
DECAWM=(7, '?'),
DECARM=(8, '?'),
DECTCEM=(25, '?'),
MOUSE_BUTTON_TRACKING=(1000, '?'),
MOUSE_MOTION_TRACKING=(1002, '?'),
MOUSE_MOVE_TRACKING=(1003, '?'),
FOCUS_TRACKING=(1004, '?'),
MOUSE_UTF8_MODE=(1005, '?'),
MOUSE_SGR_MODE=(1006, '?'),
MOUSE_URXVT_MODE=(1015, '?'),
ALTERNATE_SCREEN=(1049, '?'),
BRACKETED_PASTE=(2004, '?'),
EXTENDED_KEYBOARD=(2017, '?'),
)
def set_mode(which, private=True):
num, private = MODES[which]
return '\033[{}{}h'.format(private, num)
def reset_mode(which):
num, private = MODES[which]
return '\033[{}{}l'.format(private, num)
def clear_screen():
return string_capabilities['clear'].replace(r'\E', '\033')
def set_window_title(value):
return ('\033]2;' + value.replace('\033', '').replace('\x9c', '') + '\033\\')
def set_line_wrapping(yes_or_no):
return (set_mode if yes_or_no else reset_mode)('DECAWM')
def set_cursor_visible(yes_or_no):
return (set_mode if yes_or_no else reset_mode)('DECTCEM')
STANDARD_COLORS = {name: i for i, name in enumerate(
'black red green yellow blue magenta cyan gray'.split())}
UNDERLINE_STYLES = {name: i + 1 for i, name in enumerate(
'straight double curly'.split())}
def color_code(color, intense=False, base=30):
if isinstance(color, str):
e = str((base + 60 if intense else base) + STANDARD_COLORS[color])
elif isinstance(color, int):
e = '{}:5:{}'.format(base + 8, max(0, min(color, 255)))
else:
e = '{}:2:{}:{}:{}'.format(base + 8, *color)
return e
def sgr(*parts):
return '\033[{}m'.format(';'.join(parts))
def colored(text, color, intense=False, reset_to=None, reset_to_intense=False):
e = color_code(color, intense)
return '\033[{}m{}\033[{}m'.format(e, text, 39 if reset_to is None else color_code(reset_to, reset_to_intense))
def faint(text):
return colored(text, 'black', True)
def styled(text, fg=None, bg=None, fg_intense=False, bg_intense=False, italic=None, bold=None, underline=None, underline_color=None, reverse=None):
start, end = [], []
if fg is not None:
start.append(color_code(fg, fg_intense))
end.append('39')
if bg is not None:
start.append(color_code(bg, bg_intense, 40))
end.append('49')
if underline_color is not None:
if isinstance(underline_color, str):
underline_color = STANDARD_COLORS[underline_color]
start.append(color_code(underline_color, base=50))
end.append('59')
if underline is not None:
start.append('4:{}'.format(UNDERLINE_STYLES[underline]))
end.append('4:0')
if italic is not None:
s, e = (start, end) if italic else (end, start)
s.append('3'), e.append('23')
if bold is not None:
s, e = (start, end) if bold else (end, start)
s.append('1'), e.append('22')
if reverse is not None:
s, e = (start, end) if reverse else (end, start)
s.append('7'), e.append('27')
if not start:
return text
return '\033[{}m{}\033[{}m'.format(';'.join(start), text, ';'.join(end))
def init_state(alternate_screen=True):
ans = (
S7C1T + SAVE_CURSOR + SAVE_PRIVATE_MODE_VALUES + reset_mode('LNM') +
reset_mode('IRM') + reset_mode('DECKM') + reset_mode('DECSCNM') +
set_mode('DECARM') + reset_mode('DECOM') + set_mode('DECAWM') +
set_mode('DECTCEM') + reset_mode('MOUSE_BUTTON_TRACKING') +
reset_mode('MOUSE_MOTION_TRACKING') + reset_mode('MOUSE_MOVE_TRACKING')
+ reset_mode('FOCUS_TRACKING') + reset_mode('MOUSE_UTF8_MODE') +
reset_mode('MOUSE_SGR_MODE') + reset_mode('MOUSE_UTF8_MODE') +
set_mode('BRACKETED_PASTE') + set_mode('EXTENDED_KEYBOARD') +
'\033[*x' # reset DECSACE to default region select
)
if alternate_screen:
ans += set_mode('ALTERNATE_SCREEN')
ans += clear_screen()
return ans
def reset_state(normal_screen=True):
ans = ''
if normal_screen:
ans += reset_mode('ALTERNATE_SCREEN')
ans += RESTORE_PRIVATE_MODE_VALUES
ans += RESTORE_CURSOR
return ans
@contextmanager
def cursor(write):
write(SAVE_CURSOR)
yield
write(RESTORE_CURSOR)
@contextmanager
def alternate_screen(f=None):
f = f or sys.stdout
print(set_mode('ALTERNATE_SCREEN'), end='', file=f)
yield
print(reset_mode('ALTERNATE_SCREEN'), end='', file=f)

View File

View File

@@ -0,0 +1,477 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
import os
import string
import subprocess
import sys
from functools import lru_cache
from gettext import gettext as _
from kitty.config import cached_values_for
from kitty.constants import config_dir, editor
from kitty.fast_data_types import wcswidth
from kitty.key_encoding import (
DOWN, ESCAPE, F1, F2, F3, F4, F12, LEFT, RELEASE, RIGHT, SHIFT, TAB, UP,
backspace_key, enter_key
)
from ..tui.handler import Handler
from ..tui.loop import Loop
from ..tui.operations import (
clear_screen, color_code, colored, cursor, faint, set_line_wrapping,
set_window_title, sgr, styled
)
HEX, NAME, EMOTICONS, FAVORITES = 'HEX', 'NAME', 'EMOTICONS', 'FAVORITES'
favorites_path = os.path.join(config_dir, 'unicode-input-favorites.conf')
INDEX_CHAR = '.'
DEFAULT_SET = tuple(map(
ord,
'‘’“”‹›«»‚„' '😀😛😇😈😉😍😎😮👍👎' '—–§¶†‡©®™' '→⇒•·°±−×÷¼½½¾'
'…µ¢£€¿¡¨´¸ˆ˜' 'ÀÁÂÃÄÅÆÇÈÉÊË' 'ÌÍÎÏÐÑÒÓÔÕÖØ' 'ŒŠÙÚÛÜÝŸÞßàá' 'âãäåæçèéêëìí'
'îïðñòóôõöøœš' 'ùúûüýÿþªºαΩ∞'
))
EMOTICONS_SET = tuple(range(0x1f600, 0x1f64f + 1))
def codepoint_ok(code):
return not (code <= 32 or code == 127 or 128 <= code <= 159 or 0xd800 <= code <= 0xdbff or 0xDC00 <= code <= 0xDFFF)
@lru_cache(maxsize=256)
def points_for_word(w):
from .unicode_names import codepoints_for_word
return codepoints_for_word(w)
@lru_cache(maxsize=4096)
def name(cp):
from .unicode_names import name_for_codepoint
if isinstance(cp, str):
cp = ord(cp[0])
return (name_for_codepoint(cp) or '').capitalize()
@lru_cache(maxsize=256)
def codepoints_matching_search(parts):
ans = []
if parts and parts[0]:
codepoints = points_for_word(parts[0])
for word in parts[1:]:
pts = points_for_word(word)
if pts:
intersection = codepoints & pts
if intersection:
codepoints = intersection
continue
codepoints = {c for c in codepoints if word in name(c).lower()}
if codepoints:
ans = list(sorted(codepoints))
return ans
def parse_favorites(raw):
for line in raw.splitlines():
line = line.strip()
if line.startswith('#') or not line:
continue
idx = line.find('#')
if idx > -1:
line = line[:idx]
code_text = line.partition(' ')[0]
try:
code = int(code_text, 16)
except Exception:
pass
else:
if codepoint_ok(code):
yield code
def serialize_favorites(favorites):
ans = '''\
# Favorite characters for unicode input
# Enter the hex code for each favorite character on a new line. Blank lines are
# ignored and anything after a # is considered a comment.
'''.splitlines()
for cp in favorites:
ans.append('{:x} # {} {}'.format(cp, chr(cp), name(cp)))
return '\n'.join(ans)
def load_favorites(refresh=False):
ans = getattr(load_favorites, 'ans', None)
if ans is None or refresh:
try:
with open(favorites_path, 'rb') as f:
raw = f.read().decode('utf-8')
ans = load_favorites.ans = list(parse_favorites(raw)) or list(DEFAULT_SET)
except FileNotFoundError:
ans = load_favorites.ans = list(DEFAULT_SET)
return ans
def encode_hint(num, digits=string.digits + string.ascii_lowercase):
res = ''
d = len(digits)
while not res or num > 0:
num, i = divmod(num, d)
res = digits[i] + res
return res
def decode_hint(x):
return int(x, 36)
class Table:
def __init__(self):
self.layout_dirty = True
self.last_rows = self.last_cols = -1
self.codepoints = []
self.current_idx = 0
self.text = ''
self.num_cols = 0
self.mode = HEX
@property
def current_codepoint(self):
if self.codepoints:
return self.codepoints[self.current_idx]
def set_codepoints(self, codepoints, mode=HEX):
self.codepoints = codepoints
self.mode = mode
self.layout_dirty = True
self.current_idx = 0
def codepoint_at_hint(self, hint):
return self.codepoints[decode_hint(hint)]
def layout(self, rows, cols):
if not self.layout_dirty and self.last_cols == cols and self.last_rows == rows:
return self.text
self.last_cols, self.last_rows = cols, rows
self.layout_dirty = False
if self.mode is NAME:
def as_parts(i, codepoint):
return encode_hint(i).ljust(idx_size), chr(codepoint), name(codepoint)
def cell(i, idx, c, desc):
is_current = i == self.current_idx
if is_current:
yield sgr(color_code('gray', base=40))
yield colored(idx, 'green') + ' '
yield colored(c, 'black' if is_current else 'gray', True) + ' '
w = wcswidth(c)
if w < 2:
yield ' ' * (2 - w)
if len(desc) > space_for_desc:
desc = desc[:space_for_desc - 1] + ''
yield faint(desc)
extra = space_for_desc - len(desc)
if extra > 0:
yield ' ' * extra
if is_current:
yield sgr('49')
else:
def as_parts(i, codepoint):
return encode_hint(i).ljust(idx_size), chr(codepoint), ''
def cell(i, idx, c, desc):
yield colored(idx, 'green') + ' '
yield colored(c, 'gray', True)
w = wcswidth(c)
if w < 2:
yield ' ' * (2 - w)
num = len(self.codepoints)
if num < 1:
self.text = ''
self.num_cols = 0
return self.text
idx_size = len(encode_hint(num - 1))
parts = [as_parts(i, c) for i, c in enumerate(self.codepoints)]
if self.mode is NAME:
sizes = [idx_size + 2 + len(p[2]) + 2 for p in parts]
else:
sizes = [idx_size + 3]
longest = max(sizes) if sizes else 0
col_width = longest + 2
col_width = min(col_width, 40)
space_for_desc = col_width - 2 - idx_size - 4
num_cols = self.num_cols = max(cols // col_width, 1)
buf = []
a = buf.append
rows_left = rows
for i, (idx, c, desc) in enumerate(parts):
if i > 0 and i % num_cols == 0:
rows_left -= 1
if rows_left == 0:
break
buf.append('\r\n')
buf.extend(cell(i, idx, c, desc))
a(' ')
self.text = ''.join(buf)
return self.text
def move_current(self, rows=0, cols=0):
if cols:
self.current_idx = (self.current_idx + len(self.codepoints) + cols) % len(self.codepoints)
self.layout_dirty = True
if rows:
amt = rows * self.num_cols
self.current_idx += amt
self.current_idx = max(0, min(self.current_idx, len(self.codepoints) - 1))
self.layout_dirty = True
def is_index(w):
try:
int(w.lstrip(INDEX_CHAR), 16)
return True
except Exception:
return False
class UnicodeInput(Handler):
def __init__(self, cached_values):
self.cached_values = cached_values
self.recent = list(self.cached_values.get('recent', DEFAULT_SET))
self.current_input = ''
self.current_char = None
self.prompt_template = '{}> '
self.last_updated_code_point_at = None
self.choice_line = ''
self.mode = globals().get(cached_values.get('mode', 'HEX'), 'HEX')
self.table = Table()
self.update_prompt()
def update_codepoints(self):
codepoints = None
if self.mode is HEX:
q = self.mode, None
codepoints = self.recent
elif self.mode is EMOTICONS:
q = self.mode, None
codepoints = list(EMOTICONS_SET)
elif self.mode is FAVORITES:
codepoints = load_favorites()
q = self.mode, tuple(codepoints)
elif self.mode is NAME:
q = self.mode, self.current_input
if q != self.last_updated_code_point_at:
words = self.current_input.split()
words = [w for w in words if w != INDEX_CHAR]
index_words = [i for i, w in enumerate(words) if i > 0 and is_index(w)]
if index_words:
index_word = words[index_words[0]]
words = words[:index_words[0]]
codepoints = codepoints_matching_search(tuple(words))
if index_words:
index_word = int(index_word.lstrip(INDEX_CHAR), 16)
if index_word < len(codepoints):
codepoints = [codepoints[index_word]]
if q != self.last_updated_code_point_at:
self.last_updated_code_point_at = q
self.table.set_codepoints(codepoints, self.mode)
def update_current_char(self):
self.update_codepoints()
self.current_char = None
if self.mode is HEX:
try:
if self.current_input.startswith(INDEX_CHAR) and len(self.current_input) > 1:
self.current_char = chr(self.table.codepoint_at_hint(self.current_input[1:]))
else:
code = int(self.current_input, 16)
self.current_char = chr(code)
except Exception:
pass
elif self.mode is NAME:
cc = self.table.current_codepoint
if cc:
self.current_char = chr(cc)
else:
try:
if self.current_input:
self.current_char = chr(self.table.codepoint_at_hint(self.current_input.lstrip(INDEX_CHAR)))
except Exception:
pass
if self.current_char is not None:
code = ord(self.current_char)
if not codepoint_ok(code):
self.current_char = None
def update_prompt(self):
self.update_current_char()
if self.current_char is None:
c, color = '??', 'red'
self.choice_line = ''
else:
c, color = self.current_char, 'green'
self.choice_line = _('Chosen:') + ' {} U+{} {}'.format(
colored(c, 'green'), hex(ord(c))[2:], faint(styled(name(c) or '', italic=True)))
self.prompt = self.prompt_template.format(colored(c, color))
def init_terminal_state(self):
self.write(set_line_wrapping(False))
self.write(set_window_title(_('Unicode input')))
def initialize(self, *args):
Handler.initialize(self, *args)
self.init_terminal_state()
self.draw_screen()
def draw_title_bar(self):
entries = []
for name, key, mode in [
(_('Code'), 'F1', HEX),
(_('Name'), 'F2', NAME),
(_('Emoji'), 'F3', EMOTICONS),
(_('Favorites'), 'F4', FAVORITES),
]:
entry = ' {} ({}) '.format(name, key)
if mode is self.mode:
entry = styled(entry, reverse=False, bold=True)
entries.append(entry)
text = _('Search by:{}').format(' '.join(entries))
extra = self.screen_size.cols - wcswidth(text)
if extra > 0:
text += ' ' * extra
self.print(styled(text, reverse=True))
def draw_screen(self):
self.write(clear_screen())
self.draw_title_bar()
y = 1
def writeln(text=''):
nonlocal y
self.print(text)
y += 1
if self.mode is NAME:
writeln(_('Enter words from the name of the character'))
elif self.mode is HEX:
writeln(_('Enter the hex code for the character'))
else:
writeln(_('Enter the index for the character you want from the list below'))
self.write(self.prompt)
self.write(self.current_input)
with cursor(self.write):
writeln()
writeln(self.choice_line)
if self.mode is HEX:
writeln(faint(_('Type {} followed by the index for the recent entries below').format(INDEX_CHAR)))
elif self.mode is NAME:
writeln(faint(_('Use Tab or the arrow keys to choose a character from below')))
elif self.mode is FAVORITES:
writeln(faint(_('Press F12 to edit the list of favorites')))
self.table_at = y
self.write(self.table.layout(self.screen_size.rows - self.table_at, self.screen_size.cols))
def refresh(self):
self.update_prompt()
self.draw_screen()
def on_text(self, text, in_bracketed_paste):
self.current_input += text
self.refresh()
def on_key(self, key_event):
if key_event is backspace_key:
self.current_input = self.current_input[:-1]
self.refresh()
elif key_event is enter_key:
self.quit_loop(0)
elif key_event.type is RELEASE and not key_event.mods:
if key_event.key is ESCAPE:
self.quit_loop(1)
elif key_event.key is F1:
self.switch_mode(HEX)
elif key_event.key is F2:
self.switch_mode(NAME)
elif key_event.key is F3:
self.switch_mode(EMOTICONS)
elif key_event.key is F4:
self.switch_mode(FAVORITES)
elif key_event.key is F12 and self.mode is FAVORITES:
self.edit_favorites()
elif self.mode is NAME:
if key_event.key is TAB:
if key_event.mods == SHIFT:
self.table.move_current(cols=-1), self.refresh()
elif not key_event.mods:
self.table.move_current(cols=1), self.refresh()
elif key_event.key is LEFT and not key_event.mods:
self.table.move_current(cols=-1), self.refresh()
elif key_event.key is RIGHT and not key_event.mods:
self.table.move_current(cols=1), self.refresh()
elif key_event.key is UP and not key_event.mods:
self.table.move_current(rows=-1), self.refresh()
elif key_event.key is DOWN and not key_event.mods:
self.table.move_current(rows=1), self.refresh()
def edit_favorites(self):
if not os.path.exists(favorites_path):
with open(favorites_path, 'wb') as f:
f.write(serialize_favorites(load_favorites()).encode('utf-8'))
with self.suspend():
p = subprocess.Popen(editor + [favorites_path])
if p.wait() == 0:
load_favorites(refresh=True)
self.init_terminal_state()
self.refresh()
def switch_mode(self, mode):
if mode is not self.mode:
self.mode = mode
self.cached_values['mode'] = mode
self.current_input = ''
self.current_char = None
self.choice_line = ''
self.refresh()
def on_interrupt(self):
self.quit_loop(1)
def on_eot(self):
self.quit_loop(1)
def on_resize(self, new_size):
Handler.on_resize(self, new_size)
self.refresh()
def run_loop(args):
loop = Loop()
with cached_values_for('unicode-input') as cached_values:
handler = UnicodeInput(cached_values)
loop.loop(handler)
if handler.current_char and loop.return_code == 0:
print('OK:', hex(ord(handler.current_char))[2:])
try:
handler.recent.remove(ord(handler.current_char))
except Exception:
pass
recent = [ord(handler.current_char)] + handler.recent
cached_values['recent'] = recent[:len(DEFAULT_SET)]
return loop.return_code
def main(args=sys.argv):
try:
raise SystemExit(run_loop(args))
except Exception:
import traceback
traceback.print_exc()
input(_('Press Enter to quit.'))

63052
kittens/unicode_input/names.h generated Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,81 @@
/*
* unicode_names.c
* Copyright (C) 2018 Kovid Goyal <kovid at kovidgoyal.net>
*
* Distributed under terms of the GPL3 license.
*/
#include "names.h"
static PyObject*
all_words(PYNOARG) {
PyObject *ans = PyTuple_New(arraysz(idx_to_word));
if (!ans) return NULL;
for (size_t i = 0; i < arraysz(idx_to_word); i++) {
PyObject *w = PyUnicode_FromString(idx_to_word[i]);
if (w == NULL) { Py_DECREF(ans); return NULL; }
PyTuple_SET_ITEM(ans, i, w);
}
return ans;
}
static inline PyObject*
codepoints_for_word(const char *word, size_t len) {
PyObject *ans = PyFrozenSet_New(NULL); if (ans == NULL) return NULL;
const unsigned short *words = words_for_first_letter[(unsigned)*word];
if (words == NULL) return ans;
for (unsigned short i = 1; i <= words[0]; i++) {
unsigned short word_idx = words[i];
const char *w = idx_to_word[word_idx];
if (strncmp(word, w, len) == 0 && strlen(w) == len) {
const char_type* codepoints = codepoints_for_word_idx[word_idx];
for (char_type i = 1; i <= codepoints[0]; i++) {
PyObject *t = PyLong_FromUnsignedLong(codepoints[i]); if (t == NULL) { Py_DECREF(ans); return NULL; }
int ret = PySet_Add(ans, t); Py_DECREF(t); if (ret != 0) { Py_DECREF(ans); return NULL; }
}
break;
}
}
return ans;
}
static PyObject*
cfw(PyObject *self UNUSED, PyObject *args) {
const char *word;
if (!PyArg_ParseTuple(args, "s", &word)) return NULL;
return codepoints_for_word(word, strlen(word));
}
static PyObject*
nfc(PyObject *self UNUSED, PyObject *args) {
unsigned int cp;
if (!PyArg_ParseTuple(args, "I", &cp)) return NULL;
const char *n = name_for_codepoint(cp);
if (n == NULL) Py_RETURN_NONE;
return PyUnicode_FromString(n);
}
static PyMethodDef module_methods[] = {
METHODB(all_words, METH_NOARGS),
{"codepoints_for_word", (PyCFunction)cfw, METH_VARARGS, ""},
{"name_for_codepoint", (PyCFunction)nfc, METH_VARARGS, ""},
{NULL, NULL, 0, NULL} /* Sentinel */
};
static struct PyModuleDef module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "unicode_names", /* name of module */
.m_doc = NULL,
.m_size = -1,
.m_methods = module_methods
};
EXPORTED PyMODINIT_FUNC
PyInit_unicode_names(void) {
PyObject *m;
m = PyModule_Create(&module);
if (m == NULL) return NULL;
return m;
}

View File

247
kittens/url_hints/main.py Normal file
View File

@@ -0,0 +1,247 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
import re
import string
import subprocess
import sys
from collections import namedtuple
from functools import lru_cache, partial
from gettext import gettext as _
from kitty.cli import parse_args
from kitty.key_encoding import ESCAPE, backspace_key, enter_key
from kitty.utils import command_for_open
from ..tui.handler import Handler
from ..tui.loop import Loop
from ..tui.operations import (
clear_screen, faint, set_cursor_visible, set_window_title, styled
)
Mark = namedtuple('Mark', 'index start end text')
URL_PREFIXES = 'http https file ftp'.split()
HINT_ALPHABET = string.digits + string.ascii_lowercase
@lru_cache(maxsize=2048)
def encode_hint(num):
res = ''
d = len(HINT_ALPHABET)
while not res or num > 0:
num, i = divmod(num, d)
res = HINT_ALPHABET[i] + res
return res
def decode_hint(x):
return int(x, 36)
def render(lines, current_input):
ans = []
def mark(m):
hint = encode_hint(m.index)
text = m.text
if current_input and not hint.startswith(current_input):
return faint(text)
hint = hint[len(current_input):] or ' '
text = text[len(hint):]
return styled(
hint,
fg='black',
bg='green',
bold=True
) + styled(
text, fg='gray', fg_intense=True, bold=True
)
for line, marks in lines:
if not marks:
ans.append(faint(line))
continue
buf = []
for i, m in enumerate(marks):
if i == 0 and m.start:
buf.append(faint(line[:m.start]))
buf.append(mark(m))
if m is not marks[-1]:
buf.append(faint(line[m.end:marks[i + 1].start]))
rest = line[marks[-1].end:]
if rest:
buf.append(faint(rest))
ans.append(''.join(buf))
return '\r\n'.join(ans)
class URLHints(Handler):
def __init__(self, lines, index_map):
self.lines, self.index_map = tuple(lines), index_map
self.current_input = ''
self.current_text = None
self.chosen = None
def init_terminal_state(self):
self.write(set_cursor_visible(False))
self.write(set_window_title(_('Choose URL')))
def initialize(self, *args):
Handler.initialize(self, *args)
self.init_terminal_state()
self.draw_screen()
def on_text(self, text, in_bracketed_paste):
changed = False
for c in text:
if c in HINT_ALPHABET:
self.current_input += c
changed = True
if changed:
matches = [
t for idx, t in self.index_map.items()
if encode_hint(idx).startswith(self.current_input)
]
if len(matches) == 1:
self.chosen = matches[0]
self.quit_loop(0)
return
self.current_text = None
self.draw_screen()
def on_key(self, key_event):
if key_event is backspace_key:
self.current_input = self.current_input[:-1]
self.current_text = None
self.draw_screen()
elif key_event is enter_key and self.current_input:
idx = decode_hint(self.current_input)
self.chosen = self.index_map[idx]
self.quit_loop(0)
elif key_event.key is ESCAPE:
self.quit_loop(1)
def on_interrupt(self):
self.quit_loop(1)
def on_eot(self):
self.quit_loop(1)
def on_resize(self, new_size):
Handler.on_resize(self, new_size)
self.draw_screen()
def draw_screen(self):
if self.current_text is None:
self.current_text = render(self.lines, self.current_input)
self.write(clear_screen())
self.write(self.current_text)
def regex_finditer(pat, line):
for m in pat.finditer(line):
s, e = m.span()
if e - s > 2:
yield s, e
def find_urls(pat, line):
for m in pat.finditer(line):
s, e = m.span()
if s > 4 and line[s - 5:s] == 'link:': # asciidoc URLs
url = line[s:e]
idx = url.rfind('[')
if idx > -1:
e -= len(url) - idx
yield s, e
def mark(finditer, line, index_map):
marks = []
for s, e in finditer(line):
idx = len(index_map)
text = line[s:e]
marks.append(Mark(idx, s, e, text))
index_map[idx] = text
return line, marks
def run_loop(args, lines, index_map):
loop = Loop()
handler = URLHints(lines, index_map)
loop.loop(handler)
if handler.chosen and loop.return_code == 0:
cmd = command_for_open(args.program)
ret = subprocess.Popen(cmd + [handler.chosen]).wait()
if ret != 0:
print('URL handler "{}" failed with return code: {}'.format(' '.join(cmd), ret), file=sys.stderr)
input('Press Enter to quit')
loop.return_code = ret
raise SystemExit(loop.return_code)
def run(args, source_file=None):
if source_file is None:
text = sys.stdin.buffer.read().decode('utf-8')
sys.stdin = open('/dev/tty')
else:
with open(source_file, 'r') as f:
text = f.read()
if args.regex is None:
from .url_regex import url_delimiters
url_pat = '(?:{})://[^{}]{{3,}}'.format(
'|'.join(args.url_prefixes.split(',')), url_delimiters
)
finditer = partial(find_urls, re.compile(url_pat))
else:
finditer = partial(regex_finditer, re.compile(args.regex))
lines = []
index_map = {}
for line in text.splitlines():
marked = mark(finditer, line, index_map)
lines.append(marked)
if not index_map:
input(_('No URLs found, press Enter to abort.'))
return
try:
run_loop(args, lines, index_map)
except Exception:
import traceback
traceback.print_exc()
input(_('Press Enter to quit'))
OPTIONS = partial('''\
--program
default=default
What program to use to open matched URLs. Defaults
to the default URL open program for the operating system.
--regex
Instead of searching for URLs search for the specified regular
expression instead.
--url-prefixes
default={0}
Comma separated list of recognized URL prefixes. Defaults to:
{0}
'''.format, ','.join(sorted(URL_PREFIXES)))
def main(args=sys.argv):
msg = 'Highlight URLs inside the specified text'
try:
args, items = parse_args(args[1:], OPTIONS, '[path to file or omit to use stdin]', msg, 'url_hints')
except SystemExit as e:
print(e.args[0], file=sys.stderr)
input('Press enter to quit...')
return 1
run(args, (items or [None])[0])

View File

@@ -0,0 +1 @@
url_delimiters = '\x00-\x20\x7f-\xa0\xad\u0600-\u0605\u061c\u06dd\u070f\u08e2\u1680\u180e\u2000-\u200f\u2028-\u202f\u205f-\u2064\u2066-\u206f\u3000\ud800-\uf8ff\ufeff\ufff9-\ufffb\U000110bd\U0001bca0-\U0001bca3\U0001d173-\U0001d17a\U000e0001\U000e0020-\U000e007f\U000f0000-\U000ffffd\U00100000-\U0010fffd' # noqa

11
kitty/blit_fragment.glsl Normal file
View File

@@ -0,0 +1,11 @@
#version GLSL_VERSION
uniform sampler2D image;
in vec2 texcoord;
out vec4 color;
void main() {
color = texture(image, texcoord);
color = vec4(color.rgb / color.a, color.a);
}

20
kitty/blit_vertex.glsl Normal file
View File

@@ -0,0 +1,20 @@
#version GLSL_VERSION
#define left -1.0f
#define top 1.0f
#define right 1.0f
#define bottom -1.0f
const vec2 pos_map[] = vec2[4](
vec2(right, top),
vec2(right, bottom),
vec2(left, bottom),
vec2(left, top)
);
out vec2 texcoord;
void main() {
vec2 vertex = pos_map[gl_VertexID];
gl_Position = vec4(vertex, 0, 1);
texcoord = (vertex + 1.0) / 2.0;
}

View File

@@ -0,0 +1,8 @@
#version GLSL_VERSION
uniform float background_opacity;
in vec3 color;
out vec4 final_color;
void main() {
final_color = vec4(color, background_opacity);
}

41
kitty/border_vertex.glsl Normal file
View File

@@ -0,0 +1,41 @@
#version GLSL_VERSION
uniform uvec2 viewport;
uniform vec3 default_bg;
uniform vec3 active_border_color;
uniform vec3 inactive_border_color;
in uvec4 rect; // left, top, right, bottom
in uint rect_color;
out vec3 color;
// indices into the rect vector
const int LEFT = 0;
const int TOP = 1;
const int RIGHT = 2;
const int BOTTOM = 3;
const uint FF = uint(0xff);
const uvec2 pos_map[] = uvec2[4](
uvec2(RIGHT, TOP),
uvec2(RIGHT, BOTTOM),
uvec2(LEFT, BOTTOM),
uvec2(LEFT, TOP)
);
vec2 to_opengl(uint x, uint y) {
return vec2(
-1.0 + 2.0 * (float(x) / float(viewport.x)),
1.0 - 2.0 * (float(y) / float(viewport.y))
);
}
float to_color(uint c) {
return float(c & FF) / 255.0;
}
void main() {
uvec2 pos = pos_map[gl_VertexID];
gl_Position = vec4(to_opengl(rect[pos.x], rect[pos.y]), 0, 1);
int rc = int(rect_color);
vec3 window_bg = vec3(to_color(rect_color >> 24), to_color(rect_color >> 16), to_color(rect_color >> 8));
color = float(1 & rc) * default_bg + float((2 & rc) >> 1) * active_border_color + float((4 & rc) >> 2) * inactive_border_color + float((8 & rc) >> 3) * window_bg;
}

View File

@@ -2,98 +2,48 @@
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
from ctypes import addressof
from itertools import chain
from threading import Lock
from functools import partial
from itertools import chain
from .constants import GLfloat, GLint, GLuint, viewport_size
from .fast_data_types import GL_TRIANGLE_FAN, glMultiDrawArrays, glUniform3fv
from .shaders import ShaderProgram
from .utils import pt_to_px
from .fast_data_types import (
BORDERS_PROGRAM, add_borders_rect, compile_program, init_borders_program,
pt_to_px
)
from .utils import load_shaders
def as_color(c):
return c[0] / 255, c[1] / 255, c[2] / 255
def vertical_edge(os_window_id, tab_id, color, width, top, bottom, left):
add_borders_rect(os_window_id, tab_id, left, top, left + width, bottom, color)
def to_opengl(x, y):
return -1 + 2 * x / viewport_size.width, 1 - 2 * y / viewport_size.height
def horizontal_edge(os_window_id, tab_id, color, height, left, right, top):
add_borders_rect(os_window_id, tab_id, left, top, right, top + height, color)
def as_rect(left, top, right, bottom, color=0):
for (x, y) in ((right, top), (right, bottom), (left, bottom), (left, top)):
x, y = to_opengl(x, y)
yield x
yield y
yield color
def edge(func, os_window_id, tab_id, color, sz, a, b):
return partial(func, os_window_id, tab_id, color, sz, a, b)
class BordersProgram(ShaderProgram):
def __init__(self):
ShaderProgram.__init__(
self, '''\
uniform vec3 colors[3];
in vec3 rect;
out vec3 color;
void main() {
gl_Position = vec4(rect[0], rect[1], 0, 1);
color = colors[uint(rect[2])];
}
''', '''\
in vec3 color;
out vec4 final_color;
void main() {
final_color = vec4(color, 1);
}
''')
self.add_vertex_array('rect')
def send_data(self, data):
self.send_vertex_data('rect', data)
def set_colors(self, color_buf):
glUniform3fv(self.uniform_location('colors'), 3, addressof(color_buf))
def border(os_window_id, tab_id, color, sz, left, top, right, bottom):
horz = edge(horizontal_edge, os_window_id, tab_id, color, sz, left, right)
horz(top), horz(bottom - sz) # top, bottom edges
vert = edge(vertical_edge, os_window_id, tab_id, color, sz, top, bottom)
vert(left), vert(right - sz) # left, right edges
def border_maker(rects):
' Create a function that will add all the rectangles for drawing a border to rects '
def r(l, t, b, r, color):
rects.extend(as_rect(l, t, b, r, color))
def vertical_edge(color, width, top, bottom, left):
r(left, top, left + width, bottom, color)
def horizontal_edge(color, height, left, right, top):
r(left, top, right, top + height, color)
def edge(func, color, sz, a, b):
return partial(func, color, sz, a, b)
def border(color, sz, left, top, right, bottom):
horz = edge(horizontal_edge, color, sz, left, right)
horz(top), horz(bottom - sz) # top, bottom edges
vert = edge(vertical_edge, color, sz, top, bottom)
vert(left), vert(right - sz) # left, right edges
return border
def load_borders_program():
compile_program(BORDERS_PROGRAM, *load_shaders('border'))
init_borders_program()
Borders.program_initialized = True
class Borders:
def __init__(self, opts):
self.is_dirty = False
self.lock = Lock()
self.can_render = False
def __init__(self, os_window_id, tab_id, opts):
self.os_window_id = os_window_id
self.tab_id = tab_id
self.border_width = pt_to_px(opts.window_border_width)
self.padding_width = pt_to_px(opts.window_padding_width)
self.color_buf = (GLfloat * 9)(
*as_color(opts.background), *as_color(opts.active_border_color),
*as_color(opts.inactive_border_color))
def __call__(
self,
@@ -103,53 +53,28 @@ class Borders:
extra_blank_rects,
draw_window_borders=True
):
rects = []
add_borders_rect(self.os_window_id, self.tab_id, 0, 0, 0, 0, 1)
for br in chain(current_layout.blank_rects, extra_blank_rects):
rects.extend(as_rect(*br))
add_borders_rect(self.os_window_id, self.tab_id, *br, 1)
bw, pw = self.border_width, self.padding_width
fw = bw + pw
border = border_maker(rects)
if fw > 0:
for w in windows:
g = w.geometry
if bw > 0 and draw_window_borders:
# Draw the border rectangles
color = 1 if w is active_window else 2
color = 2 if w is active_window else 4
border(
self.os_window_id, self.tab_id,
color, bw, g.left - fw, g.top - fw, g.right + fw,
g.bottom + fw)
g.bottom + fw
)
if pw > 0:
# Draw the background rectangles over the padding region
color = 0
color = w.screen.color_profile.default_bg
border(
color, pw, g.left - pw, g.top - pw, g.right + pw,
g.bottom + pw)
with self.lock:
self.num_of_rects = len(rects) // 12
self.rects = (GLfloat * len(rects))()
self.starts = (GLint * self.num_of_rects)()
self.counts = (GLuint * self.num_of_rects)()
for i, x in enumerate(rects):
self.rects[i] = x
if i % 12 == 0:
idx = i // 12
self.starts[idx] = i // 3
self.counts[idx] = 4
self.is_dirty = True
self.can_render = True
def render(self, program):
with self.lock:
if not self.can_render:
return
with program:
if self.is_dirty:
program.send_data(self.rects)
program.set_colors(self.color_buf)
self.is_dirty = False
glMultiDrawArrays(
GL_TRIANGLE_FAN,
addressof(self.starts),
addressof(self.counts), self.num_of_rects)
self.os_window_id, self.tab_id,
(color << 8) | 8, pw, g.left - pw, g.top - pw, g.right + pw,
g.bottom + pw
)

File diff suppressed because it is too large Load Diff

110
kitty/cell_fragment.glsl Normal file
View File

@@ -0,0 +1,110 @@
#version GLSL_VERSION
#define WHICH_PROGRAM
#define NOT_TRANSPARENT
#if defined(SIMPLE) || defined(BACKGROUND) || defined(SPECIAL)
#define NEEDS_BACKROUND
#endif
#if defined(SIMPLE) || defined(FOREGROUND)
#define NEEDS_FOREGROUND
#endif
#ifdef NEEDS_BACKROUND
in vec3 background;
#if defined(TRANSPARENT) || defined(SPECIAL)
in float bg_alpha;
#endif
#endif
#ifdef NEEDS_FOREGROUND
uniform sampler2DArray sprites;
uniform float inactive_text_alpha;
in vec3 sprite_pos;
in vec3 underline_pos;
in vec3 strike_pos;
in vec3 foreground;
in vec3 decoration_fg;
in float colored_sprite;
#endif
out vec4 final_color;
// Util functions {{{
vec4 alpha_blend(vec3 over, float over_alpha, vec3 under, float under_alpha) {
// Alpha blend two colors returning the resulting color pre-multiplied by its alpha
// and its alpha.
// See https://en.wikipedia.org/wiki/Alpha_compositing
float alpha = mix(under_alpha, 1.0f, over_alpha);
vec3 combined_color = mix(under * under_alpha, over, over_alpha);
return vec4(combined_color, alpha);
}
vec3 premul_blend(vec3 over, float over_alpha, vec3 under) {
return over + (1.0f - over_alpha) * under;
}
vec4 alpha_blend_premul(vec3 over, float over_alpha, vec3 under, float under_alpha) {
// Same as alpha_blend() except that it assumes over and under are both premultiplied.
float alpha = mix(under_alpha, 1.0f, over_alpha);
return vec4(premul_blend(over, over_alpha, under), alpha);
}
// }}}
#ifdef NEEDS_FOREGROUND
vec4 calculate_foreground() {
vec4 text_fg = texture(sprites, sprite_pos);
vec3 fg = mix(foreground, text_fg.rgb, colored_sprite);
float text_alpha = text_fg.a;
float underline_alpha = texture(sprites, underline_pos).a;
float strike_alpha = texture(sprites, strike_pos).a;
// Since strike and text are the same color, we simply add the alpha values
float combined_alpha = min(text_alpha + strike_alpha, 1.0f);
// Underline color might be different, so alpha blend
return alpha_blend(decoration_fg, underline_alpha * inactive_text_alpha, fg, combined_alpha * inactive_text_alpha);
}
#endif
void main() {
#ifdef BACKGROUND
#ifdef TRANSPARENT
final_color = vec4(background.rgb * bg_alpha, bg_alpha);
#else
final_color = vec4(background.rgb, 1.0f);
#endif
#endif
#ifdef SPECIAL
#ifdef TRANSPARENT
final_color = vec4(background.rgb * bg_alpha, bg_alpha);
#else
final_color = vec4(background.rgb, bg_alpha);
#endif
#endif
#if defined(FOREGROUND) || defined(SIMPLE)
// FOREGROUND or SIMPLE
vec4 fg = calculate_foreground(); // pre-multiplied foreground
#ifdef FOREGROUND
// FOREGROUND
#ifdef TRANSPARENT
final_color = fg;
#else
final_color = vec4(fg.rgb / fg.a, fg.a);
#endif
#else
// SIMPLE
#ifdef TRANSPARENT
final_color = alpha_blend_premul(fg.rgb, fg.a, background * bg_alpha, bg_alpha);
final_color = vec4(final_color.rgb / final_color.a, final_color.a);
#else
// since background alpha is 1.0, it is effectively pre-multiplied
final_color = vec4(premul_blend(fg.rgb, fg.a, background), 1.0f);
final_color = vec4(final_color.rgb / final_color.a, final_color.a);
#endif
#endif
#endif
}

196
kitty/cell_vertex.glsl Normal file
View File

@@ -0,0 +1,196 @@
#version GLSL_VERSION
#define WHICH_PROGRAM
#define NOT_TRANSPARENT
// Inputs {{{
layout(std140) uniform CellRenderData {
float xstart, ystart, dx, dy, sprite_dx, sprite_dy, background_opacity;
uint default_fg, default_bg, highlight_fg, highlight_bg, cursor_color, url_color, url_style, inverted;
uint xnum, ynum, cursor_x, cursor_y, cursor_w;
uint color_table[256];
};
// Have to use fixed locations here as all variants of the cell program share the same VAO
layout(location=0) in uvec3 colors;
layout(location=1) in uvec4 sprite_coords;
layout(location=2) in uint is_selected;
const int fg_index_map[] = int[3](0, 1, 0);
const uvec2 cell_pos_map[] = uvec2[4](
uvec2(1, 0), // right, top
uvec2(1, 1), // right, bottom
uvec2(0, 1), // left, bottom
uvec2(0, 0) // left, top
);
// }}}
#if defined(SIMPLE) || defined(BACKGROUND) || defined(SPECIAL)
#define NEEDS_BACKROUND
#endif
#if defined(SIMPLE) || defined(FOREGROUND)
#define NEEDS_FOREGROUND
#endif
#ifdef NEEDS_BACKROUND
out vec3 background;
#if defined(TRANSPARENT) || defined(SPECIAL)
out float bg_alpha;
#endif
#endif
#ifdef NEEDS_FOREGROUND
out vec3 sprite_pos;
out vec3 underline_pos;
out vec3 strike_pos;
out vec3 foreground;
out vec3 decoration_fg;
out float colored_sprite;
#endif
// Utility functions {{{
const uint BYTE_MASK = uint(0xFF);
const uint Z_MASK = uint(0xFFF);
const uint COLOR_MASK = uint(0x4000);
const uint ZERO = uint(0);
const uint ONE = uint(1);
const uint TWO = uint(2);
const uint THREE = uint(3);
const uint FOUR = uint(4);
const uint DECORATION_MASK = uint(3);
const uint STRIKE_MASK = uint(1);
const uint REVERSE_MASK = uint(1);
vec3 color_to_vec(uint c) {
uint r, g, b;
r = (c >> 16) & BYTE_MASK;
g = (c >> 8) & BYTE_MASK;
b = c & BYTE_MASK;
return vec3(float(r) / 255.0, float(g) / 255.0, float(b) / 255.0);
}
uint resolve_color(uint c, uint defval) {
// Convert a cell color to an actual color based on the color table
int t = int(c & BYTE_MASK);
uint r;
switch(t) {
case 1:
r = color_table[(c >> 8) & BYTE_MASK];
break;
case 2:
r = c >> 8;
break;
default:
r = defval;
}
return r;
}
vec3 to_color(uint c, uint defval) {
return color_to_vec(resolve_color(c, defval));
}
vec3 to_sprite_pos(uvec2 pos, uint x, uint y, uint z) {
vec2 s_xpos = vec2(x, float(x) + 1.0) * sprite_dx;
vec2 s_ypos = vec2(y, float(y) + 1.0) * sprite_dy;
return vec3(s_xpos[pos.x], s_ypos[pos.y], z);
}
vec3 choose_color(float q, vec3 a, vec3 b) {
return mix(b, a, q);
}
float is_cursor(uint x, uint y) {
if (y == cursor_y && (x == cursor_x || x == cursor_w)) return 1.0;
return 0.0;
}
// }}}
void main() {
// set cell vertex position {{{
uint instance_id = uint(gl_InstanceID);
/* The current cell being rendered */
uint r = instance_id / xnum;
uint c = instance_id - r * xnum;
/* The position of this vertex, at a corner of the cell */
float left = xstart + c * dx;
float top = ystart - r * dy;
vec2 xpos = vec2(left, left + dx);
vec2 ypos = vec2(top, top - dy);
uvec2 pos = cell_pos_map[gl_VertexID];
gl_Position = vec4(xpos[pos.x], ypos[pos.y], 0, 1);
// }}}
// set cell color indices {{{
uvec2 default_colors = uvec2(default_fg, default_bg);
uint text_attrs = sprite_coords[3];
uint is_inverted = ((text_attrs >> 6) & REVERSE_MASK) + inverted;
int fg_index = fg_index_map[is_inverted];
int bg_index = 1 - fg_index;
float cursor = is_cursor(c, r);
vec3 bg = to_color(colors[bg_index], default_colors[bg_index]);
// }}}
// Foreground {{{
#ifdef NEEDS_FOREGROUND
// The character sprite being rendered
sprite_pos = to_sprite_pos(pos, sprite_coords.x, sprite_coords.y, sprite_coords.z & Z_MASK);
colored_sprite = float((sprite_coords.z & COLOR_MASK) >> 14);
// Foreground
uint resolved_fg = resolve_color(colors[fg_index], default_colors[fg_index]);
foreground = color_to_vec(resolved_fg);
// Selection
foreground = choose_color(float(is_selected & ONE), color_to_vec(highlight_fg), foreground);
// Underline and strike through (rendered via sprites)
float in_url = float((is_selected & TWO) >> 1);
decoration_fg = choose_color(in_url, color_to_vec(url_color), to_color(colors[2], resolved_fg));
underline_pos = choose_color(in_url, to_sprite_pos(pos, url_style, ZERO, ZERO), to_sprite_pos(pos, (text_attrs >> 2) & DECORATION_MASK, ZERO, ZERO));
strike_pos = to_sprite_pos(pos, ((text_attrs >> 7) & STRIKE_MASK) * FOUR, ZERO, ZERO);
// Cursor
foreground = choose_color(cursor, bg, foreground);
decoration_fg = choose_color(cursor, bg, decoration_fg);
#endif
// }}}
// Background {{{
#ifdef NEEDS_BACKROUND
#if defined(BACKGROUND)
background = bg;
#endif
#if defined(TRANSPARENT) && !defined(SPECIAL)
// If the background color is default, set its opacity to background_opacity, otherwise it should be opaque
bg_alpha = step(0.5, float(colors[bg_index] & BYTE_MASK));
// Cursor must not be affected by background_opacity
bg_alpha = mix(bg_alpha, 1.0, cursor);
bg_alpha = bg_alpha + (1.0f - bg_alpha) * background_opacity;
#endif
#if defined(SPECIAL) || defined(SIMPLE)
// Selection and cursor
bg = choose_color(float(is_selected & ONE), color_to_vec(highlight_bg), bg);
background = choose_color(cursor, color_to_vec(cursor_color), bg);
#ifdef SPECIAL
// bg_alpha should be 1 if cursor/selection otherwise 0
bg_alpha = mix(0.0, 1.0, step(0.5, float(is_selected & ONE) + cursor));
#endif
#endif
#endif
// }}}
}

View File

@@ -1,520 +0,0 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
import re
import sys
from enum import Enum
from collections import namedtuple
from ctypes import addressof, memmove, sizeof
from threading import Lock
from .config import build_ansi_color_table, defaults
from .constants import (
GLuint, ScreenGeometry, cell_size, get_boss, viewport_size
)
from .fast_data_types import (
CURSOR_BEAM, CURSOR_BLOCK, CURSOR_UNDERLINE, DATA_CELL_SIZE, GL_BLEND,
GL_LINE_LOOP, GL_TRIANGLE_FAN, ColorProfile, glDisable, glDrawArrays,
glDrawArraysInstanced, glEnable, glUniform1i, glUniform2f, glUniform2ui,
glUniform4f
)
from .rgb import to_color
from .utils import (
color_as_int, color_from_int, get_logical_dpi, open_url, safe_print,
set_primary_selection
)
Cursor = namedtuple('Cursor', 'x y shape blink')
class DynamicColor(Enum):
default_fg, default_bg, cursor_color, highlight_fg, highlight_bg = range(1, 6)
if DATA_CELL_SIZE % 3:
raise ValueError('Incorrect data cell size, must be a multiple of 3')
# cell shader {{{
cell_shader = (
'''\
uniform uvec2 dimensions; // xnum, ynum
uniform vec4 steps; // xstart, ystart, dx, dy
uniform vec2 sprite_layout; // dx, dy
uniform usamplerBuffer sprite_map; // gl_InstanceID -> x, y, z
uniform uvec2 color_indices; // which color to use as fg and which as bg
out vec3 sprite_pos;
out vec3 underline_pos;
out vec3 strike_pos;
out vec3 foreground;
out vec3 background;
out vec3 decoration_fg;
const uvec2 pos_map[] = uvec2[4](
uvec2(1, 0), // right, top
uvec2(1, 1), // right, bottom
uvec2(0, 1), // left, bottom
uvec2(0, 0) // left, top
);
const uint BYTE_MASK = uint(255);
const uint ZERO = uint(0);
const uint SMASK = uint(3);
vec3 to_color(uint c) {
uint r, g, b;
r = (c >> 16) & BYTE_MASK;
g = (c >> 8) & BYTE_MASK;
b = c & BYTE_MASK;
return vec3(float(r) / 255.0, float(g) / 255.0, float(b) / 255.0);
}
vec3 to_sprite_pos(uvec2 pos, uint x, uint y, uint z) {
vec2 s_xpos = vec2(x, float(x) + 1.0) * sprite_layout[0];
vec2 s_ypos = vec2(y, float(y) + 1.0) * sprite_layout[1];
return vec3(s_xpos[pos[0]], s_ypos[pos[1]], z);
}
void main() {
uint instance_id = uint(gl_InstanceID);
uint r = instance_id / dimensions[0];
uint c = instance_id - r * dimensions[0];
float left = steps[0] + c * steps[2];
float top = steps[1] - r * steps[3];
vec2 xpos = vec2(left, left + steps[2]);
vec2 ypos = vec2(top, top - steps[3]);
uvec2 pos = pos_map[gl_VertexID];
gl_Position = vec4(xpos[pos[0]], ypos[pos[1]], 0, 1);
int sprite_id = gl_InstanceID * STRIDE;
uvec4 spos = texelFetch(sprite_map, sprite_id);
uvec4 colors = texelFetch(sprite_map, sprite_id + 1);
sprite_pos = to_sprite_pos(pos, spos[0], spos[1], spos[2]);
foreground = to_color(colors[color_indices[0]]);
background = to_color(colors[color_indices[1]]);
uint decoration = colors[2];
decoration_fg = to_color(decoration);
underline_pos = to_sprite_pos(pos, (decoration >> 24) & SMASK, ZERO, ZERO);
strike_pos = to_sprite_pos(pos, (decoration >> 26) & SMASK, ZERO, ZERO);
}
'''.replace('STRIDE', str(DATA_CELL_SIZE // 3)),
'''\
uniform sampler2DArray sprites;
in vec3 sprite_pos;
in vec3 underline_pos;
in vec3 strike_pos;
in vec3 foreground;
in vec3 background;
in vec3 decoration_fg;
out vec4 final_color;
vec3 blend(float alpha, vec3 over, vec3 under) {
return over + (1 - alpha) * under;
}
void main() {
float text_alpha = texture(sprites, sprite_pos).r;
float underline_alpha = texture(sprites, underline_pos).r;
float strike_alpha = texture(sprites, strike_pos).r;
vec3 underline = underline_alpha * decoration_fg;
vec3 strike = strike_alpha * foreground;
vec3 fg = text_alpha * foreground;
vec3 decoration = blend(underline_alpha, underline, strike);
vec3 combined_fg = blend(text_alpha, fg, decoration);
float combined_alpha = max(max(underline_alpha, strike_alpha), text_alpha);
final_color = vec4(blend(combined_alpha, combined_fg, background), 1);
}
''')
# }}}
# cursor shader {{{
cursor_shader = (
'''\
uniform vec2 xpos;
uniform vec2 ypos;
const uvec2 pos_map[] = uvec2[4](
uvec2(1, 0), // right, top
uvec2(1, 1), // right, bottom
uvec2(0, 1), // left, bottom
uvec2(0, 0) // left, top
);
void main() {
uvec2 pos = pos_map[gl_VertexID];
gl_Position = vec4(xpos[pos[0]], ypos[pos[1]], 0, 1);
}
''',
'''\
uniform vec4 color;
out vec4 final_color;
void main() {
final_color = color;
}
''')
# }}}
class Selection: # {{{
__slots__ = tuple('in_progress start_x start_y start_scrolled_by end_x end_y end_scrolled_by'.split())
def __init__(self):
self.clear()
def clear(self):
self.in_progress = False
self.start_x = self.start_y = self.end_x = self.end_y = 0
self.start_scrolled_by = self.end_scrolled_by = 0
def limits(self, scrolled_by, lines, columns):
def coord(x, y, ydelta):
y = y - ydelta + scrolled_by
if y < 0:
x, y = 0, 0
elif y >= lines:
x, y = columns - 1, lines - 1
return x, y
a = coord(self.start_x, self.start_y, self.start_scrolled_by)
b = coord(self.end_x, self.end_y, self.end_scrolled_by)
return (a, b) if a[1] < b[1] or (a[1] == b[1] and a[0] <= b[0]) else (b, a)
def text(self, linebuf, historybuf):
sy = self.start_y - self.start_scrolled_by
ey = self.end_y - self.end_scrolled_by
if sy == ey and self.start_x == self.end_x:
return ''
a, b = (sy, self.start_x), (ey, self.end_x)
if a > b:
a, b = b, a
def line(y):
if y < 0:
return historybuf.line(-1 - y)
return linebuf.line(y)
lines = []
for y in range(a[0], b[0] + 1):
startx, endx = 0, linebuf.xnum - 1
if y == a[0]:
startx = max(0, min(a[1], endx))
if y == b[0]:
endx = max(0, min(b[1], endx))
l = line(y)
is_continued = l.is_continued()
if endx - startx >= linebuf.xnum - 1:
l = str(l).rstrip(' ')
else:
l = ''.join(l[x] for x in range(startx, endx + 1))
if not is_continued and startx == 0 and len(lines) > 0:
l = '\n' + l
lines.append(l)
return ''.join(lines)
# }}}
def calculate_gl_geometry(window_geometry):
dx, dy = 2 * cell_size.width / viewport_size.width, 2 * cell_size.height / viewport_size.height
xmargin = window_geometry.left / viewport_size.width
ymargin = window_geometry.top / viewport_size.height
xstart = -1 + 2 * xmargin
ystart = 1 - 2 * ymargin
return ScreenGeometry(xstart, ystart, window_geometry.xnum, window_geometry.ynum, dx, dy)
def render_cells(buffer_id, sg, cell_program, sprites, invert_colors=False):
sprites.bind_sprite_map(buffer_id)
ul = cell_program.uniform_location
glUniform2ui(ul('dimensions'), sg.xnum, sg.ynum)
glUniform2ui(ul('color_indices'), 1 if invert_colors else 0, 0 if invert_colors else 1)
glUniform4f(ul('steps'), sg.xstart, sg.ystart, sg.dx, sg.dy)
glUniform1i(ul('sprites'), sprites.sampler_num)
glUniform1i(ul('sprite_map'), sprites.buffer_sampler_num)
glUniform2f(ul('sprite_layout'), *(sprites.layout))
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, sg.xnum * sg.ynum)
class CharGrid:
url_pat = re.compile('(?:http|https|file|ftp)://\S+', re.IGNORECASE)
def __init__(self, screen, opts):
self.buffer_lock = Lock()
self.buffer_id = None
self.current_selection = Selection()
self.last_rendered_selection = self.current_selection.limits(0, screen.lines, screen.columns)
self.render_buf_is_dirty = True
self.render_data = None
self.scrolled_by = 0
self.color_profile = ColorProfile()
self.color_profile.update_ansi_color_table(build_ansi_color_table(opts))
self.screen = screen
self.opts = opts
self.default_bg = color_as_int(opts.background)
self.default_fg = color_as_int(opts.foreground)
self.dpix, self.dpiy = get_logical_dpi()
self.opts = opts
self.default_cursor = self.current_cursor = Cursor(0, 0, opts.cursor_shape, opts.cursor_blink_interval > 0)
self.opts = opts
self.highlight_fg, self.highlight_bg = map(color_as_int, (opts.selection_foreground, opts.selection_background))
self.sprite_map_type = self.main_sprite_map = self.scroll_sprite_map = self.render_buf = None
def escape(chars):
return ''.join(frozenset(chars)).replace('\\', r'\\').replace(']', r'\]').replace('-', r'\-')
try:
self.word_pat = re.compile(r'[\w{}]'.format(escape(self.opts.select_by_word_characters)), re.UNICODE)
except Exception:
safe_print('Invalid characters in select_by_word_characters, ignoring', file=sys.stderr)
self.word_pat = re.compile(r'[\w{}]'.format(escape(defaults.select_by_word_characters)), re.UNICODE)
def update_position(self, window_geometry):
self.screen_geometry = calculate_gl_geometry(window_geometry)
def resize(self, window_geometry):
self.update_position(window_geometry)
self.sprite_map_type = (GLuint * (self.screen_geometry.ynum * self.screen_geometry.xnum * DATA_CELL_SIZE))
self.main_sprite_map = self.sprite_map_type()
self.scroll_sprite_map = self.sprite_map_type()
with self.buffer_lock:
self.render_buf = self.sprite_map_type()
self.selection_buf = self.sprite_map_type()
self.render_buf_is_dirty = True
self.current_selection.clear()
def change_colors(self, changes):
dirtied = False
def item(raw):
if raw is None:
return 0
val = to_color(raw)
return None if val is None else (color_as_int(val) << 8) | 1
for which, val in changes.items():
val = item(val)
if val is None:
continue
dirtied = True
setattr(self.screen, which.name, val)
if dirtied:
self.screen.mark_as_dirty()
def scroll(self, amt, upwards=True):
if not isinstance(amt, int):
amt = {'line': 1, 'page': self.screen.lines - 1, 'full': self.screen.historybuf.count}[amt]
if not upwards:
amt *= -1
y = max(0, min(self.scrolled_by + amt, self.screen.historybuf.count))
if y != self.scrolled_by:
self.scrolled_by = y
self.update_cell_data()
def update_cell_data(self, force_full_refresh=False):
sprites = get_boss().sprites
is_dirty = self.screen.is_dirty()
with sprites.lock:
fg = self.screen.default_fg
fg = fg >> 8 if fg & 1 else self.default_fg
bg = self.screen.default_bg
bg = bg >> 8 if bg & 1 else self.default_bg
cursor_changed, history_line_added_count = self.screen.update_cell_data(
sprites.backend, self.color_profile, addressof(self.main_sprite_map), fg, bg, force_full_refresh)
if self.scrolled_by:
self.scrolled_by = min(self.scrolled_by + history_line_added_count, self.screen.historybuf.count)
self.screen.set_scroll_cell_data(
sprites.backend, self.color_profile, addressof(self.main_sprite_map), fg, bg,
self.scrolled_by, addressof(self.scroll_sprite_map))
data = self.scroll_sprite_map if self.scrolled_by else self.main_sprite_map
with self.buffer_lock:
if is_dirty:
self.current_selection.clear()
memmove(self.render_buf, data, sizeof(type(data)))
self.render_data = self.screen_geometry
self.render_buf_is_dirty = True
if cursor_changed:
c = self.screen.cursor
self.current_cursor = Cursor(c.x, c.y, c.shape, c.blink)
def cell_for_pos(self, x, y):
x, y = int(x // cell_size.width), int(y // cell_size.height)
if 0 <= x < self.screen.columns and 0 <= y < self.screen.lines:
return x, y
return None, None
def update_drag(self, is_press, mx, my):
x, y = self.cell_for_pos(mx, my)
if x is None:
x = 0 if mx <= cell_size.width else self.screen.columns - 1
y = 0 if my <= cell_size.height else self.screen.lines - 1
ps = None
with self.buffer_lock:
if is_press:
self.current_selection.start_x = self.current_selection.end_x = x
self.current_selection.start_y = self.current_selection.end_y = y
self.current_selection.start_scrolled_by = self.current_selection.end_scrolled_by = self.scrolled_by
self.current_selection.in_progress = True
elif self.current_selection.in_progress:
self.current_selection.end_x = x
self.current_selection.end_y = y
self.current_selection.end_scrolled_by = self.scrolled_by
if is_press is False:
self.current_selection.in_progress = False
ps = self.text_for_selection()
if ps and ps.strip():
set_primary_selection(ps)
def has_url_at(self, x, y):
x, y = self.cell_for_pos(x, y)
if x is not None:
l = self.screen_line(y)
if l is not None:
text = l.as_base_text()
for m in self.url_pat.finditer(text):
if m.start() <= x < m.end():
return True
return False
def click_url(self, x, y):
x, y = self.cell_for_pos(x, y)
if x is not None:
l = self.screen_line(y)
if l is not None:
text = l.as_base_text()
for m in self.url_pat.finditer(text):
if m.start() <= x < m.end():
url = ''.join(l[i] for i in range(*m.span())).rstrip('.')
# Remove trailing "] and similar
url = re.sub(r'''["'][)}\]]$''', '', url)
# Remove closing trailing character if it is matched by it's
# corresponding opening character before the url
if m.start() > 0:
before = l[m.start() - 1]
closing = {'(': ')', '[': ']', '{': '}', '<': '>', '"': '"', "'": "'", '`': '`', '|': '|', ':': ':'}.get(before)
if closing is not None and url.endswith(closing):
url = url[:-1]
if url:
open_url(url, self.opts.open_url_with)
def screen_line(self, y):
' Return the Line object corresponding to the yth line on the rendered screen '
if y >= 0 and y < self.screen.lines:
if self.scrolled_by:
if y < self.scrolled_by:
return self.screen.historybuf.line(self.scrolled_by - 1 - y)
return self.screen.line(y - self.scrolled_by)
else:
return self.screen.line(y)
def multi_click(self, count, x, y):
x, y = self.cell_for_pos(x, y)
if x is not None:
line = self.screen_line(y)
if line is not None and count in (2, 3):
s = self.current_selection
s.start_scrolled_by = s.end_scrolled_by = self.scrolled_by
s.start_y = s.end_y = y
s.in_progress = False
if count == 3:
for i in range(self.screen.columns):
if line[i] != ' ':
s.start_x = i
break
else:
s.start_x = 0
for i in range(self.screen.columns):
c = self.screen.columns - 1 - i
if line[c] != ' ':
s.end_x = c
break
else:
s.end_x = self.screen.columns - 1
elif count == 2:
i = x
while i >= 0 and self.word_pat.match(line[i]) is not None:
i -= 1
s.start_x = i if i == x else i + 1
i = x
while i < self.screen.columns and self.word_pat.match(line[i]) is not None:
i += 1
s.end_x = i if i == x else i - 1
ps = self.text_for_selection()
if ps:
set_primary_selection(ps)
def get_scrollback_as_ansi(self):
ans = []
self.screen.historybuf.as_ansi(ans.append)
self.screen.linebuf.as_ansi(ans.append)
return ''.join(ans).encode('utf-8')
def text_for_selection(self, sel=None):
s = sel or self.current_selection
return s.text(self.screen.linebuf, self.screen.historybuf)
def prepare_for_render(self, sprites):
with self.buffer_lock:
sg = self.render_data
if sg is None:
return
if self.buffer_id is None:
self.buffer_id = sprites.add_sprite_map()
buf = self.render_buf
start, end = sel = self.current_selection.limits(self.scrolled_by, self.screen.lines, self.screen.columns)
if start != end:
buf = self.selection_buf
if self.render_buf_is_dirty or sel != self.last_rendered_selection:
memmove(buf, self.render_buf, sizeof(type(buf)))
fg = self.screen.highlight_fg
fg = fg >> 8 if fg & 1 else self.highlight_fg
bg = self.screen.highlight_bg
bg = bg >> 8 if bg & 1 else self.highlight_bg
self.screen.apply_selection(addressof(buf), start[0], start[1], end[0], end[1], fg, bg)
if self.render_buf_is_dirty or self.last_rendered_selection != sel:
sprites.set_sprite_map(self.buffer_id, buf)
self.render_buf_is_dirty = False
self.last_rendered_selection = sel
return sg
def render_cells(self, sg, cell_program, sprites, invert_colors=False):
render_cells(self.buffer_id, sg, cell_program, sprites, invert_colors=invert_colors)
def render_cursor(self, sg, cursor_program, is_focused):
cursor = self.current_cursor
if not self.screen.cursor_visible or self.scrolled_by:
return
def width(w=2, vert=True):
dpi = self.dpix if vert else self.dpiy
w *= dpi / 72.0 # as pixels
factor = 2 / (viewport_size.width if vert else viewport_size.height)
return w * factor
ul = cursor_program.uniform_location
left = sg.xstart + cursor.x * sg.dx
top = sg.ystart - cursor.y * sg.dy
cc = self.screen.cursor_color
col = color_from_int(cc >> 8) if cc & 1 else self.opts.cursor
shape = cursor.shape or self.default_cursor.shape
alpha = self.opts.cursor_opacity
if alpha < 1.0 and shape == CURSOR_BLOCK:
glEnable(GL_BLEND)
mult = self.screen.current_char_width()
right = left + (width(1.5) if shape == CURSOR_BEAM else sg.dx * mult)
bottom = top - sg.dy
if shape == CURSOR_UNDERLINE:
top = bottom + width(vert=False)
glUniform4f(ul('color'), col[0] / 255.0, col[1] / 255.0, col[2] / 255.0, alpha)
glUniform2f(ul('xpos'), left, right)
glUniform2f(ul('ypos'), top, bottom)
glDrawArrays(GL_TRIANGLE_FAN if is_focused else GL_LINE_LOOP, 0, 4)
glDisable(GL_BLEND)

Some files were not shown because too many files have changed in this diff Show More