Compare commits
239 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d218900b57 | ||
|
|
cab949a939 | ||
|
|
e350822f5e | ||
|
|
3d6fe93297 | ||
|
|
3a5baf2722 | ||
|
|
cdb472cb56 | ||
|
|
e634350e77 | ||
|
|
464a6c1441 | ||
|
|
d3750b2244 | ||
|
|
b8d2b76ee4 | ||
|
|
14fb7c3201 | ||
|
|
922bc62e0e | ||
|
|
00cae4ccd1 | ||
|
|
61df266df7 | ||
|
|
17751666f2 | ||
|
|
961b2c9b65 | ||
|
|
eaf6f06047 | ||
|
|
d0ac218c05 | ||
|
|
1a01bc15d8 | ||
|
|
cdbe2f13ca | ||
|
|
4f5264277e | ||
|
|
bed3adcc95 | ||
|
|
0c5d59bcf6 | ||
|
|
ff20acd8b8 | ||
|
|
d1cffcde68 | ||
|
|
546dd9b225 | ||
|
|
2a666620c8 | ||
|
|
db50985040 | ||
|
|
8c6d593c41 | ||
|
|
40086c8d1c | ||
|
|
38f73b9f5e | ||
|
|
49429b5f49 | ||
|
|
d9f90ef077 | ||
|
|
6a126fa18e | ||
|
|
14d703f5cc | ||
|
|
9850025f3a | ||
|
|
8daab0ba41 | ||
|
|
88f25ccc76 | ||
|
|
50e7351c73 | ||
|
|
51453a54e4 | ||
|
|
c02ba03f39 | ||
|
|
78dec3d698 | ||
|
|
1590c59131 | ||
|
|
b26f79998a | ||
|
|
489f3e6c9d | ||
|
|
5fef4726a7 | ||
|
|
51fdb8200a | ||
|
|
fb0d98ead1 | ||
|
|
4096caba64 | ||
|
|
38f77144fa | ||
|
|
b8041ce17f | ||
|
|
00575733c8 | ||
|
|
621c92780c | ||
|
|
37f03af4b7 | ||
|
|
bdc4558a43 | ||
|
|
46d483e8b2 | ||
|
|
5143b62a07 | ||
|
|
87ed774cb4 | ||
|
|
4e427d05b7 | ||
|
|
195d987331 | ||
|
|
9b58317fb1 | ||
|
|
1cb15dedac | ||
|
|
5521d6b623 | ||
|
|
f5cf6c1dcb | ||
|
|
89307727e7 | ||
|
|
c30c21b250 | ||
|
|
b6fb087d7e | ||
|
|
97c2b7c1fe | ||
|
|
81506640c8 | ||
|
|
8244f7cd58 | ||
|
|
63573d6e26 | ||
|
|
9368f7f670 | ||
|
|
b7a11035d5 | ||
|
|
2e1b5e2fa7 | ||
|
|
8e5cbafe63 | ||
|
|
eb006a6688 | ||
|
|
40b9049deb | ||
|
|
64ffca2d0a | ||
|
|
1f4b6d4e9a | ||
|
|
eb30ba7722 | ||
|
|
3e0f4d36bc | ||
|
|
1fb118edee | ||
|
|
ca39634880 | ||
|
|
f8418d68a6 | ||
|
|
c0000fb24e | ||
|
|
c169f7ae83 | ||
|
|
7ab5244bf5 | ||
|
|
7e36489034 | ||
|
|
d259b12ae7 | ||
|
|
8f8138d9bd | ||
|
|
a8668f5fbf | ||
|
|
e00e6bd1c2 | ||
|
|
0fc6c47556 | ||
|
|
d530dccb96 | ||
|
|
37bf0e81d2 | ||
|
|
f872f955b0 | ||
|
|
003cd0a203 | ||
|
|
e7173f8145 | ||
|
|
93af102bec | ||
|
|
67f23664c9 | ||
|
|
39f6071c68 | ||
|
|
edc8878632 | ||
|
|
93b62c4dfd | ||
|
|
c3e210c80f | ||
|
|
9a5cc8f650 | ||
|
|
5e7fbfefe9 | ||
|
|
29ad6fba22 | ||
|
|
c848c3ee0d | ||
|
|
547132131a | ||
|
|
40186fb54b | ||
|
|
5dc4e79c8d | ||
|
|
556992a117 | ||
|
|
a41ef8d513 | ||
|
|
6d96a89328 | ||
|
|
0fb1481038 | ||
|
|
4b77530c65 | ||
|
|
cdb493cf50 | ||
|
|
c9a574a764 | ||
|
|
bdb633a882 | ||
|
|
37aee7133d | ||
|
|
2cfd55f3ce | ||
|
|
2e8188e89d | ||
|
|
1e172caea3 | ||
|
|
6866cd0fb8 | ||
|
|
2719926870 | ||
|
|
406891abcc | ||
|
|
4be6e9009a | ||
|
|
6a31909557 | ||
|
|
f49f0d19f9 | ||
|
|
a2407f94e4 | ||
|
|
62a0be4a11 | ||
|
|
b9029f6c67 | ||
|
|
92496f42c9 | ||
|
|
841c907efc | ||
|
|
9bc288cd8e | ||
|
|
2ef0391b08 | ||
|
|
6db768d1a3 | ||
|
|
9b080950a9 | ||
|
|
3cd1fef4cb | ||
|
|
a491a801bf | ||
|
|
41ebb72276 | ||
|
|
e4c0e9073e | ||
|
|
efad733cc5 | ||
|
|
1fcd6e1811 | ||
|
|
75d697fa97 | ||
|
|
cde69670ba | ||
|
|
0be6c9cb97 | ||
|
|
8c9d2d3ca2 | ||
|
|
c84e73d8e6 | ||
|
|
3fb00f6c70 | ||
|
|
86305fdeb3 | ||
|
|
710e146d22 | ||
|
|
d5abc84bea | ||
|
|
6f8214c15c | ||
|
|
a56475e32f | ||
|
|
9dadd91887 | ||
|
|
df5a73bb35 | ||
|
|
a50bf59a2c | ||
|
|
241354ae52 | ||
|
|
c863116011 | ||
|
|
5cbd591a1e | ||
|
|
6bb78c9499 | ||
|
|
893f406a99 | ||
|
|
f722b898b0 | ||
|
|
18335b3eac | ||
|
|
4708b592e2 | ||
|
|
7598a2965c | ||
|
|
1b59761a19 | ||
|
|
7fd1053e0f | ||
|
|
e178e7f6a5 | ||
|
|
d0bf21ab16 | ||
|
|
c826965833 | ||
|
|
a76db39c19 | ||
|
|
323a538bdd | ||
|
|
2435feca3b | ||
|
|
29d059680c | ||
|
|
aaaf7f9d8b | ||
|
|
bc90ce569a | ||
|
|
27f9f1756b | ||
|
|
9135387cfa | ||
|
|
af3504e05c | ||
|
|
9c9eac9d46 | ||
|
|
f28383206a | ||
|
|
ba1c093d18 | ||
|
|
3ea3a85694 | ||
|
|
0e1a423889 | ||
|
|
3ce68ed53f | ||
|
|
90c10da398 | ||
|
|
630bf28c22 | ||
|
|
ff89c1d8e4 | ||
|
|
96703c23c8 | ||
|
|
2b78f5adad | ||
|
|
ab7df777eb | ||
|
|
adbc694ff8 | ||
|
|
7709cdb12b | ||
|
|
f6051f73f5 | ||
|
|
d5c2a21cdf | ||
|
|
8ffc841a3a | ||
|
|
6c478977bb | ||
|
|
07beb53b37 | ||
|
|
59df1a8647 | ||
|
|
fb98aa650d | ||
|
|
9981b5a9c6 | ||
|
|
603533e632 | ||
|
|
38bc90f724 | ||
|
|
721beb9202 | ||
|
|
2e99259589 | ||
|
|
83e6b75872 | ||
|
|
cf70946f50 | ||
|
|
f1c36aba83 | ||
|
|
2973cf15a4 | ||
|
|
55969bc3c5 | ||
|
|
a8504c971a | ||
|
|
1644de2083 | ||
|
|
dd1fb85f60 | ||
|
|
b945b19865 | ||
|
|
91bf9f2ec8 | ||
|
|
f151f4c165 | ||
|
|
95b9b2d373 | ||
|
|
8be698681c | ||
|
|
da3e1a3730 | ||
|
|
29f637c19a | ||
|
|
3d01565ba7 | ||
|
|
962291cc8e | ||
|
|
a662dace9c | ||
|
|
d34e0b325e | ||
|
|
4c242ec528 | ||
|
|
658be9405f | ||
|
|
15e8f6ad8a | ||
|
|
a5aca35f1c | ||
|
|
ae9df1ffac | ||
|
|
8bf2e098f5 | ||
|
|
7091d554b5 | ||
|
|
bada795320 | ||
|
|
7d385849fb | ||
|
|
78775b7f6b | ||
|
|
8d21a5b6b3 | ||
|
|
9da095ca50 | ||
|
|
0fafc07db0 |
@@ -10,9 +10,15 @@ jobs:
|
||||
- run: if grep -Inr '\s$' kitty kitty_tests kittens docs *.py *.asciidoc *.rst .gitattributes .gitignore; then echo Trailing whitespace found, aborting.; exit 1; fi
|
||||
- run: python3 -m flake8 --count .
|
||||
- run: python3 setup.py build --debug --verbose
|
||||
- run: python3 test.py
|
||||
- run: ./kitty/launcher/kitty +launch test.py
|
||||
- run: make FAIL_WARN=-W man
|
||||
- run: make FAIL_WARN=-W html
|
||||
|
||||
lin-package:
|
||||
docker:
|
||||
- image: kovidgoyal/kitty-test:latest
|
||||
steps:
|
||||
- checkout
|
||||
- run: python3 setup.py linux-package --update-check-interval=0
|
||||
|
||||
lin-35:
|
||||
@@ -26,7 +32,7 @@ jobs:
|
||||
steps:
|
||||
- checkout
|
||||
- run: /opt/py3.5/bin/python3 setup.py build --debug --verbose --sanitize
|
||||
- run: ./asan-launcher test.py
|
||||
- run: ./kitty/launcher/kitty +launch test.py
|
||||
|
||||
lin-37:
|
||||
docker:
|
||||
@@ -38,7 +44,7 @@ jobs:
|
||||
steps:
|
||||
- checkout
|
||||
- run: /opt/py3.7/bin/python3 setup.py build --debug --verbose --sanitize
|
||||
- run: ./asan-launcher test.py
|
||||
- run: ./kitty/launcher/kitty +launch test.py
|
||||
|
||||
lin-bundle:
|
||||
docker:
|
||||
@@ -49,8 +55,9 @@ jobs:
|
||||
- checkout
|
||||
- run: echo "export LD_LIBRARY_PATH=$SW/lib" >> $BASH_ENV
|
||||
- run: echo "export PKG_CONFIG_PATH=$SW/lib/pkgconfig" >> $BASH_ENV
|
||||
- run: echo "export PYTHONHOME=$SW" >> $BASH_ENV
|
||||
- run: $SW/bin/python3 setup.py build --debug --verbose
|
||||
- run: $SW/bin/python3 test.py
|
||||
- run: ./kitty/launcher/kitty +launch test.py
|
||||
|
||||
mac-bundle:
|
||||
macos:
|
||||
@@ -65,21 +72,23 @@ jobs:
|
||||
- run: curl https://download.calibre-ebook.com/travis/kitty/osx.tar.xz | tar xJ -C $SW
|
||||
- run: echo "export PATH=$SW/bin:$PATH" >> $BASH_ENV
|
||||
- run: python3 setup.py build --debug --verbose
|
||||
- run: python3 test.py
|
||||
- run: ./kitty/launcher/kitty +launch test.py
|
||||
|
||||
mac-brew:
|
||||
macos:
|
||||
xcode: "10.1.0"
|
||||
xcode: "10.2.0"
|
||||
environment:
|
||||
LC_ALL: en_US.UTF-8
|
||||
LANG: en_US.UTF-8
|
||||
steps:
|
||||
- checkout
|
||||
- run: brew bundle
|
||||
- run: python3 logo/make.py
|
||||
- run: python3 setup.py build --debug --verbose
|
||||
- run: python3 test.py
|
||||
- run: python3 setup.py macos-bundle
|
||||
- run: ./kitty/launcher/kitty +launch test.py
|
||||
- run: echo "export PATH=/usr/local/opt/sphinx-doc/bin:$PATH" >> $BASH_ENV
|
||||
- run: python3 setup.py linux-package --verbose
|
||||
- run: python3 setup.py kitty.app --verbose
|
||||
- run: kitty.app/Contents/MacOS/kitty +runpy "from kitty.constants import *; print(kitty_exe())"
|
||||
|
||||
|
||||
workflows:
|
||||
@@ -90,5 +99,6 @@ workflows:
|
||||
- lin-sys
|
||||
- lin-35
|
||||
- lin-37
|
||||
- lin-package
|
||||
- lin-bundle
|
||||
- mac-brew
|
||||
|
||||
@@ -31,7 +31,7 @@ ENV LANG=en_US.UTF-8
|
||||
RUN apt-get install -y libreadline-dev zlib1g-dev libssl-dev libbz2-dev libsqlite3-dev libffi-dev
|
||||
|
||||
# kitty deps
|
||||
RUN apt-get install -y libgl1-mesa-dev libxi-dev libxrandr-dev libxinerama-dev libxcursor-dev libxcb-xkb-dev libdbus-1-dev libxkbcommon-dev libharfbuzz-dev libpng-dev libfontconfig-dev libpython3-dev libxkbcommon-x11-dev python3-pygments
|
||||
RUN apt-get install -y libgl1-mesa-dev libxi-dev libxrandr-dev libxinerama-dev libxcursor-dev libxcb-xkb-dev libdbus-1-dev libxkbcommon-dev libharfbuzz-dev libpng-dev libfontconfig-dev libpython3-dev libxkbcommon-x11-dev python3-pygments libcanberra-dev
|
||||
|
||||
# Needed to build kitty docs
|
||||
RUN pip3 install sphinx
|
||||
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -5,12 +5,11 @@ tags
|
||||
build
|
||||
linux-package
|
||||
kitty.app
|
||||
logo/*.iconset
|
||||
compile_commands.json
|
||||
link_commands.json
|
||||
glad/out
|
||||
asan-launcher
|
||||
asan-launcher.dSYM
|
||||
kitty-profile
|
||||
kitty/launcher
|
||||
*.dSYM
|
||||
dev
|
||||
__pycache__
|
||||
glfw/wayland-*-client-protocol.[ch]
|
||||
|
||||
3
Brewfile
3
Brewfile
@@ -1,6 +1,5 @@
|
||||
brew 'pkg-config'
|
||||
brew 'imagemagick'
|
||||
brew 'optipng'
|
||||
brew 'librsvg'
|
||||
brew 'harfbuzz'
|
||||
brew 'python'
|
||||
brew 'sphinx-doc'
|
||||
|
||||
7
Makefile
7
Makefile
@@ -28,12 +28,7 @@ asan:
|
||||
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
|
||||
app:
|
||||
python3 setup.py kitty.app $(VVAL)
|
||||
|
||||
man:
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* asan-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;
|
||||
}
|
||||
@@ -20,6 +20,7 @@ Run-time dependencies:
|
||||
* libpng
|
||||
* freetype (not needed on macOS)
|
||||
* fontconfig (not needed on macOS)
|
||||
* libcanberra (not needed on macOS)
|
||||
* ImageMagick (optional, needed to use the ``kitty icat`` tool to display images in the terminal)
|
||||
* pygments (optional, need for syntax highlighting in ``kitty +kitten diff``)
|
||||
|
||||
@@ -28,7 +29,7 @@ Build-time dependencies:
|
||||
* gcc or clang
|
||||
* pkg-config
|
||||
* For building on Linux in addition to the above dependencies you might also need to install the ``-dev`` packages for:
|
||||
``libdbus-1-dev``, ``libxcursor-dev``, ``libxrandr-dev``, ``libxi-dev``, ``libxinerama-dev``, ``libgl1-mesa-dev``, ``libxkbcommon-x11-dev``, ``libfontconfig-dev`` and ``libpython-dev``.
|
||||
``libdbus-1-dev``, ``libxcursor-dev``, ``libxrandr-dev``, ``libxi-dev``, ``libxinerama-dev``, ``libgl1-mesa-dev``, ``libxkbcommon-x11-dev``, ``libfontconfig-dev``, ``libcanberra-dev`` and ``libpython-dev``.
|
||||
if they are not already installed by your distro.
|
||||
|
||||
Install and run from source
|
||||
@@ -44,25 +45,17 @@ Now build the native code parts of |kitty| with the following command::
|
||||
|
||||
You can run |kitty|, as::
|
||||
|
||||
python3 .
|
||||
./kitty/launcher/kitty
|
||||
|
||||
If that works, you can create a script to launch |kitty|:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
#!/usr/bin/env python3
|
||||
import runpy
|
||||
runpy.run_path('/path/to/kitty/dir', run_name='__main__')
|
||||
|
||||
And place it in :file:`~/bin` or :file:`/usr/bin` so that you can run |kitty| using
|
||||
If that works, you can create a symlink to the launcher in :file:`~/bin` or
|
||||
some other directory on your PATH so that you can run |kitty| using
|
||||
just ``kitty``.
|
||||
|
||||
|
||||
Building kitty.app on macOS from source
|
||||
-------------------------------------------
|
||||
|
||||
Install `imagemagick`, `optipng` and `librsvg` using `brew` or similar (needed
|
||||
for the logo generation step). And run::
|
||||
Run::
|
||||
|
||||
make app
|
||||
|
||||
|
||||
@@ -4,6 +4,61 @@ Changelog
|
||||
|kitty| is a feature full, cross-platform, *fast*, GPU based terminal emulator.
|
||||
To update |kitty|, :doc:`follow the instructions <binary>`.
|
||||
|
||||
0.14.3 [2019-07-29]
|
||||
---------------------
|
||||
|
||||
- Remote control: Add a command `kitty @ scroll-window` to scroll windows
|
||||
|
||||
- Allow passing a ``!neighbor`` argument to the new_window mapping to open a
|
||||
new window next to the active window (:iss:`1746`)
|
||||
|
||||
- Document the kitty remote control protocol (:iss:`1646`)
|
||||
|
||||
- Add a new option :opt:`pointer_shape_when_grabbed` that allows you to control
|
||||
the mouse pointer shape when the terminal programs grabs the pointer
|
||||
(:iss:`1808`)
|
||||
|
||||
- Add an option :opt:`terminal_select_modifiers` to control which modifiers
|
||||
are used to override mouse selection even when a terminal application has
|
||||
grabbed the mouse (:iss:`1774`)
|
||||
|
||||
- When piping data to a child in the pipe command do it in a thread so as not
|
||||
to block the UI (:iss:`1708`)
|
||||
|
||||
- unicode_input kitten: Fix a regression that broke using indices to select
|
||||
recently used symbols.
|
||||
|
||||
- Fix a regression that caused closing an overlay window to focus
|
||||
the previously focused window rather than the underlying window (:iss:`1720`)
|
||||
|
||||
- macOS: Reduce energy consumption when idle by shutting down Apple's display
|
||||
link thread after 30 second of inactivity (:iss:`1763`)
|
||||
|
||||
- Linux: Fix incorrect scaling for fallback fonts when the font has an
|
||||
underscore that renders out of bounds (:iss:`1713`)
|
||||
|
||||
- macOS: Fix finding fallback font for private use unicode symbols not working
|
||||
reliably (:iss:`1650`)
|
||||
|
||||
- Fix an out of bounds read causing a crash when selecting text with the mouse
|
||||
in the alternate screen mode (:iss:`1578`)
|
||||
|
||||
- Linux: Use the system "bell" sound for the terminal bell. Adds libcanberra
|
||||
as a new dependency to play the system sound.
|
||||
|
||||
- macOS: Fix a rare deadlock causing kitty to hang (:iss:`1779`)
|
||||
|
||||
- Linux: Fix a regression in 0.14.0 that caused the event loop to tick
|
||||
continuously, wasting CPU even when idle (:iss:`1782`)
|
||||
|
||||
- ssh kitten: Make argument parsing more like ssh (:iss:`1787`)
|
||||
|
||||
- When using :opt:`strip_trailing_spaces` do not remove empty lines
|
||||
(:iss:`1802`)
|
||||
|
||||
- Fix a crash when displaying very large number of images (:iss:`1825`)
|
||||
|
||||
|
||||
0.14.2 [2019-06-09]
|
||||
---------------------
|
||||
|
||||
|
||||
48
docs/conf.py
48
docs/conf.py
@@ -276,6 +276,48 @@ def write_cli_docs(all_kitten_names):
|
||||
# }}}
|
||||
|
||||
|
||||
def write_remote_control_protocol_docs(): # {{{
|
||||
from kitty.cmds import cmap
|
||||
field_pat = re.compile(r'\s*([a-zA-Z0-9_+]+)\s*:\s*(.+)')
|
||||
|
||||
def format_cmd(p, name, cmd):
|
||||
p(name)
|
||||
p('-' * 80)
|
||||
lines = cmd.__doc__.strip().splitlines()
|
||||
fields = []
|
||||
for line in lines:
|
||||
m = field_pat.match(line)
|
||||
if m is None:
|
||||
p(line)
|
||||
else:
|
||||
fields.append((m.group(1), m.group(2)))
|
||||
if fields:
|
||||
p('\nFields are:\n')
|
||||
for (name, desc) in fields:
|
||||
if '+' in name:
|
||||
title = name.replace('+', ' (required)')
|
||||
else:
|
||||
title = name
|
||||
defval = cmd.get_default(name.replace('-', '_'), cmd)
|
||||
if defval is not cmd:
|
||||
title = f'{title} (default: {defval})'
|
||||
else:
|
||||
title = f'{title} (optional)'
|
||||
p(f':code:`{title}`')
|
||||
p(' ', desc), p()
|
||||
p(), p()
|
||||
|
||||
with open(f'generated/rc.rst', 'w') as f:
|
||||
p = partial(print, file=f)
|
||||
for name in sorted(cmap):
|
||||
cmd = cmap[name]
|
||||
if not cmd.__doc__:
|
||||
continue
|
||||
name = name.replace('_', '-')
|
||||
format_cmd(p, name, cmd)
|
||||
# }}}
|
||||
|
||||
|
||||
# config file docs {{{
|
||||
|
||||
class ConfLexer(RegexLexer):
|
||||
@@ -483,9 +525,12 @@ def process_shortcut_link(env, refnode, has_explicit_title, title, target):
|
||||
conf_name, slug = 'kitty', conf_name
|
||||
full_name = conf_name + '.' + slug
|
||||
try:
|
||||
target, title = shortcut_slugs[full_name]
|
||||
target, stitle = shortcut_slugs[full_name]
|
||||
except KeyError:
|
||||
logger.warning('Unknown shortcut: {}'.format(target), location=refnode)
|
||||
else:
|
||||
if not has_explicit_title:
|
||||
title = stitle
|
||||
return title, target
|
||||
|
||||
|
||||
@@ -537,6 +582,7 @@ def setup(app):
|
||||
from kittens.runner import all_kitten_names
|
||||
all_kitten_names = all_kitten_names()
|
||||
write_cli_docs(all_kitten_names)
|
||||
write_remote_control_protocol_docs()
|
||||
write_conf_docs(app, all_kitten_names)
|
||||
app.add_lexer('session', SessionLexer())
|
||||
app.add_role('link', link_role)
|
||||
|
||||
50
docs/faq.rst
50
docs/faq.rst
@@ -103,6 +103,28 @@ for |kitty| and use :ref:`at_set-colors`.
|
||||
A list of pre-made color themes for kitty is available at:
|
||||
`kitty-themes <https://github.com/dexpota/kitty-themes>`_
|
||||
|
||||
Examples of using OSC escape codes to set colors::
|
||||
|
||||
Change the default foreground color:
|
||||
printf '\x1b]10;#ff0000\x1b\\'
|
||||
Change the default background color:
|
||||
printf '\x1b]11;blue\x1b\\'
|
||||
Change the cursor color:
|
||||
printf '\x1b]12;blue\x1b\\'
|
||||
Change the selection background color:
|
||||
printf '\x1b]17;blue\x1b\\'
|
||||
Change the selection foreground color:
|
||||
printf '\x1b]19;blue\x1b\\'
|
||||
Change the nth color (0 - 255):
|
||||
printf '\x1b]4;n;green\x1b\\'
|
||||
|
||||
You can use various syntaxes/names for color specifications in the above
|
||||
examples. See `XParseColor <https://linux.die.net/man/3/xparsecolor>`_
|
||||
for full details.
|
||||
|
||||
If a ``?`` is given rather than a color specification, kitty will respond
|
||||
with the current value for the specified color.
|
||||
|
||||
|
||||
How do I specify command line options for kitty on macOS?
|
||||
---------------------------------------------------------------
|
||||
@@ -140,3 +162,31 @@ Bringing up applications on a single key press is the job of the window
|
||||
manager/desktop environment. For ways to do it with kitty (or indeed any
|
||||
terminal) in different environments,
|
||||
see `here <https://github.com/kovidgoyal/kitty/issues/45>`_.
|
||||
|
||||
|
||||
How do I map key presses in kitty to different keys in the terminal program?
|
||||
--------------------------------------------------------------------------------------
|
||||
|
||||
This is accomplished by using ``map`` with :sc:`send_text <send_text>` in :file:`kitty.conf`.
|
||||
For example::
|
||||
|
||||
map alt+s send_text all \x13
|
||||
|
||||
This maps :kbd:`alt+s`` to :kbd:`ctrl+s`. To figure out what bytes to use for
|
||||
the :sc:`send_text <send_text>` you can use the ``showkey`` utility. Run::
|
||||
|
||||
showkey -a
|
||||
|
||||
Then press the key you want to emulate. On macOS, this utility is currently not
|
||||
available. The manual way to figure it out is:
|
||||
|
||||
1. Look up your key's decimal value in the table at the bottom of `this
|
||||
page <http://ascii-table.com/ansi-escape-sequences.php>`_ or any
|
||||
ANSI escape sequence table. There are different modifiers for :kbd:`ctrl`,
|
||||
:kbd:`alt`, etc. For e.g., for :kbd:`ctrl+s`, find the ``S`` row and look at
|
||||
the third column value, ``19``.
|
||||
|
||||
2. Convert the decimal value to hex with ``kitty +runpy "print(hex(19))"``.
|
||||
This shows the hex value, ``13`` in this case.
|
||||
|
||||
3. Use ``\x(hexval)`` in your ``send_text`` command in kitty. So in this example, ``\x13``
|
||||
|
||||
@@ -368,6 +368,8 @@ Mouse features
|
||||
columns.
|
||||
* Selecting text automatically copies it to the primary clipboard (on
|
||||
platforms with a primary clipboard).
|
||||
* You can select text with kitty even when a terminal program has grabbed
|
||||
the mouse by holding down the :kbd:`shift` key.
|
||||
|
||||
|
||||
Font control
|
||||
@@ -448,6 +450,14 @@ Add the following to your :file:`~/.bashrc`
|
||||
|
||||
source <(kitty + complete setup bash)
|
||||
|
||||
Older versions of bash (for example, v3.2) do not support
|
||||
process substitution with the source command, in which
|
||||
case you can try an alternative:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
source /dev/stdin <<<"$(kitty + complete setup bash)"
|
||||
|
||||
|
||||
zsh
|
||||
~~~~~~~~~
|
||||
@@ -486,3 +496,4 @@ See :doc:`changelog`.
|
||||
|
||||
*
|
||||
kittens/*
|
||||
generated/rc
|
||||
|
||||
@@ -14,12 +14,12 @@ render loop to reduce CPU usage. See :ref:`conf-kitty-performance` for details.
|
||||
See also the :opt:`sync_to_monitor` option to further decrease latency at the cost
|
||||
of some `tearing <https://en.wikipedia.org/wiki/Screen_tearing>`_ while scrolling.
|
||||
|
||||
You can generate detailed per-function performance data using
|
||||
`gperftools <https://github.com/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.
|
||||
You can generate detailed per-function performance data using `gperftools
|
||||
<https://github.com/gperftools/gperftools>`_. Build |kitty| with `make
|
||||
profile`. Run kitty 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
|
||||
|
||||
29
docs/rc_protocol.rst
Normal file
29
docs/rc_protocol.rst
Normal file
@@ -0,0 +1,29 @@
|
||||
Documentation for the kitty remote control protocol
|
||||
======================================================
|
||||
|
||||
The kitty remote control protocol is a simple protocol that involves sending
|
||||
data to kitty in the form of JSON. Any individual command ot kitty has the
|
||||
form::
|
||||
|
||||
<ESC>P@kitty-cmd<JSON object><ESC>\
|
||||
|
||||
Where ``<ESC>`` is the byte ``0x1b``. The JSON object has the form::
|
||||
|
||||
{
|
||||
'cmd': "command name",
|
||||
'version': "kitty version",
|
||||
'no_response': Optional Boolean,
|
||||
'payload': <Optional JSON object>,
|
||||
}
|
||||
|
||||
The ``version`` above is a string of the form :code:`0.14.2`. If you are developing a
|
||||
standalone client, use the kitty version that you are developing against. Using
|
||||
a version greater than the version of the kitty instance you are talking to,
|
||||
will cause a failure.
|
||||
|
||||
Set ``no_response`` to True if you dont want a response from kitty.
|
||||
|
||||
The optional payload is a JSON object that is specific to the actual command being sent.
|
||||
The fields in the object for every command are documented below.
|
||||
|
||||
.. include:: generated/rc.rst
|
||||
@@ -134,5 +134,10 @@ still write to the pipes of any other program on the same computer and
|
||||
therefore can control |kitty|. It can, however, be useful to block programs
|
||||
running on other computers (for example, over ssh) or as other users.
|
||||
|
||||
Documentation for the remote control protocol
|
||||
-----------------------------------------------
|
||||
|
||||
If you wish to develop your own client to talk to |kitty|, you
|
||||
can use the :doc:`rc_protocol`.
|
||||
|
||||
.. include:: generated/cli-kitty-at.rst
|
||||
|
||||
@@ -8,9 +8,11 @@ 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'
|
||||
'glad --out-path {dest} --api gl:core=3.3 '
|
||||
' --extensions GL_ARB_texture_storage,GL_ARB_copy_image,GL_ARB_multisample,GL_ARB_robustness,GL_KHR_debug '
|
||||
'c --header-only --debug'
|
||||
)
|
||||
|
||||
|
||||
@@ -23,7 +25,7 @@ def regenerate():
|
||||
clean('out')
|
||||
|
||||
subprocess.check_call(
|
||||
shlex.split(cmdline.format(dest='out', generator='c-debug'))
|
||||
shlex.split(cmdline.format(dest='out'))
|
||||
)
|
||||
|
||||
|
||||
@@ -32,33 +34,12 @@ def strip_trailing_whitespace(c):
|
||||
|
||||
|
||||
def export():
|
||||
c = open('out/src/glad.c', 'rb').read().decode('utf-8')
|
||||
functions = []
|
||||
with open('out/include/glad/gl.h', 'r', encoding='utf-8') as source:
|
||||
data = source.read()
|
||||
data = strip_trailing_whitespace(data)
|
||||
|
||||
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(strip_trailing_whitespace(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(strip_trailing_whitespace(raw))
|
||||
raw = open('out/include/KHR/khrplatform.h', 'rb').read().decode('utf-8')
|
||||
open('../kitty/khrplatform.h', 'w').write(strip_trailing_whitespace(raw))
|
||||
with open('../kitty/gl-wrapper.h', 'w', encoding='utf-8') as dest:
|
||||
dest.write(data)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
89
glfw/backend_utils.c
vendored
89
glfw/backend_utils.c
vendored
@@ -11,6 +11,8 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <float.h>
|
||||
#include <time.h>
|
||||
@@ -220,24 +222,90 @@ dispatchTimers(EventLoopData *eld) {
|
||||
}
|
||||
|
||||
static void
|
||||
drain_wakeup_fd(int fd, int events, void* data) {
|
||||
drain_wakeup_fd(int fd, EventLoopData* eld) {
|
||||
static char drain_buf[64];
|
||||
while(read(fd, drain_buf, sizeof(drain_buf)) < 0 && errno == EINTR);
|
||||
eld->wakeup_data_read = false;
|
||||
while(true) {
|
||||
ssize_t ret = read(fd, drain_buf, sizeof(drain_buf));
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
break;
|
||||
}
|
||||
if (ret > 0) { eld->wakeup_data_read = true; continue; }
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mark_wakep_fd_ready(int fd UNUSED, int events UNUSED, void *data) {
|
||||
((EventLoopData*)(data))->wakeup_fd_ready = true;
|
||||
}
|
||||
|
||||
bool
|
||||
initPollData(EventLoopData *eld, int display_fd) {
|
||||
if (!addWatch(eld, "display", display_fd, POLLIN, 1, NULL, NULL)) return false;
|
||||
#ifdef HAS_EVENT_FD
|
||||
eld->wakeupFd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
|
||||
if (eld->wakeupFd == -1) return false;
|
||||
const int wakeup_fd = eld->wakeupFd;
|
||||
#else
|
||||
if (pipe2(eld->wakeupFds, O_CLOEXEC | O_NONBLOCK) != 0) return false;
|
||||
const int wakeup_fd = eld->wakeupFds[0];
|
||||
#endif
|
||||
if (!addWatch(eld, "wakeup", wakeup_fd, POLLIN, 1, mark_wakep_fd_ready, eld)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
initPollData(EventLoopData *eld, int wakeup_fd, int display_fd) {
|
||||
addWatch(eld, "display", display_fd, POLLIN, 1, NULL, NULL);
|
||||
addWatch(eld, "wakeup", wakeup_fd, POLLIN, 1, drain_wakeup_fd, NULL);
|
||||
check_for_wakeup_events(EventLoopData *eld) {
|
||||
#ifdef HAS_EVENT_FD
|
||||
int fd = eld->wakeupFd;
|
||||
#else
|
||||
int fd = eld->wakeupFds[0];
|
||||
#endif
|
||||
drain_wakeup_fd(fd, eld);
|
||||
}
|
||||
|
||||
void
|
||||
wakeupEventLoop(EventLoopData *eld) {
|
||||
#ifdef HAS_EVENT_FD
|
||||
static const uint64_t value = 1;
|
||||
while (write(eld->wakeupFd, &value, sizeof value) < 0 && (errno == EINTR || errno == EAGAIN));
|
||||
#else
|
||||
while (write(eld->wakeupFds[1], "w", 1) < 0 && (errno == EINTR || errno == EAGAIN));
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef HAS_EVENT_FD
|
||||
static inline void
|
||||
closeFds(int *fds, size_t count) {
|
||||
while(count--) {
|
||||
if (*fds > 0) {
|
||||
close(*fds);
|
||||
*fds = -1;
|
||||
}
|
||||
fds++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
finalizePollData(EventLoopData *eld) {
|
||||
#ifdef HAS_EVENT_FD
|
||||
close(eld->wakeupFd); eld->wakeupFd = -1;
|
||||
#else
|
||||
closeFds(eld->wakeupFds, arraysz(eld->wakeupFds));
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
pollForEvents(EventLoopData *eld, double timeout) {
|
||||
int read_ok = 0;
|
||||
timeout = prepareForPoll(eld, timeout);
|
||||
EVDBG("pollForEvents final timeout: %.3f", timeout);
|
||||
int result;
|
||||
double end_time = monotonic() + timeout;
|
||||
eld->wakeup_fd_ready = false;
|
||||
|
||||
while(1) {
|
||||
if (timeout >= 0) {
|
||||
@@ -270,17 +338,6 @@ pollForEvents(EventLoopData *eld, double timeout) {
|
||||
return read_ok;
|
||||
}
|
||||
|
||||
void
|
||||
closeFds(int *fds, size_t count) {
|
||||
while(count--) {
|
||||
if (*fds > 0) {
|
||||
close(*fds);
|
||||
*fds = -1;
|
||||
}
|
||||
fds++;
|
||||
}
|
||||
}
|
||||
|
||||
// Splits and translates a text/uri-list into separate file paths
|
||||
// NOTE: This function destroys the provided string
|
||||
//
|
||||
|
||||
21
glfw/backend_utils.h
vendored
21
glfw/backend_utils.h
vendored
@@ -29,6 +29,16 @@
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __has_include
|
||||
#if __has_include(<sys/eventfd.h>)
|
||||
#define HAS_EVENT_FD
|
||||
#include <sys/eventfd.h>
|
||||
#endif
|
||||
#else
|
||||
#define HAS_EVENT_FD
|
||||
#include <sys/eventfd.h>
|
||||
#endif
|
||||
|
||||
typedef unsigned long long id_type;
|
||||
typedef void(*watch_callback_func)(int, int, void*);
|
||||
typedef void(*timer_callback_func)(id_type, void*);
|
||||
@@ -56,13 +66,19 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
struct pollfd fds[32];
|
||||
#ifdef HAS_EVENT_FD
|
||||
int wakeupFd;
|
||||
#else
|
||||
int wakeupFds[2];
|
||||
#endif
|
||||
bool wakeup_data_read, wakeup_fd_ready;
|
||||
nfds_t watches_count, timers_count;
|
||||
Watch watches[32];
|
||||
Timer timers[128];
|
||||
} EventLoopData;
|
||||
|
||||
|
||||
void check_for_wakeup_events(EventLoopData *eld);
|
||||
id_type addWatch(EventLoopData *eld, const char *name, int fd, int events, int enabled, watch_callback_func cb, void *cb_data);
|
||||
void removeWatch(EventLoopData *eld, id_type watch_id);
|
||||
void toggleWatch(EventLoopData *eld, id_type watch_id, int enabled);
|
||||
@@ -75,6 +91,7 @@ double prepareForPoll(EventLoopData *eld, double timeout);
|
||||
int pollWithTimeout(struct pollfd *fds, nfds_t nfds, double timeout);
|
||||
int pollForEvents(EventLoopData *eld, double timeout);
|
||||
unsigned dispatchTimers(EventLoopData *eld);
|
||||
void closeFds(int *fds, size_t count);
|
||||
void initPollData(EventLoopData *eld, int wakeup_fd, int display_fd);
|
||||
void finalizePollData(EventLoopData *eld);
|
||||
bool initPollData(EventLoopData *eld, int display_fd);
|
||||
char** parseUriList(char* text, int* count);
|
||||
void wakeupEventLoop(EventLoopData *eld);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 macOS - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2009-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2009-2019 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
|
||||
@@ -23,9 +23,12 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
#include <sys/param.h> // For MAXPATHLEN
|
||||
#include <pthread.h>
|
||||
|
||||
// Change to our application bundle's resources directory, if present
|
||||
//
|
||||
@@ -247,13 +250,13 @@ static bool initializeTIS(void)
|
||||
CFStringRef* kPropertyUnicodeKeyLayoutData =
|
||||
CFBundleGetDataPointerForName(_glfw.ns.tis.bundle,
|
||||
CFSTR("kTISPropertyUnicodeKeyLayoutData"));
|
||||
_glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource =
|
||||
*(void **)&_glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource =
|
||||
CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
|
||||
CFSTR("TISCopyCurrentKeyboardLayoutInputSource"));
|
||||
_glfw.ns.tis.GetInputSourceProperty =
|
||||
*(void **)&_glfw.ns.tis.GetInputSourceProperty =
|
||||
CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
|
||||
CFSTR("TISGetInputSourceProperty"));
|
||||
_glfw.ns.tis.GetKbdType =
|
||||
*(void **)&_glfw.ns.tis.GetKbdType =
|
||||
CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
|
||||
CFSTR("LMGetKbdType"));
|
||||
|
||||
@@ -280,14 +283,16 @@ static bool initializeTIS(void)
|
||||
|
||||
- (void)selectedKeyboardInputSourceChanged:(NSObject* )object
|
||||
{
|
||||
(void)object;
|
||||
updateUnicodeDataNS();
|
||||
}
|
||||
|
||||
- (void)doNothing:(id)object
|
||||
{
|
||||
(void)object;
|
||||
}
|
||||
|
||||
@end // GLFWHelper
|
||||
@end // GLFWHelper
|
||||
|
||||
@interface GLFWApplication : NSApplication
|
||||
- (void)tick_callback;
|
||||
@@ -307,6 +312,7 @@ static bool initializeTIS(void)
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -332,6 +338,7 @@ is_cmd_period(NSEvent *event, NSEventModifierFlags modifierFlags) {
|
||||
int _glfwPlatformInit(void)
|
||||
{
|
||||
@autoreleasepool {
|
||||
|
||||
_glfw.ns.helper = [[GLFWHelper alloc] init];
|
||||
|
||||
[NSThread detachNewThreadSelector:@selector(doNothing:)
|
||||
@@ -374,6 +381,7 @@ int _glfwPlatformInit(void)
|
||||
_glfw.ns.keyDownMonitor =
|
||||
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyDown
|
||||
handler:keydown_block];
|
||||
|
||||
if (_glfw.hints.init.ns.chdir)
|
||||
changeToResourcesDirectory();
|
||||
|
||||
@@ -394,24 +402,20 @@ int _glfwPlatformInit(void)
|
||||
if (!initializeTIS())
|
||||
return false;
|
||||
|
||||
_glfw.ns.displayLinks.lock = [NSLock new];
|
||||
_glfwInitTimerNS();
|
||||
_glfwInitJoysticksNS();
|
||||
|
||||
_glfwPollMonitorsNS();
|
||||
}
|
||||
return true;
|
||||
|
||||
} // autoreleasepool
|
||||
}
|
||||
|
||||
void _glfwPlatformTerminate(void)
|
||||
{
|
||||
@autoreleasepool {
|
||||
|
||||
if (_glfw.ns.displayLinks.lock) {
|
||||
_glfwClearDisplayLinks();
|
||||
[_glfw.ns.displayLinks.lock release];
|
||||
_glfw.ns.displayLinks.lock = nil;
|
||||
}
|
||||
_glfwClearDisplayLinks();
|
||||
|
||||
if (_glfw.ns.inputSource)
|
||||
{
|
||||
@@ -444,6 +448,7 @@ void _glfwPlatformTerminate(void)
|
||||
[_glfw.ns.helper release];
|
||||
_glfw.ns.helper = nil;
|
||||
}
|
||||
|
||||
if (_glfw.ns.keyUpMonitor)
|
||||
[NSEvent removeMonitor:_glfw.ns.keyUpMonitor];
|
||||
if (_glfw.ns.keyDownMonitor)
|
||||
@@ -453,7 +458,8 @@ void _glfwPlatformTerminate(void)
|
||||
|
||||
_glfwTerminateNSGL();
|
||||
_glfwTerminateJoysticksNS();
|
||||
}
|
||||
|
||||
} // autoreleasepool
|
||||
}
|
||||
|
||||
const char* _glfwPlatformGetVersionString(void)
|
||||
@@ -468,32 +474,56 @@ const char* _glfwPlatformGetVersionString(void)
|
||||
static GLFWtickcallback tick_callback = NULL;
|
||||
static void* tick_callback_data = NULL;
|
||||
static bool tick_callback_requested = false;
|
||||
static pthread_t main_thread;
|
||||
static NSLock *tick_lock = NULL;
|
||||
|
||||
|
||||
void _glfwDispatchTickCallback() {
|
||||
if (tick_callback) {
|
||||
tick_callback_requested = false;
|
||||
tick_callback(tick_callback_data);
|
||||
if (tick_lock && tick_callback) {
|
||||
[tick_lock lock];
|
||||
while(tick_callback_requested) {
|
||||
tick_callback_requested = false;
|
||||
tick_callback(tick_callback_data);
|
||||
}
|
||||
[tick_lock unlock];
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwPlatformRequestTickCallback() {
|
||||
static void
|
||||
request_tick_callback() {
|
||||
if (!tick_callback_requested) {
|
||||
tick_callback_requested = true;
|
||||
[NSApp performSelectorOnMainThread:@selector(tick_callback) withObject:nil waitUntilDone:NO];
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwPlatformPostEmptyEvent(void)
|
||||
{
|
||||
if (pthread_equal(pthread_self(), main_thread)) {
|
||||
request_tick_callback();
|
||||
} else if (tick_lock) {
|
||||
[tick_lock lock];
|
||||
request_tick_callback();
|
||||
[tick_lock unlock];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void _glfwPlatformStopMainLoop(void) {
|
||||
tick_callback = NULL;
|
||||
[NSApp stop:nil];
|
||||
_glfwPlatformPostEmptyEvent();
|
||||
_glfwCocoaPostEmptyEvent();
|
||||
}
|
||||
|
||||
void _glfwPlatformRunMainLoop(GLFWtickcallback callback, void* data) {
|
||||
main_thread = pthread_self();
|
||||
tick_callback = callback;
|
||||
tick_callback_data = data;
|
||||
tick_lock = [NSLock new];
|
||||
[NSApp run];
|
||||
[tick_lock release];
|
||||
tick_lock = NULL;
|
||||
tick_callback = NULL;
|
||||
tick_callback_data = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
2
glfw/cocoa_joystick.h
vendored
2
glfw/cocoa_joystick.h
vendored
@@ -1,7 +1,7 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 Cocoa - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2017 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 Cocoa - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2009-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2009-2019 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
|
||||
@@ -24,6 +24,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@@ -75,7 +77,7 @@ static long getElementValue(_GLFWjoystick* js, _GLFWjoyelementNS* element)
|
||||
//
|
||||
static CFComparisonResult compareElements(const void* fp,
|
||||
const void* sp,
|
||||
void* user)
|
||||
void* user UNUSED)
|
||||
{
|
||||
const _GLFWjoyelementNS* fe = fp;
|
||||
const _GLFWjoyelementNS* se = sp;
|
||||
@@ -117,9 +119,9 @@ static void closeJoystick(_GLFWjoystick* js)
|
||||
|
||||
// Callback for user-initiated joystick addition
|
||||
//
|
||||
static void matchCallback(void* context,
|
||||
IOReturn result,
|
||||
void* sender,
|
||||
static void matchCallback(void* context UNUSED,
|
||||
IOReturn result UNUSED,
|
||||
void* sender UNUSED,
|
||||
IOHIDDeviceRef device)
|
||||
{
|
||||
int jid;
|
||||
@@ -270,9 +272,9 @@ static void matchCallback(void* context,
|
||||
|
||||
// Callback for user-initiated joystick removal
|
||||
//
|
||||
static void removeCallback(void* context,
|
||||
IOReturn result,
|
||||
void* sender,
|
||||
static void removeCallback(void* context UNUSED,
|
||||
IOReturn result UNUSED,
|
||||
void* sender UNUSED,
|
||||
IOHIDDeviceRef device)
|
||||
{
|
||||
int jid;
|
||||
@@ -316,7 +318,7 @@ void _glfwInitJoysticksNS(void)
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sizeof(usages) / sizeof(long); i++)
|
||||
for (size_t i = 0; i < sizeof(usages) / sizeof(long); i++)
|
||||
{
|
||||
const long page = kHIDPage_GenericDesktop;
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// GLFW 3.3 macOS - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2019 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
|
||||
@@ -24,6 +24,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@@ -215,7 +217,7 @@ static void endFadeReservation(CGDisplayFadeReservationToken token)
|
||||
|
||||
// Finds and caches the NSScreen corresponding to the specified monitor
|
||||
//
|
||||
bool refreshMonitorScreen(_GLFWmonitor* monitor)
|
||||
static bool refreshMonitorScreen(_GLFWmonitor* monitor)
|
||||
{
|
||||
if (monitor->ns.screen)
|
||||
return true;
|
||||
@@ -243,49 +245,30 @@ bool refreshMonitorScreen(_GLFWmonitor* monitor)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void _glfwClearDisplayLinks() {
|
||||
[_glfw.ns.displayLinks.lock lock];
|
||||
for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) {
|
||||
if (_glfw.ns.displayLinks.entries[i].displayLinkStarted) {
|
||||
CVDisplayLinkStop(_glfw.ns.displayLinks.entries[i].displayLink);
|
||||
_glfw.ns.displayLinks.entries[i].displayLinkStarted = false;
|
||||
}
|
||||
if (_glfw.ns.displayLinks.entries[i].displayLink) {
|
||||
CVDisplayLinkStop(_glfw.ns.displayLinks.entries[i].displayLink);
|
||||
CVDisplayLinkRelease(_glfw.ns.displayLinks.entries[i].displayLink);
|
||||
_glfw.ns.displayLinks.entries[i].displayLink = nil;
|
||||
_glfw.ns.displayLinks.entries[i].lastRenderFrameRequestedAt = 0;
|
||||
}
|
||||
}
|
||||
_glfw.ns.displayLinks.count = 0;
|
||||
[_glfw.ns.displayLinks.lock unlock];
|
||||
}
|
||||
|
||||
static CVReturn displayLinkCallback(
|
||||
CVDisplayLinkRef displayLink,
|
||||
const CVTimeStamp* now, const CVTimeStamp* outputTime,
|
||||
CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* userInfo)
|
||||
CVDisplayLinkRef displayLink UNUSED,
|
||||
const CVTimeStamp* now UNUSED, const CVTimeStamp* outputTime UNUSED,
|
||||
CVOptionFlags flagsIn UNUSED, CVOptionFlags* flagsOut UNUSED, void* userInfo)
|
||||
{
|
||||
CGDirectDisplayID displayID = (CGDirectDisplayID)userInfo;
|
||||
[_glfw.ns.displayLinks.lock lock];
|
||||
bool notify = false;
|
||||
for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) {
|
||||
if (_glfw.ns.displayLinks.entries[i].displayID == displayID) {
|
||||
if (_glfw.ns.displayLinks.entries[i].renderFrameRequested) {
|
||||
notify = true;
|
||||
_glfw.ns.displayLinks.entries[i].renderFrameRequested = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
[_glfw.ns.displayLinks.lock unlock];
|
||||
if (notify) {
|
||||
NSNumber *arg = [NSNumber numberWithUnsignedInt:displayID];
|
||||
[NSApp performSelectorOnMainThread:@selector(render_frame_received:) withObject:arg waitUntilDone:NO];
|
||||
[arg release];
|
||||
}
|
||||
NSNumber *arg = [NSNumber numberWithUnsignedInt:displayID];
|
||||
[NSApp performSelectorOnMainThread:@selector(render_frame_received:) withObject:arg waitUntilDone:NO];
|
||||
[arg release];
|
||||
return kCVReturnSuccess;
|
||||
}
|
||||
|
||||
static inline void createDisplayLink(CGDirectDisplayID displayID) {
|
||||
[_glfw.ns.displayLinks.lock lock];
|
||||
if (_glfw.ns.displayLinks.count >= sizeof(_glfw.ns.displayLinks.entries)/sizeof(_glfw.ns.displayLinks.entries[0]) - 1) return;
|
||||
for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) {
|
||||
if (_glfw.ns.displayLinks.entries[i].displayID == displayID) return;
|
||||
@@ -295,26 +278,24 @@ static inline void createDisplayLink(CGDirectDisplayID displayID) {
|
||||
entry->displayID = displayID;
|
||||
CVDisplayLinkCreateWithCGDisplay(displayID, &entry->displayLink);
|
||||
CVDisplayLinkSetOutputCallback(entry->displayLink, &displayLinkCallback, (void*)(uintptr_t)displayID);
|
||||
[_glfw.ns.displayLinks.lock unlock];
|
||||
}
|
||||
|
||||
// Poll for changes in the set of connected monitors
|
||||
//
|
||||
void _glfwPollMonitorsNS(void)
|
||||
{
|
||||
uint32_t i, j, displayCount, disconnectedCount;
|
||||
CGDirectDisplayID* displays;
|
||||
_GLFWmonitor** disconnected = NULL;
|
||||
uint32_t displayCount;
|
||||
|
||||
CGGetOnlineDisplayList(0, NULL, &displayCount);
|
||||
displays = calloc(displayCount, sizeof(CGDirectDisplayID));
|
||||
CGDirectDisplayID* displays = calloc(displayCount, sizeof(CGDirectDisplayID));
|
||||
CGGetOnlineDisplayList(displayCount, displays, &displayCount);
|
||||
_glfwClearDisplayLinks();
|
||||
|
||||
for (i = 0; i < _glfw.monitorCount; i++)
|
||||
for (int i = 0; i < _glfw.monitorCount; i++)
|
||||
_glfw.monitors[i]->ns.screen = nil;
|
||||
|
||||
disconnectedCount = _glfw.monitorCount;
|
||||
_GLFWmonitor** disconnected = NULL;
|
||||
uint32_t disconnectedCount = _glfw.monitorCount;
|
||||
if (disconnectedCount)
|
||||
{
|
||||
disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*));
|
||||
@@ -323,19 +304,18 @@ void _glfwPollMonitorsNS(void)
|
||||
_glfw.monitorCount * sizeof(_GLFWmonitor*));
|
||||
}
|
||||
|
||||
for (i = 0; i < displayCount; i++)
|
||||
for (uint32_t 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
|
||||
const uint32_t unitNumber = CGDisplayUnitNumber(displays[i]);
|
||||
|
||||
for (uint32_t 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;
|
||||
@@ -348,7 +328,7 @@ void _glfwPollMonitorsNS(void)
|
||||
if (!name)
|
||||
name = _glfw_strdup("Unknown");
|
||||
|
||||
monitor = _glfwAllocMonitor(name, size.width, size.height);
|
||||
_GLFWmonitor* monitor = _glfwAllocMonitor(name, size.width, size.height);
|
||||
monitor->ns.displayID = displays[i];
|
||||
monitor->ns.unitNumber = unitNumber;
|
||||
createDisplayLink(monitor->ns.displayID);
|
||||
@@ -358,7 +338,7 @@ void _glfwPollMonitorsNS(void)
|
||||
_glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST);
|
||||
}
|
||||
|
||||
for (i = 0; i < disconnectedCount; i++)
|
||||
for (uint32_t i = 0; i < disconnectedCount; i++)
|
||||
{
|
||||
if (disconnected[i])
|
||||
_glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0);
|
||||
@@ -373,24 +353,20 @@ void _glfwPollMonitorsNS(void)
|
||||
//
|
||||
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);
|
||||
const GLFWvidmode* best = _glfwChooseVideoMode(monitor, desired);
|
||||
_glfwPlatformGetVideoMode(monitor, ¤t);
|
||||
if (_glfwCompareVideoModes(¤t, best) == 0)
|
||||
return;
|
||||
|
||||
CVDisplayLinkRef link;
|
||||
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
|
||||
|
||||
modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
|
||||
count = CFArrayGetCount(modes);
|
||||
CFArrayRef modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
|
||||
const CFIndex count = CFArrayGetCount(modes);
|
||||
CGDisplayModeRef native = NULL;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
for (CFIndex i = 0; i < count; i++)
|
||||
{
|
||||
CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i);
|
||||
if (!modeIsGood(dm))
|
||||
@@ -439,7 +415,7 @@ void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor)
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
|
||||
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -468,7 +444,9 @@ void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
|
||||
*yscale = (float) (pixels.size.height / points.size.height);
|
||||
}
|
||||
|
||||
void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int *width, int *height)
|
||||
void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor,
|
||||
int* xpos, int* ypos,
|
||||
int* width, int* height)
|
||||
{
|
||||
if (!refreshMonitorScreen(monitor))
|
||||
return;
|
||||
@@ -488,20 +466,16 @@ void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos
|
||||
|
||||
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
|
||||
{
|
||||
CFArrayRef modes;
|
||||
CFIndex found, i, j;
|
||||
GLFWvidmode* result;
|
||||
CVDisplayLinkRef link;
|
||||
|
||||
*count = 0;
|
||||
|
||||
CVDisplayLinkRef link;
|
||||
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
|
||||
|
||||
modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
|
||||
found = CFArrayGetCount(modes);
|
||||
result = calloc(found, sizeof(GLFWvidmode));
|
||||
CFArrayRef modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
|
||||
const CFIndex found = CFArrayGetCount(modes);
|
||||
GLFWvidmode* result = calloc(found, sizeof(GLFWvidmode));
|
||||
|
||||
for (i = 0; i < found; i++)
|
||||
for (CFIndex i = 0; i < found; i++)
|
||||
{
|
||||
CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i);
|
||||
if (!modeIsGood(dm))
|
||||
@@ -509,7 +483,7 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
|
||||
|
||||
const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link);
|
||||
|
||||
for (j = 0; j < *count; j++)
|
||||
for (CFIndex j = 0; j < *count; j++)
|
||||
{
|
||||
if (_glfwCompareVideoModes(result + j, &mode) == 0)
|
||||
break;
|
||||
@@ -530,21 +504,20 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
|
||||
|
||||
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);
|
||||
CGDisplayModeRef native = CGDisplayCopyDisplayMode(monitor->ns.displayID);
|
||||
*mode = vidmodeFromCGDisplayMode(native, link);
|
||||
CGDisplayModeRelease(native);
|
||||
|
||||
CVDisplayLinkRelease(link);
|
||||
}
|
||||
|
||||
bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
{
|
||||
uint32_t i, size = CGDisplayGammaTableCapacity(monitor->ns.displayID);
|
||||
uint32_t size = CGDisplayGammaTableCapacity(monitor->ns.displayID);
|
||||
CGGammaValue* values = calloc(size * 3, sizeof(CGGammaValue));
|
||||
|
||||
CGGetDisplayTransferByTable(monitor->ns.displayID,
|
||||
@@ -556,7 +529,7 @@ bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
|
||||
_glfwAllocGammaArrays(ramp, size);
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
for (uint32_t i = 0; i < size; i++)
|
||||
{
|
||||
ramp->red[i] = (unsigned short) (values[i] * 65535);
|
||||
ramp->green[i] = (unsigned short) (values[i + size] * 65535);
|
||||
@@ -569,10 +542,9 @@ bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
|
||||
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
|
||||
{
|
||||
int i;
|
||||
CGGammaValue* values = calloc(ramp->size * 3, sizeof(CGGammaValue));
|
||||
|
||||
for (i = 0; i < ramp->size; i++)
|
||||
for (unsigned int i = 0; i < ramp->size; i++)
|
||||
{
|
||||
values[i] = ramp->red[i] / 65535.f;
|
||||
values[i + ramp->size] = ramp->green[i] / 65535.f;
|
||||
|
||||
17
glfw/cocoa_platform.h
vendored
17
glfw/cocoa_platform.h
vendored
@@ -1,7 +1,7 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 macOS - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2009-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2009-2019 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
|
||||
@@ -116,8 +116,8 @@ typedef struct _GLFWwindowNS
|
||||
id view;
|
||||
id layer;
|
||||
|
||||
bool maximized;
|
||||
bool retina;
|
||||
bool maximized;
|
||||
bool retina;
|
||||
|
||||
// Cached window properties to filter out duplicate events
|
||||
int width, height;
|
||||
@@ -144,8 +144,7 @@ typedef struct _GLFWDisplayLinkNS
|
||||
{
|
||||
CVDisplayLinkRef displayLink;
|
||||
CGDirectDisplayID displayID;
|
||||
bool displayLinkStarted;
|
||||
bool renderFrameRequested;
|
||||
double lastRenderFrameRequestedAt;
|
||||
} _GLFWDisplayLinkNS;
|
||||
|
||||
// Cocoa-specific global data
|
||||
@@ -154,7 +153,7 @@ typedef struct _GLFWlibraryNS
|
||||
{
|
||||
CGEventSourceRef eventSource;
|
||||
id delegate;
|
||||
bool cursorHidden;
|
||||
bool cursorHidden;
|
||||
TISInputSourceRef inputSource;
|
||||
IOHIDManagerRef hidManager;
|
||||
id unicodeData;
|
||||
@@ -184,7 +183,6 @@ typedef struct _GLFWlibraryNS
|
||||
struct {
|
||||
_GLFWDisplayLinkNS entries[256];
|
||||
size_t count;
|
||||
id lock;
|
||||
} displayLinks;
|
||||
|
||||
} _GLFWlibraryNS;
|
||||
@@ -222,9 +220,12 @@ void _glfwInitTimerNS(void);
|
||||
void _glfwPollMonitorsNS(void);
|
||||
void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired);
|
||||
void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor);
|
||||
|
||||
float _glfwTransformYNS(float y);
|
||||
|
||||
void _glfwClearDisplayLinks(void);
|
||||
void _glfwRestartDisplayLinks(void);
|
||||
void _glfwCocoaPostEmptyEvent(short subtype, long data1, bool at_start);
|
||||
void _glfwDispatchTickCallback(void);
|
||||
void _glfwDispatchRenderFrame(CGDirectDisplayID);
|
||||
void _glfwShutdownCVDisplayLink(unsigned long long, void*);
|
||||
void _glfwCocoaPostEmptyEvent(void);
|
||||
|
||||
2
glfw/cocoa_time.c
vendored
2
glfw/cocoa_time.c
vendored
@@ -23,6 +23,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 macOS - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2009-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2009-2019 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
|
||||
@@ -23,6 +23,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@@ -57,11 +59,23 @@ static NSUInteger getStyleMask(_GLFWwindow* window)
|
||||
CGDirectDisplayID displayIDForWindow(_GLFWwindow *w) {
|
||||
NSWindow *nw = w->ns.object;
|
||||
NSDictionary *dict = [nw.screen deviceDescription];
|
||||
NSNumber *displayIDns = [dict objectForKey:@"NSScreenNumber"];
|
||||
NSNumber *displayIDns = dict[@"NSScreenNumber"];
|
||||
if (displayIDns) return [displayIDns unsignedIntValue];
|
||||
return (CGDirectDisplayID)-1;
|
||||
}
|
||||
|
||||
static unsigned long long display_link_shutdown_timer = 0;
|
||||
#define DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL 30
|
||||
|
||||
void
|
||||
_glfwShutdownCVDisplayLink(unsigned long long timer_id UNUSED, void *user_data UNUSED) {
|
||||
display_link_shutdown_timer = 0;
|
||||
for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) {
|
||||
_GLFWDisplayLinkNS *dl = &_glfw.ns.displayLinks.entries[i];
|
||||
if (dl->displayLink) CVDisplayLinkStop(dl->displayLink);
|
||||
dl->lastRenderFrameRequestedAt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
requestRenderFrame(_GLFWwindow *w, GLFWcocoarenderframefun callback) {
|
||||
@@ -73,19 +87,22 @@ requestRenderFrame(_GLFWwindow *w, GLFWcocoarenderframefun callback) {
|
||||
w->ns.renderFrameCallback = callback;
|
||||
w->ns.renderFrameRequested = true;
|
||||
CGDirectDisplayID displayID = displayIDForWindow(w);
|
||||
[_glfw.ns.displayLinks.lock lock];
|
||||
if (display_link_shutdown_timer) {
|
||||
_glfwPlatformUpdateTimer(display_link_shutdown_timer, DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL, true);
|
||||
} else {
|
||||
display_link_shutdown_timer = _glfwPlatformAddTimer(DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL, false, _glfwShutdownCVDisplayLink, NULL, NULL);
|
||||
}
|
||||
double now = glfwGetTime();
|
||||
for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) {
|
||||
_GLFWDisplayLinkNS *dl = &_glfw.ns.displayLinks.entries[i];
|
||||
if (dl->displayID == displayID) {
|
||||
dl->renderFrameRequested = true;
|
||||
if (!dl->displayLinkStarted) {
|
||||
CVDisplayLinkStart(dl->displayLink);
|
||||
dl->displayLinkStarted = true;
|
||||
}
|
||||
break;
|
||||
dl->lastRenderFrameRequestedAt = now;
|
||||
if (!CVDisplayLinkIsRunning(dl->displayLink)) CVDisplayLinkStart(dl->displayLink);
|
||||
} else if (dl->displayLink && dl->lastRenderFrameRequestedAt && now - dl->lastRenderFrameRequestedAt >= DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL) {
|
||||
CVDisplayLinkStop(dl->displayLink);
|
||||
dl->lastRenderFrameRequestedAt = 0;
|
||||
}
|
||||
}
|
||||
[_glfw.ns.displayLinks.lock unlock];
|
||||
}
|
||||
|
||||
void
|
||||
@@ -108,7 +125,7 @@ static bool cursorInContentArea(_GLFWwindow* window)
|
||||
|
||||
// Hides the cursor if not already hidden
|
||||
//
|
||||
static void hideCursor(_GLFWwindow* window)
|
||||
static void hideCursor(_GLFWwindow* window UNUSED)
|
||||
{
|
||||
if (!_glfw.ns.cursorHidden)
|
||||
{
|
||||
@@ -119,7 +136,7 @@ static void hideCursor(_GLFWwindow* window)
|
||||
|
||||
// Shows the cursor if not already shown
|
||||
//
|
||||
static void showCursor(_GLFWwindow* window)
|
||||
static void showCursor(_GLFWwindow* window UNUSED)
|
||||
{
|
||||
if (_glfw.ns.cursorHidden)
|
||||
{
|
||||
@@ -333,9 +350,8 @@ static int translateKey(unsigned int key, bool apply_keymap)
|
||||
}
|
||||
|
||||
static void
|
||||
display_reconfigured(CGDirectDisplayID display, CGDisplayChangeSummaryFlags flags, void *userInfo)
|
||||
display_reconfigured(CGDirectDisplayID display UNUSED, CGDisplayChangeSummaryFlags flags, void *userInfo UNUSED)
|
||||
{
|
||||
(void)(userInfo); (void)(display); (void)(flags);
|
||||
if (flags & kCGDisplayBeginConfigurationFlag) {
|
||||
return;
|
||||
}
|
||||
@@ -374,9 +390,7 @@ static NSUInteger translateKeyToModifierFlag(int key)
|
||||
static const NSRange kEmptyRange = { NSNotFound, 0 };
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Delegate for window related notifications
|
||||
//------------------------------------------------------------------------
|
||||
// Delegate for window related notifications {{{
|
||||
|
||||
@interface GLFWWindowDelegate : NSObject
|
||||
{
|
||||
@@ -400,12 +414,14 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
||||
|
||||
- (BOOL)windowShouldClose:(id)sender
|
||||
{
|
||||
(void)sender;
|
||||
_glfwInputWindowCloseRequest(window);
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)windowDidResize:(NSNotification *)notification
|
||||
{
|
||||
(void)notification;
|
||||
if (window->context.client != GLFW_NO_API)
|
||||
[window->context.nsgl.object update];
|
||||
|
||||
@@ -441,6 +457,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
||||
|
||||
- (void)windowDidMove:(NSNotification *)notification
|
||||
{
|
||||
(void)notification;
|
||||
if (window->context.client != GLFW_NO_API)
|
||||
[window->context.nsgl.object update];
|
||||
|
||||
@@ -454,11 +471,13 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
||||
|
||||
- (void)windowDidChangeOcclusionState:(NSNotification *)notification
|
||||
{
|
||||
(void)notification;
|
||||
_glfwInputWindowOcclusion(window, !([window->ns.object occlusionState] & NSWindowOcclusionStateVisible));
|
||||
}
|
||||
|
||||
- (void)windowDidMiniaturize:(NSNotification *)notification
|
||||
{
|
||||
(void)notification;
|
||||
if (window->monitor)
|
||||
releaseMonitor(window);
|
||||
|
||||
@@ -467,6 +486,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
||||
|
||||
- (void)windowDidDeminiaturize:(NSNotification *)notification
|
||||
{
|
||||
(void)notification;
|
||||
if (window->monitor)
|
||||
acquireMonitor(window);
|
||||
|
||||
@@ -475,6 +495,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
||||
|
||||
- (void)windowDidBecomeKey:(NSNotification *)notification
|
||||
{
|
||||
(void)notification;
|
||||
if (_glfw.ns.disabledCursorWindow == window)
|
||||
_glfwCenterCursorInContentArea(window);
|
||||
|
||||
@@ -491,6 +512,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
||||
|
||||
- (void)windowDidResignKey:(NSNotification *)notification
|
||||
{
|
||||
(void)notification;
|
||||
if (window->monitor && window->autoIconify)
|
||||
_glfwPlatformIconifyWindow(window);
|
||||
showCursor(window);
|
||||
@@ -500,6 +522,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
||||
|
||||
- (void)windowDidChangeScreen:(NSNotification *)notification
|
||||
{
|
||||
(void)notification;
|
||||
if (window->ns.renderFrameRequested && window->ns.renderFrameCallback) {
|
||||
// Ensure that if the window changed its monitor, CVDisplayLink
|
||||
// is running for the new monitor
|
||||
@@ -508,12 +531,9 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@end // }}}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Delegate for application related notifications
|
||||
//------------------------------------------------------------------------
|
||||
// Delegate for application related notifications {{{
|
||||
|
||||
@interface GLFWApplicationDelegate : NSObject
|
||||
@end
|
||||
@@ -522,6 +542,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
||||
|
||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
|
||||
{
|
||||
(void)sender;
|
||||
_GLFWwindow* window;
|
||||
|
||||
for (window = _glfw.windowListHead; window; window = window->next)
|
||||
@@ -534,6 +555,7 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
||||
|
||||
- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag
|
||||
{
|
||||
(void)sender;
|
||||
if (!handle_reopen_callback) return YES;
|
||||
if (handle_reopen_callback(flag)) return YES;
|
||||
return NO;
|
||||
@@ -541,6 +563,7 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
||||
|
||||
- (void)applicationDidChangeScreenParameters:(NSNotification *) notification
|
||||
{
|
||||
(void)notification;
|
||||
_GLFWwindow* window;
|
||||
|
||||
for (window = _glfw.windowListHead; window; window = window->next)
|
||||
@@ -554,19 +577,22 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)notification
|
||||
{
|
||||
(void)notification;
|
||||
[NSApp stop:nil];
|
||||
|
||||
CGDisplayRegisterReconfigurationCallback(display_reconfigured, NULL);
|
||||
_glfwPlatformPostEmptyEvent();
|
||||
_glfwCocoaPostEmptyEvent();
|
||||
}
|
||||
|
||||
- (void)applicationWillTerminate:(NSNotification *)aNotification
|
||||
{
|
||||
(void)aNotification;
|
||||
CGDisplayRemoveReconfigurationCallback(display_reconfigured, NULL);
|
||||
}
|
||||
|
||||
- (void)applicationDidHide:(NSNotification *)notification
|
||||
{
|
||||
(void)notification;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < _glfw.monitorCount; i++)
|
||||
@@ -574,11 +600,9 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
||||
}
|
||||
|
||||
@end
|
||||
// }}}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Content view class for the GLFW window
|
||||
//------------------------------------------------------------------------
|
||||
// Content view class for the GLFW window {{{
|
||||
|
||||
@interface GLFWContentView : NSView <NSTextInputClient>
|
||||
{
|
||||
@@ -588,6 +612,7 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
||||
NSRect markedRect;
|
||||
}
|
||||
|
||||
- (void) removeGLFWWindow;
|
||||
- (instancetype)initWithGlfwWindow:(_GLFWwindow *)initWindow;
|
||||
|
||||
@end
|
||||
@@ -618,13 +643,18 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) removeGLFWWindow
|
||||
{
|
||||
window = NULL;
|
||||
}
|
||||
|
||||
- (_GLFWwindow*)glfwWindow {
|
||||
return window;
|
||||
}
|
||||
|
||||
- (BOOL)isOpaque
|
||||
{
|
||||
return [window->ns.object isOpaque];
|
||||
return window && [window->ns.object isOpaque];
|
||||
}
|
||||
|
||||
- (BOOL)canBecomeKeyView
|
||||
@@ -639,11 +669,13 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
||||
|
||||
- (void) viewWillStartLiveResize
|
||||
{
|
||||
if (!window) return;
|
||||
_glfwInputLiveResize(window, true);
|
||||
}
|
||||
|
||||
- (void)viewDidEndLiveResize
|
||||
{
|
||||
if (!window) return;
|
||||
_glfwInputLiveResize(window, false);
|
||||
}
|
||||
|
||||
@@ -654,6 +686,7 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
||||
|
||||
- (void)updateLayer
|
||||
{
|
||||
if (!window) return;
|
||||
if (window->context.client != GLFW_NO_API) {
|
||||
@try {
|
||||
[window->context.nsgl.object update];
|
||||
@@ -669,16 +702,19 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
||||
|
||||
- (void)cursorUpdate:(NSEvent *)event
|
||||
{
|
||||
updateCursorImage(window);
|
||||
(void)event;
|
||||
if (window) updateCursorImage(window);
|
||||
}
|
||||
|
||||
- (BOOL)acceptsFirstMouse:(NSEvent *)event
|
||||
{
|
||||
(void)event;
|
||||
return NO; // changed by Kovid, to follow cocoa platform conventions
|
||||
}
|
||||
|
||||
- (void)mouseDown:(NSEvent *)event
|
||||
{
|
||||
if (!window) return;
|
||||
_glfwInputMouseClick(window,
|
||||
GLFW_MOUSE_BUTTON_LEFT,
|
||||
GLFW_PRESS,
|
||||
@@ -692,6 +728,7 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
||||
|
||||
- (void)mouseUp:(NSEvent *)event
|
||||
{
|
||||
if (!window) return;
|
||||
_glfwInputMouseClick(window,
|
||||
GLFW_MOUSE_BUTTON_LEFT,
|
||||
GLFW_RELEASE,
|
||||
@@ -700,6 +737,7 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
||||
|
||||
- (void)mouseMoved:(NSEvent *)event
|
||||
{
|
||||
if (!window) return;
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
{
|
||||
const double dx = [event deltaX] - window->ns.cursorWarpDeltaX;
|
||||
@@ -724,6 +762,7 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
||||
|
||||
- (void)rightMouseDown:(NSEvent *)event
|
||||
{
|
||||
if (!window) return;
|
||||
_glfwInputMouseClick(window,
|
||||
GLFW_MOUSE_BUTTON_RIGHT,
|
||||
GLFW_PRESS,
|
||||
@@ -737,6 +776,7 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
||||
|
||||
- (void)rightMouseUp:(NSEvent *)event
|
||||
{
|
||||
if (!window) return;
|
||||
_glfwInputMouseClick(window,
|
||||
GLFW_MOUSE_BUTTON_RIGHT,
|
||||
GLFW_RELEASE,
|
||||
@@ -745,6 +785,7 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
||||
|
||||
- (void)otherMouseDown:(NSEvent *)event
|
||||
{
|
||||
if (!window) return;
|
||||
_glfwInputMouseClick(window,
|
||||
(int) [event buttonNumber],
|
||||
GLFW_PRESS,
|
||||
@@ -758,6 +799,7 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
||||
|
||||
- (void)otherMouseUp:(NSEvent *)event
|
||||
{
|
||||
if (!window) return;
|
||||
_glfwInputMouseClick(window,
|
||||
(int) [event buttonNumber],
|
||||
GLFW_RELEASE,
|
||||
@@ -766,16 +808,21 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
||||
|
||||
- (void)mouseExited:(NSEvent *)event
|
||||
{
|
||||
(void)event;
|
||||
if (!window) return;
|
||||
_glfwInputCursorEnter(window, false);
|
||||
}
|
||||
|
||||
- (void)mouseEntered:(NSEvent *)event
|
||||
{
|
||||
(void)event;
|
||||
if (!window) return;
|
||||
_glfwInputCursorEnter(window, true);
|
||||
}
|
||||
|
||||
- (void)viewDidChangeBackingProperties
|
||||
{
|
||||
if (!window) return;
|
||||
const NSRect contentRect = [window->ns.view frame];
|
||||
const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect];
|
||||
|
||||
@@ -803,6 +850,8 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
||||
|
||||
- (void)drawRect:(NSRect)rect
|
||||
{
|
||||
(void)rect;
|
||||
if (!window) return;
|
||||
_glfwInputWindowDamage(window);
|
||||
}
|
||||
|
||||
@@ -975,10 +1024,9 @@ is_ascii_control_char(char x) {
|
||||
|
||||
- (void)scrollWheel:(NSEvent *)event
|
||||
{
|
||||
double deltaX, deltaY;
|
||||
double deltaX = [event scrollingDeltaX];
|
||||
double deltaY = [event scrollingDeltaY];
|
||||
|
||||
deltaX = [event scrollingDeltaX];
|
||||
deltaY = [event scrollingDeltaY];
|
||||
int flags = [event hasPreciseScrollingDeltas] ? 1 : 0;
|
||||
if (flags) {
|
||||
float xscale = 1, yscale = 1;
|
||||
@@ -1010,8 +1058,9 @@ is_ascii_control_char(char x) {
|
||||
|
||||
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
|
||||
{
|
||||
(void)sender;
|
||||
// HACK: We don't know what to say here because we don't know what the
|
||||
// application wants to do with the paths
|
||||
// application wants to do with the paths
|
||||
return NSDragOperationGeneric;
|
||||
}
|
||||
|
||||
@@ -1021,19 +1070,19 @@ is_ascii_control_char(char x) {
|
||||
// NOTE: The returned location uses base 0,1 not 0,0
|
||||
const NSPoint pos = [sender draggingLocation];
|
||||
_glfwInputCursorPos(window, pos.x, contentRect.size.height - pos.y);
|
||||
|
||||
NSPasteboard* pasteboard = [sender draggingPasteboard];
|
||||
NSDictionary* options = @{NSPasteboardURLReadingFileURLsOnlyKey:@YES};
|
||||
NSArray* urls = [pasteboard readObjectsForClasses:@[[NSURL class]]
|
||||
options:options];
|
||||
if (!urls) return NO;
|
||||
const NSUInteger count = [urls count];
|
||||
|
||||
if (count)
|
||||
{
|
||||
char** paths = calloc(count, sizeof(char*));
|
||||
|
||||
for (NSUInteger i = 0; i < count; i++)
|
||||
paths[i] = _glfw_strdup([[urls objectAtIndex:i] fileSystemRepresentation]);
|
||||
paths[i] = _glfw_strdup([urls[i] fileSystemRepresentation]);
|
||||
|
||||
_glfwInputDrop(window, (int) count, (const char**) paths);
|
||||
|
||||
@@ -1067,6 +1116,7 @@ is_ascii_control_char(char x) {
|
||||
selectedRange:(NSRange)selectedRange
|
||||
replacementRange:(NSRange)replacementRange
|
||||
{
|
||||
(void)selectedRange; (void)replacementRange;
|
||||
[markedText release];
|
||||
if ([string isKindOfClass:[NSAttributedString class]])
|
||||
markedText = [[NSMutableAttributedString alloc] initWithAttributedString:string];
|
||||
@@ -1089,6 +1139,7 @@ void _glfwPlatformUpdateIMEState(_GLFWwindow *w, int which, int a, int b, int c,
|
||||
cellWidth:(CGFloat)cellWidth
|
||||
cellHeight:(CGFloat)cellHeight
|
||||
{
|
||||
(void) which;
|
||||
left /= window->ns.xscale;
|
||||
top /= window->ns.yscale;
|
||||
cellWidth /= window->ns.xscale;
|
||||
@@ -1109,22 +1160,26 @@ void _glfwPlatformUpdateIMEState(_GLFWwindow *w, int which, int a, int b, int c,
|
||||
- (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)range
|
||||
actualRange:(NSRangePointer)actualRange
|
||||
{
|
||||
(void)range; (void)actualRange;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSUInteger)characterIndexForPoint:(NSPoint)point
|
||||
{
|
||||
(void)point;
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (NSRect)firstRectForCharacterRange:(NSRange)range
|
||||
actualRange:(NSRangePointer)actualRange
|
||||
{
|
||||
(void)range; (void)actualRange;
|
||||
return markedRect;
|
||||
}
|
||||
|
||||
- (void)insertText:(id)string replacementRange:(NSRange)replacementRange
|
||||
{
|
||||
(void)replacementRange;
|
||||
NSString* characters;
|
||||
if ([string isKindOfClass:[NSAttributedString class]])
|
||||
characters = [string string];
|
||||
@@ -1138,20 +1193,44 @@ void _glfwPlatformUpdateIMEState(_GLFWwindow *w, int which, int a, int b, int c,
|
||||
|
||||
- (void)doCommandBySelector:(SEL)selector
|
||||
{
|
||||
(void)selector;
|
||||
}
|
||||
|
||||
@end
|
||||
// }}}
|
||||
|
||||
// GLFW Window class {{{
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// GLFW window class
|
||||
//------------------------------------------------------------------------
|
||||
@interface GLFWWindow : NSWindow {
|
||||
_GLFWwindow* glfw_window;
|
||||
}
|
||||
|
||||
@interface GLFWWindow : NSWindow {}
|
||||
- (instancetype)initWithGlfwWindow:(NSRect)contentRect
|
||||
styleMask:(NSWindowStyleMask)style
|
||||
backing:(NSBackingStoreType)backingStoreType
|
||||
initWindow:(_GLFWwindow *)initWindow;
|
||||
|
||||
- (void) removeGLFWWindow;
|
||||
@end
|
||||
|
||||
@implementation GLFWWindow
|
||||
|
||||
- (instancetype)initWithGlfwWindow:(NSRect)contentRect
|
||||
styleMask:(NSWindowStyleMask)style
|
||||
backing:(NSBackingStoreType)backingStoreType
|
||||
initWindow:(_GLFWwindow *)initWindow
|
||||
{
|
||||
self = [super initWithContentRect:contentRect styleMask:style backing:backingStoreType defer:NO];
|
||||
if (self != nil) glfw_window = initWindow;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) removeGLFWWindow
|
||||
{
|
||||
glfw_window = NULL;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)canBecomeKeyWindow
|
||||
{
|
||||
// Required for NSWindowStyleMaskBorderless windows
|
||||
@@ -1165,18 +1244,13 @@ void _glfwPlatformUpdateIMEState(_GLFWwindow *w, int which, int a, int b, int c,
|
||||
|
||||
- (void)toggleFullScreen:(nullable id)sender
|
||||
{
|
||||
GLFWContentView *view = [self contentView];
|
||||
if (view)
|
||||
{
|
||||
_GLFWwindow *window = [view glfwWindow];
|
||||
if (window && window->ns.toggleFullscreenCallback && window->ns.toggleFullscreenCallback((GLFWwindow*)window) == 1)
|
||||
if (glfw_window && glfw_window->ns.toggleFullscreenCallback && glfw_window->ns.toggleFullscreenCallback((GLFWwindow*)glfw_window) == 1)
|
||||
return;
|
||||
}
|
||||
[super toggleFullScreen:sender];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
// }}}
|
||||
|
||||
// Set up the menu bar (manually)
|
||||
// This is nasty, nasty stuff -- calls to undocumented semi-private APIs that
|
||||
@@ -1199,7 +1273,7 @@ static void createMenuBar(void)
|
||||
|
||||
for (i = 0; i < sizeof(nameKeys) / sizeof(nameKeys[0]); i++)
|
||||
{
|
||||
id name = [bundleInfo objectForKey:nameKeys[i]];
|
||||
id name = bundleInfo[nameKeys[i]];
|
||||
if (name &&
|
||||
[name isKindOfClass:[NSString class]] &&
|
||||
![name isEqualToString:@""])
|
||||
@@ -1213,7 +1287,7 @@ static void createMenuBar(void)
|
||||
{
|
||||
char** progname = _NSGetProgname();
|
||||
if (progname && *progname)
|
||||
appName = [NSString stringWithUTF8String:*progname];
|
||||
appName = @(*progname);
|
||||
else
|
||||
appName = @"GLFW Application";
|
||||
}
|
||||
@@ -1357,10 +1431,11 @@ static bool createNativeWindow(_GLFWwindow* window,
|
||||
contentRect = NSMakeRect(0, 0, wndconfig->width, wndconfig->height);
|
||||
|
||||
window->ns.object = [[GLFWWindow alloc]
|
||||
initWithContentRect:contentRect
|
||||
initWithGlfwWindow:contentRect
|
||||
styleMask:getStyleMask(window)
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:NO];
|
||||
initWindow:window
|
||||
];
|
||||
|
||||
if (window->ns.object == nil)
|
||||
{
|
||||
@@ -1372,7 +1447,7 @@ static bool createNativeWindow(_GLFWwindow* window,
|
||||
[window->ns.object setLevel:NSMainMenuWindowLevel + 1];
|
||||
else
|
||||
{
|
||||
[window->ns.object center];
|
||||
[(NSWindow*)window->ns.object center];
|
||||
_glfw.ns.cascadePoint =
|
||||
NSPointToCGPoint([window->ns.object cascadeTopLeftFromPoint:
|
||||
NSPointFromCGPoint(_glfw.ns.cascadePoint)]);
|
||||
@@ -1393,10 +1468,9 @@ static bool createNativeWindow(_GLFWwindow* window,
|
||||
}
|
||||
|
||||
if (strlen(wndconfig->ns.frameName))
|
||||
[window->ns.object setFrameAutosaveName:[NSString stringWithUTF8String:wndconfig->ns.frameName]];
|
||||
[window->ns.object setFrameAutosaveName:@(wndconfig->ns.frameName)];
|
||||
|
||||
window->ns.view = [[GLFWContentView alloc] initWithGlfwWindow:window];
|
||||
|
||||
window->ns.retina = wndconfig->ns.retina;
|
||||
|
||||
if (fbconfig->transparent)
|
||||
@@ -1408,7 +1482,7 @@ static bool createNativeWindow(_GLFWwindow* window,
|
||||
|
||||
[window->ns.object setContentView:window->ns.view];
|
||||
[window->ns.object makeFirstResponder:window->ns.view];
|
||||
[window->ns.object setTitle:[NSString stringWithUTF8String:wndconfig->title]];
|
||||
[window->ns.object setTitle:@(wndconfig->title)];
|
||||
[window->ns.object setDelegate:window->ns.delegate];
|
||||
[window->ns.object setAcceptsMouseMovedEvents:YES];
|
||||
[window->ns.object setRestorable:NO];
|
||||
@@ -1488,24 +1562,26 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
|
||||
[window->ns.delegate release];
|
||||
window->ns.delegate = nil;
|
||||
|
||||
[window->ns.view removeGLFWWindow];
|
||||
[window->ns.view release];
|
||||
window->ns.view = nil;
|
||||
|
||||
[window->ns.object removeGLFWWindow];
|
||||
[window->ns.object close];
|
||||
window->ns.object = nil;
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char *title)
|
||||
void _glfwPlatformSetWindowTitle(_GLFWwindow* window UNUSED, const char *title)
|
||||
{
|
||||
NSString* string = [NSString stringWithUTF8String:title];
|
||||
NSString* string = @(title);
|
||||
[window->ns.object setTitle:string];
|
||||
// HACK: Set the miniwindow title explicitly as setTitle: doesn't update it
|
||||
// if the window lacks NSWindowStyleMaskTitled
|
||||
[window->ns.object setMiniwindowTitle:string];
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
|
||||
int count, const GLFWimage* images)
|
||||
void _glfwPlatformSetWindowIcon(_GLFWwindow* window UNUSED,
|
||||
int count UNUSED, const GLFWimage* images UNUSED)
|
||||
{
|
||||
// Regular windows do not have icons
|
||||
}
|
||||
@@ -1615,7 +1691,7 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
|
||||
*yscale = (float) (pixels.size.height / points.size.height);
|
||||
}
|
||||
|
||||
double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window)
|
||||
double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED)
|
||||
{
|
||||
return [NSEvent doubleClickInterval];
|
||||
}
|
||||
@@ -1649,12 +1725,12 @@ void _glfwPlatformHideWindow(_GLFWwindow* window)
|
||||
[window->ns.object orderOut:nil];
|
||||
}
|
||||
|
||||
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window)
|
||||
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window UNUSED)
|
||||
{
|
||||
[NSApp requestUserAttention:NSInformationalRequest];
|
||||
}
|
||||
|
||||
int _glfwPlatformWindowBell(_GLFWwindow* window)
|
||||
int _glfwPlatformWindowBell(_GLFWwindow* window UNUSED)
|
||||
{
|
||||
NSBeep();
|
||||
return true;
|
||||
@@ -1663,11 +1739,10 @@ int _glfwPlatformWindowBell(_GLFWwindow* window)
|
||||
void _glfwPlatformFocusWindow(_GLFWwindow* window)
|
||||
{
|
||||
// Make us the active application
|
||||
// HACK: This has been moved here from initializeAppKit to prevent
|
||||
// applications using only hidden windows from being activated, but
|
||||
// should probably not be done every time any window is shown
|
||||
// HACK: This is here to prevent applications using only hidden windows from
|
||||
// being activated, but should probably not be done every time any
|
||||
// window is shown
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
|
||||
[window->ns.object makeKeyAndOrderFront:nil];
|
||||
}
|
||||
|
||||
@@ -1675,7 +1750,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
|
||||
_GLFWmonitor* monitor,
|
||||
int xpos, int ypos,
|
||||
int width, int height,
|
||||
int refreshRate)
|
||||
int refreshRate UNUSED)
|
||||
{
|
||||
if (window->monitor == monitor)
|
||||
{
|
||||
@@ -1708,7 +1783,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
|
||||
// HACK: Changing the style mask can cause the first responder to be cleared
|
||||
[window->ns.object makeFirstResponder:window->ns.view];
|
||||
|
||||
if (monitor)
|
||||
if (window->monitor)
|
||||
{
|
||||
[window->ns.object setLevel:NSMainMenuWindowLevel + 1];
|
||||
[window->ns.object setHasShadow:NO];
|
||||
@@ -1800,12 +1875,12 @@ int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
|
||||
return ![window->ns.object isOpaque] && ![window->ns.view isOpaque];
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, bool enabled)
|
||||
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, bool enabled UNUSED)
|
||||
{
|
||||
[window->ns.object setStyleMask:getStyleMask(window)];
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, bool enabled)
|
||||
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, bool enabled UNUSED)
|
||||
{
|
||||
[window->ns.object setStyleMask:getStyleMask(window)];
|
||||
[window->ns.object makeFirstResponder:window->ns.view];
|
||||
@@ -1841,27 +1916,6 @@ _glfwDispatchRenderFrame(CGDirectDisplayID displayID) {
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwCocoaPostEmptyEvent(short subtype, long data1, bool at_start)
|
||||
{
|
||||
@autoreleasepool {
|
||||
NSEvent* event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined
|
||||
location:NSMakePoint(0, 0)
|
||||
modifierFlags:0
|
||||
timestamp:0
|
||||
windowNumber:0
|
||||
context:nil
|
||||
subtype:subtype
|
||||
data1:data1
|
||||
data2:0];
|
||||
[NSApp postEvent:event atStart:at_start ? YES : NO];
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwPlatformPostEmptyEvent(void)
|
||||
{
|
||||
_glfwCocoaPostEmptyEvent(0, 0, true);
|
||||
}
|
||||
|
||||
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
|
||||
{
|
||||
const NSRect contentRect = [window->ns.view frame];
|
||||
@@ -1901,7 +1955,7 @@ void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
|
||||
void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode UNUSED)
|
||||
{
|
||||
if (_glfwPlatformWindowFocused(window))
|
||||
updateCursorMode(window);
|
||||
@@ -1974,6 +2028,7 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||
|
||||
cursor->ns.object = [[NSCursor alloc] initWithImage:native
|
||||
hotSpot:NSMakePoint(xhot, yhot)];
|
||||
|
||||
[native release];
|
||||
if (cursor->ns.object == nil)
|
||||
return false;
|
||||
@@ -2018,7 +2073,7 @@ void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
|
||||
[(NSCursor*) cursor->ns.object release];
|
||||
}
|
||||
|
||||
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
||||
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor UNUSED)
|
||||
{
|
||||
if (cursorInContentArea(window))
|
||||
updateCursorImage(window);
|
||||
@@ -2051,8 +2106,7 @@ void _glfwPlatformSetClipboardString(const char* string)
|
||||
{
|
||||
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
|
||||
[pasteboard declareTypes:@[NSPasteboardTypeString] owner:nil];
|
||||
[pasteboard setString:[NSString stringWithUTF8String:string]
|
||||
forType:NSPasteboardTypeString];
|
||||
[pasteboard setString:@(string) forType:NSPasteboardTypeString];
|
||||
}
|
||||
|
||||
const char* _glfwPlatformGetClipboardString(void)
|
||||
@@ -2089,9 +2143,9 @@ void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)
|
||||
extensions[1] = "VK_MVK_macos_surface";
|
||||
}
|
||||
|
||||
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
|
||||
VkPhysicalDevice device,
|
||||
uint32_t queuefamily)
|
||||
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance UNUSED,
|
||||
VkPhysicalDevice device UNUSED,
|
||||
uint32_t queuefamily UNUSED)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -2136,6 +2190,7 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
|
||||
|
||||
if (window->ns.retina)
|
||||
[window->ns.layer setContentsScale:[window->ns.object backingScaleFactor]];
|
||||
|
||||
[window->ns.view setLayer:window->ns.layer];
|
||||
[window->ns.view setWantsLayer:YES];
|
||||
|
||||
@@ -2210,6 +2265,7 @@ GLFWAPI void glfwGetCocoaKeyEquivalent(int glfw_key, int glfw_mods, unsigned sho
|
||||
if (glfw_mods & GLFW_MOD_CAPS_LOCK)
|
||||
*cocoa_mods |= NSEventModifierFlagCapsLock;
|
||||
|
||||
START_ALLOW_CASE_RANGE
|
||||
switch(glfw_key) {
|
||||
#define K(ch, name) case GLFW_KEY_##name: *cocoa_key = ch; break;
|
||||
K('a', A);
|
||||
@@ -2287,9 +2343,11 @@ GLFWAPI void glfwGetCocoaKeyEquivalent(int glfw_key, int glfw_mods, unsigned sho
|
||||
K((unichar)(0x4E|NSEventModifierFlagNumericPad), KP_SUBTRACT);
|
||||
K((unichar)(0x51|NSEventModifierFlagNumericPad), KP_EQUAL);
|
||||
#undef K
|
||||
END_ALLOW_CASE_RANGE
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -2300,3 +2358,16 @@ float _glfwTransformYNS(float y)
|
||||
{
|
||||
return CGDisplayBounds(CGMainDisplayID()).size.height - y - 1;
|
||||
}
|
||||
|
||||
void _glfwCocoaPostEmptyEvent(void) {
|
||||
NSEvent* event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined
|
||||
location:NSMakePoint(0, 0)
|
||||
modifierFlags:0
|
||||
timestamp:0
|
||||
windowNumber:0
|
||||
context:nil
|
||||
subtype:0
|
||||
data1:0
|
||||
data2:0];
|
||||
[NSApp postEvent:event atStart:YES];
|
||||
}
|
||||
|
||||
2
glfw/context.c
vendored
2
glfw/context.c
vendored
@@ -24,6 +24,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// Please use C89 style variable declarations in this file because VS 2010
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
14
glfw/dbus_glfw.c
vendored
14
glfw/dbus_glfw.c
vendored
@@ -53,7 +53,7 @@ glfw_dbus_init(_GLFWDBUSData *dbus, EventLoopData *eld) {
|
||||
}
|
||||
|
||||
static void
|
||||
on_dbus_watch_ready(int fd, int events, void *data) {
|
||||
on_dbus_watch_ready(int fd UNUSED, int events, void *data) {
|
||||
DBusWatch *watch = (DBusWatch*)data;
|
||||
unsigned int flags = 0;
|
||||
if (events & POLLERR) flags |= DBUS_WATCH_ERROR;
|
||||
@@ -84,19 +84,19 @@ add_dbus_watch(DBusWatch *watch, void *data) {
|
||||
}
|
||||
|
||||
static void
|
||||
remove_dbus_watch(DBusWatch *watch, void *data) {
|
||||
remove_dbus_watch(DBusWatch *watch, void *data UNUSED) {
|
||||
id_type *idp = dbus_watch_get_data(watch);
|
||||
if (idp) removeWatch(dbus_data->eld, *idp);
|
||||
}
|
||||
|
||||
static void
|
||||
toggle_dbus_watch(DBusWatch *watch, void *data) {
|
||||
toggle_dbus_watch(DBusWatch *watch, void *data UNUSED) {
|
||||
id_type *idp = dbus_watch_get_data(watch);
|
||||
if (idp) toggleWatch(dbus_data->eld, *idp, dbus_watch_get_enabled(watch));
|
||||
}
|
||||
|
||||
static void
|
||||
on_dbus_timer_ready(id_type timer_id, void *data) {
|
||||
on_dbus_timer_ready(id_type timer_id UNUSED, void *data) {
|
||||
if (data) {
|
||||
DBusTimeout *t = (DBusTimeout*)data;
|
||||
dbus_timeout_handle(t);
|
||||
@@ -123,13 +123,13 @@ add_dbus_timeout(DBusTimeout *timeout, void *data) {
|
||||
}
|
||||
|
||||
static void
|
||||
remove_dbus_timeout(DBusTimeout *timeout, void *data) {
|
||||
remove_dbus_timeout(DBusTimeout *timeout, void *data UNUSED) {
|
||||
id_type *idp = dbus_timeout_get_data(timeout);
|
||||
if (idp) removeTimer(dbus_data->eld, *idp);
|
||||
}
|
||||
|
||||
static void
|
||||
toggle_dbus_timeout(DBusTimeout *timeout, void *data) {
|
||||
toggle_dbus_timeout(DBusTimeout *timeout, void *data UNUSED) {
|
||||
id_type *idp = dbus_timeout_get_data(timeout);
|
||||
if (idp) toggleTimer(dbus_data->eld, *idp, dbus_timeout_get_enabled(timeout));
|
||||
}
|
||||
@@ -178,7 +178,7 @@ glfw_dbus_session_bus_dispatch() {
|
||||
}
|
||||
|
||||
void
|
||||
glfw_dbus_terminate(_GLFWDBUSData *dbus) {
|
||||
glfw_dbus_terminate(_GLFWDBUSData *dbus UNUSED) {
|
||||
if (dbus_data) {
|
||||
dbus_data->eld = NULL;
|
||||
dbus_data = NULL;
|
||||
|
||||
60
glfw/egl_context.c
vendored
60
glfw/egl_context.c
vendored
@@ -2,7 +2,7 @@
|
||||
// GLFW 3.3 EGL - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2019 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
|
||||
@@ -24,6 +24,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// Please use C89 style variable declarations in this file because VS 2010
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@@ -253,8 +255,8 @@ static GLFWglproc getProcAddressEGL(const char* procname)
|
||||
|
||||
if (window->context.egl.client)
|
||||
{
|
||||
GLFWglproc proc = (GLFWglproc) _glfw_dlsym(window->context.egl.client,
|
||||
procname);
|
||||
GLFWglproc proc = NULL;
|
||||
glfw_dlsym(proc, window->context.egl.client, procname);
|
||||
if (proc)
|
||||
return proc;
|
||||
}
|
||||
@@ -335,38 +337,22 @@ bool _glfwInitEGL(void)
|
||||
|
||||
_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");
|
||||
glfw_dlsym(_glfw.egl.GetConfigAttrib, _glfw.egl.handle, "eglGetConfigAttrib");
|
||||
glfw_dlsym(_glfw.egl.GetConfigs, _glfw.egl.handle, "eglGetConfigs");
|
||||
glfw_dlsym(_glfw.egl.GetDisplay, _glfw.egl.handle, "eglGetDisplay");
|
||||
glfw_dlsym(_glfw.egl.GetError, _glfw.egl.handle, "eglGetError");
|
||||
glfw_dlsym(_glfw.egl.Initialize, _glfw.egl.handle, "eglInitialize");
|
||||
glfw_dlsym(_glfw.egl.Terminate, _glfw.egl.handle, "eglTerminate");
|
||||
glfw_dlsym(_glfw.egl.BindAPI, _glfw.egl.handle, "eglBindAPI");
|
||||
glfw_dlsym(_glfw.egl.CreateContext, _glfw.egl.handle, "eglCreateContext");
|
||||
glfw_dlsym(_glfw.egl.DestroySurface, _glfw.egl.handle, "eglDestroySurface");
|
||||
glfw_dlsym(_glfw.egl.DestroyContext, _glfw.egl.handle, "eglDestroyContext");
|
||||
glfw_dlsym(_glfw.egl.CreateWindowSurface, _glfw.egl.handle, "eglCreateWindowSurface");
|
||||
glfw_dlsym(_glfw.egl.MakeCurrent, _glfw.egl.handle, "eglMakeCurrent");
|
||||
glfw_dlsym(_glfw.egl.SwapBuffers, _glfw.egl.handle, "eglSwapBuffers");
|
||||
glfw_dlsym(_glfw.egl.SwapInterval, _glfw.egl.handle, "eglSwapInterval");
|
||||
glfw_dlsym(_glfw.egl.QueryString, _glfw.egl.handle, "eglQueryString");
|
||||
glfw_dlsym(_glfw.egl.GetProcAddress, _glfw.egl.handle, "eglGetProcAddress");
|
||||
|
||||
if (!_glfw.egl.GetConfigAttrib ||
|
||||
!_glfw.egl.GetConfigs ||
|
||||
@@ -446,7 +432,7 @@ void _glfwTerminateEGL(void)
|
||||
|
||||
#define setAttrib(a, v) \
|
||||
{ \
|
||||
assert((size_t) (index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
|
||||
assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
|
||||
attribs[index++] = a; \
|
||||
attribs[index++] = v; \
|
||||
}
|
||||
@@ -714,7 +700,7 @@ bool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
// Returns the Visual and depth of the chosen EGLConfig
|
||||
//
|
||||
#if defined(_GLFW_X11)
|
||||
bool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig,
|
||||
bool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig UNUSED,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig,
|
||||
Visual** visual, int* depth)
|
||||
|
||||
14
glfw/egl_context.h
vendored
14
glfw/egl_context.h
vendored
@@ -2,7 +2,7 @@
|
||||
// GLFW 3.3 EGL - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2017 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
|
||||
@@ -173,13 +173,13 @@ typedef struct _GLFWlibraryEGL
|
||||
{
|
||||
EGLDisplay display;
|
||||
EGLint major, minor;
|
||||
bool prefix;
|
||||
bool prefix;
|
||||
|
||||
bool KHR_create_context;
|
||||
bool KHR_create_context_no_error;
|
||||
bool KHR_gl_colorspace;
|
||||
bool KHR_get_all_proc_addresses;
|
||||
bool KHR_context_flush_control;
|
||||
bool KHR_create_context;
|
||||
bool KHR_create_context_no_error;
|
||||
bool KHR_gl_colorspace;
|
||||
bool KHR_get_all_proc_addresses;
|
||||
bool KHR_context_flush_control;
|
||||
|
||||
void* handle;
|
||||
|
||||
|
||||
15
glfw/glfw.py
15
glfw/glfw.py
@@ -23,10 +23,6 @@ def wayland_protocol_file_name(base, ext='c'):
|
||||
|
||||
def init_env(env, pkg_config, at_least_version, test_compile, 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')
|
||||
@@ -88,7 +84,8 @@ def init_env(env, pkg_config, at_least_version, test_compile, module='x11'):
|
||||
return ans
|
||||
|
||||
|
||||
def build_wayland_protocols(env, run_tool, emphasis, newer, dest_dir):
|
||||
def build_wayland_protocols(env, Command, parallel_run, emphasis, newer, dest_dir):
|
||||
items = []
|
||||
for protocol in env.wayland_protocols:
|
||||
src = os.path.join(env.wayland_packagedir, protocol)
|
||||
if not os.path.exists(src):
|
||||
@@ -98,8 +95,12 @@ def build_wayland_protocols(env, run_tool, emphasis, newer, dest_dir):
|
||||
dest = os.path.join(dest_dir, dest)
|
||||
if newer(dest, src):
|
||||
q = 'client-header' if ext == 'h' else env.wayland_scanner_code
|
||||
run_tool([env.wayland_scanner, q, src, dest],
|
||||
desc='Generating {} ...'.format(emphasis(os.path.basename(dest))))
|
||||
items.append(Command(
|
||||
'Generating {} ...'.format(emphasis(os.path.basename(dest))),
|
||||
[env.wayland_scanner, q, src, dest],
|
||||
lambda: True, None, None, None))
|
||||
if items:
|
||||
parallel_run(items)
|
||||
|
||||
|
||||
class Arg:
|
||||
|
||||
43
glfw/glfw3.h
vendored
43
glfw/glfw3.h
vendored
@@ -3,7 +3,7 @@
|
||||
* A library for OpenGL, window and input
|
||||
*------------------------------------------------------------------------
|
||||
* Copyright (c) 2002-2006 Marcus Geelnard
|
||||
* Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
* Copyright (c) 2006-2019 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
|
||||
@@ -905,62 +905,62 @@ extern "C" {
|
||||
#define GLFW_CLIENT_API 0x00022001
|
||||
/*! @brief Context client API major version hint and attribute.
|
||||
*
|
||||
* Context client API major version [hint](@ref GLFW_CLIENT_API_hint) and
|
||||
* [attribute](@ref GLFW_CLIENT_API_attrib).
|
||||
* Context client API major version [hint](@ref GLFW_CONTEXT_VERSION_MAJOR_hint)
|
||||
* and [attribute](@ref GLFW_CONTEXT_VERSION_MAJOR_attrib).
|
||||
*/
|
||||
#define GLFW_CONTEXT_VERSION_MAJOR 0x00022002
|
||||
/*! @brief Context client API minor version hint and attribute.
|
||||
*
|
||||
* Context client API minor version [hint](@ref GLFW_CLIENT_API_hint) and
|
||||
* [attribute](@ref GLFW_CLIENT_API_attrib).
|
||||
* Context client API minor version [hint](@ref GLFW_CONTEXT_VERSION_MINOR_hint)
|
||||
* and [attribute](@ref GLFW_CONTEXT_VERSION_MINOR_attrib).
|
||||
*/
|
||||
#define GLFW_CONTEXT_VERSION_MINOR 0x00022003
|
||||
/*! @brief Context client API revision number hint and attribute.
|
||||
*
|
||||
* Context client API revision number [hint](@ref GLFW_CLIENT_API_hint) and
|
||||
* [attribute](@ref GLFW_CLIENT_API_attrib).
|
||||
* Context client API revision number
|
||||
* [attribute](@ref GLFW_CONTEXT_REVISION_attrib).
|
||||
*/
|
||||
#define GLFW_CONTEXT_REVISION 0x00022004
|
||||
/*! @brief Context robustness hint and attribute.
|
||||
*
|
||||
* Context client API revision number [hint](@ref GLFW_CLIENT_API_hint) and
|
||||
* [attribute](@ref GLFW_CLIENT_API_attrib).
|
||||
* Context client API revision number [hint](@ref GLFW_CONTEXT_ROBUSTNESS_hint)
|
||||
* and [attribute](@ref GLFW_CONTEXT_ROBUSTNESS_attrib).
|
||||
*/
|
||||
#define GLFW_CONTEXT_ROBUSTNESS 0x00022005
|
||||
/*! @brief OpenGL forward-compatibility hint and attribute.
|
||||
*
|
||||
* OpenGL forward-compatibility [hint](@ref GLFW_CLIENT_API_hint) and
|
||||
* [attribute](@ref GLFW_CLIENT_API_attrib).
|
||||
* OpenGL forward-compatibility [hint](@ref GLFW_OPENGL_FORWARD_COMPAT_hint)
|
||||
* and [attribute](@ref GLFW_OPENGL_FORWARD_COMPAT_attrib).
|
||||
*/
|
||||
#define GLFW_OPENGL_FORWARD_COMPAT 0x00022006
|
||||
/*! @brief OpenGL debug context hint and attribute.
|
||||
*
|
||||
* OpenGL debug context [hint](@ref GLFW_CLIENT_API_hint) and
|
||||
* [attribute](@ref GLFW_CLIENT_API_attrib).
|
||||
* OpenGL debug context [hint](@ref GLFW_OPENGL_DEBUG_CONTEXT_hint) and
|
||||
* [attribute](@ref GLFW_OPENGL_DEBUG_CONTEXT_attrib).
|
||||
*/
|
||||
#define GLFW_OPENGL_DEBUG_CONTEXT 0x00022007
|
||||
/*! @brief OpenGL profile hint and attribute.
|
||||
*
|
||||
* OpenGL profile [hint](@ref GLFW_CLIENT_API_hint) and
|
||||
* [attribute](@ref GLFW_CLIENT_API_attrib).
|
||||
* OpenGL profile [hint](@ref GLFW_OPENGL_PROFILE_hint) and
|
||||
* [attribute](@ref GLFW_OPENGL_PROFILE_attrib).
|
||||
*/
|
||||
#define GLFW_OPENGL_PROFILE 0x00022008
|
||||
/*! @brief Context flush-on-release hint and attribute.
|
||||
*
|
||||
* Context flush-on-release [hint](@ref GLFW_CLIENT_API_hint) and
|
||||
* [attribute](@ref GLFW_CLIENT_API_attrib).
|
||||
* Context flush-on-release [hint](@ref GLFW_CONTEXT_RELEASE_BEHAVIOR_hint) and
|
||||
* [attribute](@ref GLFW_CONTEXT_RELEASE_BEHAVIOR_attrib).
|
||||
*/
|
||||
#define GLFW_CONTEXT_RELEASE_BEHAVIOR 0x00022009
|
||||
/*! @brief Context error suppression hint and attribute.
|
||||
*
|
||||
* Context error suppression [hint](@ref GLFW_CLIENT_API_hint) and
|
||||
* [attribute](@ref GLFW_CLIENT_API_attrib).
|
||||
* Context error suppression [hint](@ref GLFW_CONTEXT_NO_ERROR_hint) and
|
||||
* [attribute](@ref GLFW_CONTEXT_NO_ERROR_attrib).
|
||||
*/
|
||||
#define GLFW_CONTEXT_NO_ERROR 0x0002200A
|
||||
/*! @brief Context creation API hint and attribute.
|
||||
*
|
||||
* Context creation API [hint](@ref GLFW_CLIENT_API_hint) and
|
||||
* [attribute](@ref GLFW_CLIENT_API_attrib).
|
||||
* Context creation API [hint](@ref GLFW_CONTEXT_CREATION_API_hint) and
|
||||
* [attribute](@ref GLFW_CONTEXT_CREATION_API_attrib).
|
||||
*/
|
||||
#define GLFW_CONTEXT_CREATION_API 0x0002200B
|
||||
/*! @brief Window content area scaling window
|
||||
@@ -1628,7 +1628,6 @@ typedef struct GLFWgamepadstate
|
||||
GLFWAPI int glfwInit(void);
|
||||
GLFWAPI void glfwRunMainLoop(GLFWtickcallback callback, void *callback_data);
|
||||
GLFWAPI void glfwStopMainLoop(void);
|
||||
GLFWAPI void glfwRequestTickCallback(void);
|
||||
GLFWAPI unsigned long long glfwAddTimer(double interval, bool repeats, GLFWuserdatafun callback, void * callback_data, GLFWuserdatafun free_callback);
|
||||
GLFWAPI void glfwUpdateTimer(unsigned long long timer_id, double interval, bool enabled);
|
||||
GLFWAPI void glfwRemoveTimer(unsigned long long);
|
||||
|
||||
64
glfw/glx_context.c
vendored
64
glfw/glx_context.c
vendored
@@ -2,7 +2,7 @@
|
||||
// GLFW 3.3 GLX - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2019 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
|
||||
@@ -24,6 +24,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@@ -142,7 +144,7 @@ static bool chooseGLXFBConfig(const _GLFWfbconfig* desired,
|
||||
|
||||
// Create the OpenGL context using legacy API
|
||||
//
|
||||
static GLXContext createLegacyContextGLX(_GLFWwindow* window,
|
||||
static GLXContext createLegacyContextGLX(_GLFWwindow* window UNUSED,
|
||||
GLXFBConfig fbconfig,
|
||||
GLXContext share)
|
||||
{
|
||||
@@ -222,8 +224,11 @@ static GLFWglproc getProcAddressGLX(const char* procname)
|
||||
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);
|
||||
else {
|
||||
GLFWglproc ans = NULL;
|
||||
glfw_dlsym(ans, _glfw.glx.handle, procname);
|
||||
return ans;
|
||||
}
|
||||
}
|
||||
|
||||
static void destroyContextGLX(_GLFWwindow* window)
|
||||
@@ -280,36 +285,21 @@ bool _glfwInitGLX(void)
|
||||
return 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");
|
||||
glfw_dlsym(_glfw.glx.GetFBConfigs, _glfw.glx.handle, "glXGetFBConfigs");
|
||||
glfw_dlsym(_glfw.glx.GetFBConfigAttrib, _glfw.glx.handle, "glXGetFBConfigAttrib");
|
||||
glfw_dlsym(_glfw.glx.GetClientString, _glfw.glx.handle, "glXGetClientString");
|
||||
glfw_dlsym(_glfw.glx.QueryExtension, _glfw.glx.handle, "glXQueryExtension");
|
||||
glfw_dlsym(_glfw.glx.QueryVersion, _glfw.glx.handle, "glXQueryVersion");
|
||||
glfw_dlsym(_glfw.glx.DestroyContext, _glfw.glx.handle, "glXDestroyContext");
|
||||
glfw_dlsym(_glfw.glx.MakeCurrent, _glfw.glx.handle, "glXMakeCurrent");
|
||||
glfw_dlsym(_glfw.glx.SwapBuffers, _glfw.glx.handle, "glXSwapBuffers");
|
||||
glfw_dlsym(_glfw.glx.QueryExtensionsString, _glfw.glx.handle, "glXQueryExtensionsString");
|
||||
glfw_dlsym(_glfw.glx.CreateNewContext, _glfw.glx.handle, "glXCreateNewContext");
|
||||
glfw_dlsym(_glfw.glx.CreateWindow, _glfw.glx.handle, "glXCreateWindow");
|
||||
glfw_dlsym(_glfw.glx.DestroyWindow, _glfw.glx.handle, "glXDestroyWindow");
|
||||
glfw_dlsym(_glfw.glx.GetProcAddress, _glfw.glx.handle, "glXGetProcAddress");
|
||||
glfw_dlsym(_glfw.glx.GetProcAddressARB, _glfw.glx.handle, "glXGetProcAddressARB");
|
||||
glfw_dlsym(_glfw.glx.GetVisualFromFBConfig, _glfw.glx.handle, "glXGetVisualFromFBConfig");
|
||||
|
||||
if (!_glfw.glx.GetFBConfigs ||
|
||||
!_glfw.glx.GetFBConfigAttrib ||
|
||||
@@ -433,7 +423,7 @@ void _glfwTerminateGLX(void)
|
||||
|
||||
#define setAttrib(a, v) \
|
||||
{ \
|
||||
assert((size_t) (index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
|
||||
assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
|
||||
attribs[index++] = a; \
|
||||
attribs[index++] = v; \
|
||||
}
|
||||
@@ -631,8 +621,8 @@ bool _glfwCreateContextGLX(_GLFWwindow* window,
|
||||
|
||||
// Returns the Visual and depth of the chosen GLXFBConfig
|
||||
//
|
||||
bool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
bool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig UNUSED,
|
||||
const _GLFWctxconfig* ctxconfig UNUSED,
|
||||
const _GLFWfbconfig* fbconfig,
|
||||
Visual** visual, int* depth)
|
||||
{
|
||||
|
||||
7
glfw/glx_context.h
vendored
7
glfw/glx_context.h
vendored
@@ -2,7 +2,7 @@
|
||||
// GLFW 3.3 GLX - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2017 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
|
||||
@@ -107,8 +107,8 @@ typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSARBPROC)(Display*,GLXFBConfig,GLX
|
||||
#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
|
||||
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextGLX glx;
|
||||
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryGLX glx;
|
||||
|
||||
|
||||
// GLX-specific per-context data
|
||||
@@ -178,4 +178,3 @@ bool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig,
|
||||
Visual** visual, int* depth);
|
||||
|
||||
|
||||
6
glfw/ibus_glfw.c
vendored
6
glfw/ibus_glfw.c
vendored
@@ -57,7 +57,7 @@ test_env_var(const char *name, const char *val) {
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
MIN(size_t a, size_t b) {
|
||||
GLFW_MIN(size_t a, size_t b) {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ send_text(const char *text, int state) {
|
||||
// Connection handling {{{
|
||||
|
||||
static DBusHandlerResult
|
||||
message_handler(DBusConnection *conn, DBusMessage *msg, void *user_data) {
|
||||
message_handler(DBusConnection *conn UNUSED, DBusMessage *msg, void *user_data) {
|
||||
// To monitor signals from IBUS, use
|
||||
// dbus-monitor --address `ibus address` "type='signal',interface='org.freedesktop.IBus.InputContext'"
|
||||
_GLFWIBUSData *ibus = (_GLFWIBUSData*)user_data;
|
||||
@@ -151,7 +151,7 @@ get_ibus_address_file_name(void) {
|
||||
addr = getenv("IBUS_ADDRESS");
|
||||
int offset = 0;
|
||||
if (addr && addr[0]) {
|
||||
memcpy(ans, addr, MIN(strlen(addr), sizeof(ans)));
|
||||
memcpy(ans, addr, GLFW_MIN(strlen(addr), sizeof(ans)));
|
||||
return ans;
|
||||
}
|
||||
|
||||
|
||||
8
glfw/init.c
vendored
8
glfw/init.c
vendored
@@ -2,7 +2,7 @@
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2018 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
|
||||
@@ -24,6 +24,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// Please use C89 style variable declarations in this file because VS 2010
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
#include "mappings.h"
|
||||
@@ -342,10 +344,6 @@ GLFWAPI void glfwRunMainLoop(GLFWtickcallback callback, void *data)
|
||||
_glfwPlatformRunMainLoop(callback, data);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwRequestTickCallback(void) {
|
||||
_glfwPlatformRequestTickCallback();
|
||||
}
|
||||
|
||||
GLFWAPI void glfwStopMainLoop(void) {
|
||||
_GLFW_REQUIRE_INIT();
|
||||
_glfwPlatformStopMainLoop();
|
||||
|
||||
26
glfw/input.c
vendored
26
glfw/input.c
vendored
@@ -2,7 +2,7 @@
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2019 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
|
||||
@@ -24,6 +24,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// Please use C89 style variable declarations in this file because VS 2010
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@@ -254,7 +256,7 @@ static bool parseMapping(_GLFWmapping* mapping, const char* string)
|
||||
////// GLFW event API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Notifies shared code of a key event
|
||||
// Notifies shared code of a physical key event
|
||||
//
|
||||
void _glfwInputKeyboard(_GLFWwindow* window, int key, int scancode, int action, int mods, const char* text, int state)
|
||||
{
|
||||
@@ -409,7 +411,7 @@ _GLFWjoystick* _glfwAllocJoystick(const char* name,
|
||||
js->present = true;
|
||||
js->name = _glfw_strdup(name);
|
||||
js->axes = calloc(axisCount, sizeof(float));
|
||||
js->buttons = calloc(buttonCount + hatCount * 4, 1);
|
||||
js->buttons = calloc(buttonCount + (size_t) hatCount * 4, 1);
|
||||
js->hats = calloc(hatCount, 1);
|
||||
js->axisCount = axisCount;
|
||||
js->buttonCount = buttonCount;
|
||||
@@ -566,15 +568,17 @@ const char* _glfwGetKeyName(int key)
|
||||
}
|
||||
}
|
||||
|
||||
// Center the cursor in the middle of the content area of the specified window
|
||||
// Center the cursor in the content area of the specified window
|
||||
//
|
||||
void _glfwCenterCursorInContentArea(_GLFWwindow* window)
|
||||
{
|
||||
int width, height;
|
||||
|
||||
_glfwPlatformGetWindowSize(window, &width, &height);
|
||||
_glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW public API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -672,7 +676,9 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
|
||||
window->stickyMouseButtons = value;
|
||||
}
|
||||
else if (mode == GLFW_LOCK_KEY_MODS)
|
||||
{
|
||||
window->lockKeyMods = value ? true : false;
|
||||
}
|
||||
else
|
||||
_glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
|
||||
}
|
||||
@@ -1359,15 +1365,17 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state)
|
||||
const unsigned int bit = e->index & 0xf;
|
||||
if (js->hats[hat] & bit)
|
||||
state->axes[i] = 1.f;
|
||||
else
|
||||
state->axes[i] = -1.f;
|
||||
}
|
||||
else if (e->type == _GLFW_JOYSTICK_BUTTON)
|
||||
state->axes[i] = (float) js->buttons[e->index];
|
||||
state->axes[i] = js->buttons[e->index] * 2.f - 1.f;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string)
|
||||
GLFWAPI void glfwSetClipboardString(GLFWwindow* handle UNUSED, const char* string)
|
||||
{
|
||||
assert(string != NULL);
|
||||
|
||||
@@ -1375,14 +1383,14 @@ GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string)
|
||||
_glfwPlatformSetClipboardString(string);
|
||||
}
|
||||
|
||||
GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle)
|
||||
GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle UNUSED)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
return _glfwPlatformGetClipboardString();
|
||||
}
|
||||
|
||||
#if defined(_GLFW_X11) || defined(_GLFW_WAYLAND)
|
||||
GLFWAPI void glfwSetPrimarySelectionString(GLFWwindow* handle, const char* string)
|
||||
GLFWAPI void glfwSetPrimarySelectionString(GLFWwindow* handle UNUSED, const char* string)
|
||||
{
|
||||
assert(string != NULL);
|
||||
|
||||
@@ -1390,7 +1398,7 @@ GLFWAPI void glfwSetPrimarySelectionString(GLFWwindow* handle, const char* strin
|
||||
_glfwPlatformSetPrimarySelectionString(string);
|
||||
}
|
||||
|
||||
GLFWAPI const char* glfwGetPrimarySelectionString(GLFWwindow* handle)
|
||||
GLFWAPI const char* glfwGetPrimarySelectionString(GLFWwindow* handle UNUSED)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
return _glfwPlatformGetPrimarySelectionString();
|
||||
|
||||
121
glfw/internal.h
vendored
121
glfw/internal.h
vendored
@@ -2,7 +2,7 @@
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2019 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
|
||||
@@ -225,12 +225,32 @@ typedef void (APIENTRY * PFN_vkVoidFunction)(void);
|
||||
|
||||
// Swaps the provided pointers
|
||||
#define _GLFW_SWAP_POINTERS(x, y) \
|
||||
{ \
|
||||
void* t; \
|
||||
do{ \
|
||||
__typeof__(x) t; \
|
||||
t = x; \
|
||||
x = y; \
|
||||
y = t; \
|
||||
}
|
||||
}while(0)
|
||||
|
||||
|
||||
// Suppress some pedantic warnings
|
||||
#ifdef __clang__
|
||||
#define START_ALLOW_CASE_RANGE _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wpedantic\"")
|
||||
#define END_ALLOW_CASE_RANGE _Pragma("clang diagnostic pop")
|
||||
#define ALLOW_UNUSED_RESULT _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wunused-result\"")
|
||||
#define END_ALLOW_UNUSED_RESULT _Pragma("clang diagnostic pop")
|
||||
#else
|
||||
#define START_ALLOW_CASE_RANGE _Pragma("GCC diagnostic ignored \"-Wpedantic\"")
|
||||
#define END_ALLOW_CASE_RANGE _Pragma("GCC diagnostic pop")
|
||||
#define ALLOW_UNUSED_RESULT _Pragma("GCC diagnostic ignored \"-Wunused-result\"")
|
||||
#define END_ALLOW_UNUSED_RESULT _Pragma("GCC diagnostic pop")
|
||||
#endif
|
||||
|
||||
// dlsym that works with -Wpedantic
|
||||
#define glfw_dlsym(dest, handle, name) do {*(void **)&(dest) = _glfw_dlsym(handle, name);}while (0)
|
||||
|
||||
// Mark function arguments as unused
|
||||
#define UNUSED __attribute__ ((unused))
|
||||
|
||||
// Per-thread error structure
|
||||
//
|
||||
@@ -247,12 +267,12 @@ struct _GLFWerror
|
||||
//
|
||||
struct _GLFWinitconfig
|
||||
{
|
||||
bool hatButtons;
|
||||
bool debugKeyboard;
|
||||
bool enableJoysticks;
|
||||
bool hatButtons;
|
||||
bool debugKeyboard;
|
||||
bool enableJoysticks;
|
||||
struct {
|
||||
bool menubar;
|
||||
bool chdir;
|
||||
bool menubar;
|
||||
bool chdir;
|
||||
} ns;
|
||||
};
|
||||
|
||||
@@ -267,18 +287,18 @@ struct _GLFWwndconfig
|
||||
int width;
|
||||
int height;
|
||||
const char* title;
|
||||
bool resizable;
|
||||
bool visible;
|
||||
bool decorated;
|
||||
bool focused;
|
||||
bool autoIconify;
|
||||
bool floating;
|
||||
bool maximized;
|
||||
bool centerCursor;
|
||||
bool focusOnShow;
|
||||
bool scaleToMonitor;
|
||||
bool resizable;
|
||||
bool visible;
|
||||
bool decorated;
|
||||
bool focused;
|
||||
bool autoIconify;
|
||||
bool floating;
|
||||
bool maximized;
|
||||
bool centerCursor;
|
||||
bool focusOnShow;
|
||||
bool scaleToMonitor;
|
||||
struct {
|
||||
bool retina;
|
||||
bool retina;
|
||||
char frameName[256];
|
||||
} ns;
|
||||
struct {
|
||||
@@ -302,15 +322,15 @@ struct _GLFWctxconfig
|
||||
int source;
|
||||
int major;
|
||||
int minor;
|
||||
bool forward;
|
||||
bool debug;
|
||||
bool noerror;
|
||||
bool forward;
|
||||
bool debug;
|
||||
bool noerror;
|
||||
int profile;
|
||||
int robustness;
|
||||
int release;
|
||||
_GLFWwindow* share;
|
||||
struct {
|
||||
bool offline;
|
||||
bool offline;
|
||||
} nsgl;
|
||||
};
|
||||
|
||||
@@ -335,11 +355,11 @@ struct _GLFWfbconfig
|
||||
int accumBlueBits;
|
||||
int accumAlphaBits;
|
||||
int auxBuffers;
|
||||
bool stereo;
|
||||
bool stereo;
|
||||
int samples;
|
||||
bool sRGB;
|
||||
bool doublebuffer;
|
||||
bool transparent;
|
||||
bool sRGB;
|
||||
bool doublebuffer;
|
||||
bool transparent;
|
||||
uintptr_t handle;
|
||||
};
|
||||
|
||||
@@ -350,7 +370,7 @@ struct _GLFWcontext
|
||||
int client;
|
||||
int source;
|
||||
int major, minor, revision;
|
||||
bool forward, debug, noerror;
|
||||
bool forward, debug, noerror;
|
||||
int profile;
|
||||
int robustness;
|
||||
int release;
|
||||
@@ -367,7 +387,7 @@ struct _GLFWcontext
|
||||
_GLFWdestroycontextfun destroy;
|
||||
|
||||
// This is defined in the context API's context.h
|
||||
_GLFW_PLATFORM_CONTEXT_STATE;
|
||||
_GLFW_PLATFORM_CONTEXT_STATE
|
||||
// This is defined in egl_context.h
|
||||
_GLFW_EGL_CONTEXT_STATE;
|
||||
// This is defined in osmesa_context.h
|
||||
@@ -381,12 +401,12 @@ struct _GLFWwindow
|
||||
struct _GLFWwindow* next;
|
||||
|
||||
// Window settings and state
|
||||
bool resizable;
|
||||
bool decorated;
|
||||
bool autoIconify;
|
||||
bool floating;
|
||||
bool focusOnShow;
|
||||
bool shouldClose;
|
||||
bool resizable;
|
||||
bool decorated;
|
||||
bool autoIconify;
|
||||
bool floating;
|
||||
bool focusOnShow;
|
||||
bool shouldClose;
|
||||
void* userPointer;
|
||||
GLFWid id;
|
||||
GLFWvidmode videoMode;
|
||||
@@ -397,9 +417,9 @@ struct _GLFWwindow
|
||||
int maxwidth, maxheight;
|
||||
int numer, denom;
|
||||
|
||||
bool stickyKeys;
|
||||
bool stickyMouseButtons;
|
||||
bool lockKeyMods;
|
||||
bool stickyKeys;
|
||||
bool stickyMouseButtons;
|
||||
bool lockKeyMods;
|
||||
int cursorMode;
|
||||
char mouseButtons[GLFW_MOUSE_BUTTON_LAST + 1];
|
||||
char keys[GLFW_KEY_LAST + 1];
|
||||
@@ -490,7 +510,7 @@ struct _GLFWmapping
|
||||
//
|
||||
struct _GLFWjoystick
|
||||
{
|
||||
bool present;
|
||||
bool present;
|
||||
float* axes;
|
||||
int axisCount;
|
||||
unsigned char* buttons;
|
||||
@@ -526,7 +546,7 @@ struct _GLFWmutex
|
||||
//
|
||||
struct _GLFWlibrary
|
||||
{
|
||||
bool initialized;
|
||||
bool initialized;
|
||||
|
||||
struct {
|
||||
_GLFWinitconfig init;
|
||||
@@ -559,23 +579,23 @@ struct _GLFWlibrary
|
||||
} timer;
|
||||
|
||||
struct {
|
||||
bool available;
|
||||
bool available;
|
||||
void* handle;
|
||||
char* extensions[2];
|
||||
#if !defined(_GLFW_VULKAN_STATIC)
|
||||
PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties;
|
||||
PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
|
||||
#endif
|
||||
bool KHR_surface;
|
||||
bool KHR_surface;
|
||||
#if defined(_GLFW_WIN32)
|
||||
bool KHR_win32_surface;
|
||||
bool KHR_win32_surface;
|
||||
#elif defined(_GLFW_COCOA)
|
||||
bool MVK_macos_surface;
|
||||
bool MVK_macos_surface;
|
||||
#elif defined(_GLFW_X11)
|
||||
bool KHR_xlib_surface;
|
||||
bool KHR_xcb_surface;
|
||||
bool KHR_xlib_surface;
|
||||
bool KHR_xcb_surface;
|
||||
#elif defined(_GLFW_WAYLAND)
|
||||
bool KHR_wayland_surface;
|
||||
bool KHR_wayland_surface;
|
||||
#endif
|
||||
} vk;
|
||||
|
||||
@@ -587,9 +607,9 @@ struct _GLFWlibrary
|
||||
// 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;
|
||||
_GLFW_PLATFORM_LIBRARY_CONTEXT_STATE
|
||||
// This is defined in the platform's joystick.h
|
||||
_GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE;
|
||||
_GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE
|
||||
// This is defined in egl_context.h
|
||||
_GLFW_EGL_LIBRARY_CONTEXT_STATE;
|
||||
// This is defined in osmesa_context.h
|
||||
@@ -802,7 +822,6 @@ const char* _glfwGetVulkanResultString(VkResult result);
|
||||
_GLFWwindow* _glfwFocusedWindow(void);
|
||||
_GLFWwindow* _glfwWindowForId(GLFWid id);
|
||||
void _glfwPlatformRunMainLoop(GLFWtickcallback, void*);
|
||||
void _glfwPlatformRequestTickCallback(void);
|
||||
void _glfwPlatformStopMainLoop(void);
|
||||
unsigned long long _glfwPlatformAddTimer(double interval, bool repeats, GLFWuserdatafun callback, void *callback_data, GLFWuserdatafun free_callback);
|
||||
void _glfwPlatformUpdateTimer(unsigned long long timer_id, double interval, bool enabled);
|
||||
|
||||
59
glfw/linux_joystick.c
vendored
59
glfw/linux_joystick.c
vendored
@@ -2,7 +2,7 @@
|
||||
// GLFW 3.3 Linux - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2017 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
|
||||
@@ -24,6 +24,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@@ -104,9 +106,7 @@ static void handleAbsEvent(_GLFWjoystick* js, int code, int value)
|
||||
//
|
||||
static void pollAbsState(_GLFWjoystick* js)
|
||||
{
|
||||
int code;
|
||||
|
||||
for (code = 0; code < ABS_CNT; code++)
|
||||
for (int code = 0; code < ABS_CNT; code++)
|
||||
{
|
||||
if (js->linjs.absMap[code] < 0)
|
||||
continue;
|
||||
@@ -126,18 +126,7 @@ static void pollAbsState(_GLFWjoystick* js)
|
||||
//
|
||||
static bool 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++)
|
||||
for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
|
||||
{
|
||||
if (!_glfw.joysticks[jid].present)
|
||||
continue;
|
||||
@@ -145,10 +134,16 @@ static bool openJoystickDevice(const char* path)
|
||||
return false;
|
||||
}
|
||||
|
||||
_GLFWjoystickLinux linjs = {0};
|
||||
linjs.fd = open(path, O_RDONLY | O_NONBLOCK);
|
||||
if (linjs.fd == -1)
|
||||
return false;
|
||||
|
||||
char evBits[(EV_CNT + 7) / 8] = {0};
|
||||
char keyBits[(KEY_CNT + 7) / 8] = {0};
|
||||
char absBits[(ABS_CNT + 7) / 8] = {0};
|
||||
struct input_id id;
|
||||
|
||||
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 ||
|
||||
@@ -168,9 +163,13 @@ static bool openJoystickDevice(const char* path)
|
||||
return false;
|
||||
}
|
||||
|
||||
char name[256] = "";
|
||||
|
||||
if (ioctl(linjs.fd, EVIOCGNAME(sizeof(name)), name) < 0)
|
||||
strncpy(name, "Unknown", sizeof(name));
|
||||
|
||||
char guid[33] = "";
|
||||
|
||||
// Generate a joystick GUID that matches the SDL 2.0.5+ one
|
||||
if (id.vendor && id.product && id.version)
|
||||
{
|
||||
@@ -189,7 +188,9 @@ static bool openJoystickDevice(const char* path)
|
||||
name[8], name[9], name[10]);
|
||||
}
|
||||
|
||||
for (code = BTN_MISC; code < KEY_CNT; code++)
|
||||
int axisCount = 0, buttonCount = 0, hatCount = 0;
|
||||
|
||||
for (int code = BTN_MISC; code < KEY_CNT; code++)
|
||||
{
|
||||
if (!isBitSet(code, keyBits))
|
||||
continue;
|
||||
@@ -198,7 +199,7 @@ static bool openJoystickDevice(const char* path)
|
||||
buttonCount++;
|
||||
}
|
||||
|
||||
for (code = 0; code < ABS_CNT; code++)
|
||||
for (int code = 0; code < ABS_CNT; code++)
|
||||
{
|
||||
linjs.absMap[code] = -1;
|
||||
if (!isBitSet(code, absBits))
|
||||
@@ -221,7 +222,7 @@ static bool openJoystickDevice(const char* path)
|
||||
}
|
||||
}
|
||||
|
||||
js = _glfwAllocJoystick(name, guid, axisCount, buttonCount, hatCount);
|
||||
_GLFWjoystick* js = _glfwAllocJoystick(name, guid, axisCount, buttonCount, hatCount);
|
||||
if (!js)
|
||||
{
|
||||
close(linjs.fd);
|
||||
@@ -266,8 +267,6 @@ static int compareJoysticks(const void* fp, const void* sp)
|
||||
//
|
||||
bool _glfwInitJoysticksLinux(void)
|
||||
{
|
||||
DIR* dir;
|
||||
int count = 0;
|
||||
const char* dirname = "/dev/input";
|
||||
|
||||
_glfw.linjs.inotify = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
||||
@@ -289,7 +288,9 @@ bool _glfwInitJoysticksLinux(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
dir = opendir(dirname);
|
||||
int count = 0;
|
||||
|
||||
DIR* dir = opendir(dirname);
|
||||
if (dir)
|
||||
{
|
||||
struct dirent* entry;
|
||||
@@ -314,7 +315,7 @@ bool _glfwInitJoysticksLinux(void)
|
||||
|
||||
// Continue with no joysticks if enumeration fails
|
||||
|
||||
qsort(_glfw.joysticks, count, sizeof(_GLFWjoystick), compareJoysticks);
|
||||
qsort(_glfw.joysticks, count, sizeof(_glfw.joysticks[0]), compareJoysticks);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -344,12 +345,12 @@ void _glfwTerminateJoysticksLinux(void)
|
||||
|
||||
void _glfwDetectJoystickConnectionLinux(void)
|
||||
{
|
||||
ssize_t offset = 0;
|
||||
char buffer[16384];
|
||||
|
||||
if (_glfw.linjs.inotify <= 0)
|
||||
return;
|
||||
|
||||
ssize_t offset = 0;
|
||||
char buffer[16384];
|
||||
const ssize_t size = read(_glfw.linjs.inotify, buffer, sizeof(buffer));
|
||||
|
||||
while (size > offset)
|
||||
@@ -369,9 +370,7 @@ void _glfwDetectJoystickConnectionLinux(void)
|
||||
openJoystickDevice(path);
|
||||
else if (e->mask & IN_DELETE)
|
||||
{
|
||||
int jid;
|
||||
|
||||
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
|
||||
for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
|
||||
{
|
||||
if (strcmp(_glfw.joysticks[jid].linjs.path, path) == 0)
|
||||
{
|
||||
@@ -388,7 +387,7 @@ void _glfwDetectJoystickConnectionLinux(void)
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode)
|
||||
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode UNUSED)
|
||||
{
|
||||
// Read all queued events (non-blocking)
|
||||
for (;;)
|
||||
@@ -428,6 +427,6 @@ int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode)
|
||||
return js->present;
|
||||
}
|
||||
|
||||
void _glfwPlatformUpdateGamepadGUID(char* guid)
|
||||
void _glfwPlatformUpdateGamepadGUID(char* guid UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
3
glfw/linux_joystick.h
vendored
3
glfw/linux_joystick.h
vendored
@@ -29,7 +29,7 @@
|
||||
#include <regex.h>
|
||||
|
||||
#define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickLinux linjs
|
||||
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE _GLFWlibraryLinux linjs
|
||||
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE _GLFWlibraryLinux linjs;
|
||||
|
||||
#define _GLFW_PLATFORM_MAPPING_NAME "Linux"
|
||||
|
||||
@@ -59,4 +59,3 @@ typedef struct _GLFWlibraryLinux
|
||||
bool _glfwInitJoysticksLinux(void);
|
||||
void _glfwTerminateJoysticksLinux(void);
|
||||
void _glfwDetectJoystickConnectionLinux(void);
|
||||
|
||||
|
||||
3
glfw/linux_notify.c
vendored
3
glfw/linux_notify.c
vendored
@@ -43,8 +43,7 @@ notification_created(DBusMessage *msg, const char* errmsg, void *data) {
|
||||
}
|
||||
|
||||
static DBusHandlerResult
|
||||
message_handler(DBusConnection *conn, DBusMessage *msg, void *user_data) {
|
||||
(void)(user_data);
|
||||
message_handler(DBusConnection *conn UNUSED, DBusMessage *msg, void *user_data UNUSED) {
|
||||
/* printf("session_bus message_handler invoked interface: %s member: %s\n", dbus_message_get_interface(msg), dbus_message_get_member(msg)); */
|
||||
if (dbus_message_is_signal(msg, NOTIFICATIONS_IFACE, "ActionInvoked")) {
|
||||
uint32_t notification_id;
|
||||
|
||||
13
glfw/main_loop.h
vendored
13
glfw/main_loop.h
vendored
@@ -14,8 +14,6 @@
|
||||
|
||||
static bool keep_going = false;
|
||||
|
||||
void _glfwPlatformRequestTickCallback() {
|
||||
}
|
||||
|
||||
void _glfwPlatformStopMainLoop(void) {
|
||||
if (keep_going) {
|
||||
@@ -25,12 +23,17 @@ void _glfwPlatformStopMainLoop(void) {
|
||||
}
|
||||
|
||||
void _glfwPlatformRunMainLoop(GLFWtickcallback tick_callback, void* data) {
|
||||
keep_going = true;
|
||||
keep_going = 1;
|
||||
EventLoopData *eld = &_glfw.GLFW_LOOP_BACKEND.eventLoopData;
|
||||
while(keep_going) {
|
||||
_glfwPlatformWaitEvents();
|
||||
EVDBG("loop tick");
|
||||
tick_callback(data);
|
||||
EVDBG("--------- loop tick, wakeups_happened: %d ----------", eld->wakeup_data_read);
|
||||
if (eld->wakeup_data_read) {
|
||||
eld->wakeup_data_read = false;
|
||||
tick_callback(data);
|
||||
}
|
||||
}
|
||||
EVDBG("main loop exiting");
|
||||
}
|
||||
|
||||
unsigned long long _glfwPlatformAddTimer(double interval, bool repeats, GLFWuserdatafreefun callback, void *callback_data, GLFWuserdatafreefun free_callback) {
|
||||
|
||||
2
glfw/mappings.h
vendored
2
glfw/mappings.h
vendored
@@ -1,7 +1,7 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2018 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
|
||||
|
||||
19
glfw/monitor.c
vendored
19
glfw/monitor.c
vendored
@@ -2,7 +2,7 @@
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2019 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
|
||||
@@ -24,6 +24,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// Please use C89 style variable declarations in this file because VS 2010
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@@ -72,7 +74,7 @@ static bool refreshVideoModes(_GLFWmonitor* monitor)
|
||||
if (!modes)
|
||||
return false;
|
||||
|
||||
qsort(modes, modeCount, sizeof(GLFWvidmode), compareVideoModes);
|
||||
qsort(modes, modeCount, sizeof(modes[0]), compareVideoModes);
|
||||
|
||||
free(monitor->modes);
|
||||
monitor->modes = modes;
|
||||
@@ -100,7 +102,7 @@ void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement)
|
||||
{
|
||||
memmove(_glfw.monitors + 1,
|
||||
_glfw.monitors,
|
||||
(_glfw.monitorCount - 1) * sizeof(_GLFWmonitor*));
|
||||
((size_t) _glfw.monitorCount - 1) * sizeof(_GLFWmonitor*));
|
||||
_glfw.monitors[0] = monitor;
|
||||
}
|
||||
else
|
||||
@@ -327,7 +329,9 @@ GLFWAPI void glfwGetMonitorPos(GLFWmonitor* handle, int* xpos, int* ypos)
|
||||
_glfwPlatformGetMonitorPos(monitor, xpos, ypos);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwGetMonitorWorkarea(GLFWmonitor* handle, int* xpos, int* ypos, int* width, int* height)
|
||||
GLFWAPI void glfwGetMonitorWorkarea(GLFWmonitor* handle,
|
||||
int* xpos, int* ypos,
|
||||
int* width, int* height)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
@@ -448,7 +452,7 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
|
||||
GLFWgammaramp ramp;
|
||||
const GLFWgammaramp* original;
|
||||
assert(handle != NULL);
|
||||
assert(gamma >= 0.f);
|
||||
assert(gamma > 0.f);
|
||||
assert(gamma <= FLT_MAX);
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
@@ -458,6 +462,7 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
|
||||
_glfwInputError(GLFW_INVALID_VALUE, "Invalid gamma value %f", gamma);
|
||||
return;
|
||||
}
|
||||
|
||||
original = glfwGetGammaRamp(handle);
|
||||
if (!original)
|
||||
return;
|
||||
@@ -472,10 +477,8 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
|
||||
value = i / (float) (original->size - 1);
|
||||
// Apply gamma curve
|
||||
value = powf(value, 1.f / gamma) * 65535.f + 0.5f;
|
||||
|
||||
// Clamp to value range
|
||||
if (value > 65535.f)
|
||||
value = 65535.f;
|
||||
value = fminf(value, 65535.f);
|
||||
|
||||
values[i] = (unsigned short) value;
|
||||
}
|
||||
|
||||
7
glfw/nsgl_context.h
vendored
7
glfw/nsgl_context.h
vendored
@@ -1,7 +1,7 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 macOS - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2009-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2009-2019 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
|
||||
@@ -24,8 +24,8 @@
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextNSGL nsgl
|
||||
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryNSGL nsgl
|
||||
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextNSGL nsgl;
|
||||
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryNSGL nsgl;
|
||||
|
||||
|
||||
// NSGL-specific per-context data
|
||||
@@ -53,4 +53,3 @@ bool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig);
|
||||
void _glfwDestroyContextNSGL(_GLFWwindow* window);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 macOS - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2009-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2009-2019 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
|
||||
@@ -23,6 +23,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@@ -43,15 +45,14 @@ static void swapBuffersNSGL(_GLFWwindow* window)
|
||||
[window->context.nsgl.object flushBuffer];
|
||||
}
|
||||
|
||||
static void swapIntervalNSGL(int interval)
|
||||
static void swapIntervalNSGL(int interval UNUSED)
|
||||
{
|
||||
// As of Mojave this does not work so we use CVDisplayLink instead
|
||||
(void)(interval);
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"NSGL: Swap intervals do not work on macOS");
|
||||
}
|
||||
|
||||
static int extensionSupportedNSGL(const char* extension)
|
||||
static int extensionSupportedNSGL(const char* extension UNUSED)
|
||||
{
|
||||
// There are no NSGL extensions
|
||||
return false;
|
||||
@@ -63,8 +64,9 @@ static GLFWglproc getProcAddressNSGL(const char* procname)
|
||||
procname,
|
||||
kCFStringEncodingASCII);
|
||||
|
||||
GLFWglproc symbol = CFBundleGetFunctionPointerForName(_glfw.nsgl.framework,
|
||||
symbolName);
|
||||
GLFWglproc symbol;
|
||||
*(void **) &symbol = CFBundleGetFunctionPointerForName(_glfw.nsgl.framework,
|
||||
symbolName);
|
||||
|
||||
CFRelease(symbolName);
|
||||
|
||||
@@ -131,7 +133,6 @@ bool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
"NSGL: The targeted version of macOS does not support OpenGL 3.0 or 3.1 but may support 3.2 and above");
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Context robustness modes (GL_KHR_robustness) are not yet supported by
|
||||
@@ -288,7 +289,8 @@ bool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
if (fbconfig->transparent)
|
||||
{
|
||||
GLint opaque = 0;
|
||||
[window->context.nsgl.object setValues:&opaque forParameter:NSOpenGLContextParameterSurfaceOpacity];
|
||||
[window->context.nsgl.object setValues:&opaque
|
||||
forParameter:NSOpenGLContextParameterSurfaceOpacity];
|
||||
}
|
||||
|
||||
if (window->ns.retina)
|
||||
|
||||
4
glfw/null_init.c
vendored
4
glfw/null_init.c
vendored
@@ -2,7 +2,7 @@
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2016-2017 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
|
||||
@@ -24,6 +24,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
4
glfw/null_joystick.c
vendored
4
glfw/null_joystick.c
vendored
@@ -1,7 +1,7 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2016-2017 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
|
||||
@@ -23,6 +23,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
5
glfw/null_joystick.h
vendored
5
glfw/null_joystick.h
vendored
@@ -1,7 +1,7 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2017 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
|
||||
@@ -25,7 +25,6 @@
|
||||
//========================================================================
|
||||
|
||||
#define _GLFW_PLATFORM_JOYSTICK_STATE int nulljs
|
||||
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE int nulljs
|
||||
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE int nulljs;
|
||||
|
||||
#define _GLFW_PLATFORM_MAPPING_NAME ""
|
||||
|
||||
|
||||
9
glfw/null_monitor.c
vendored
9
glfw/null_monitor.c
vendored
@@ -2,7 +2,7 @@
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2016-2019 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
|
||||
@@ -24,6 +24,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@@ -49,7 +51,9 @@ void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
|
||||
*yscale = 1.f;
|
||||
}
|
||||
|
||||
void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int *width, int *height)
|
||||
void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor,
|
||||
int* xpos, int* ypos,
|
||||
int* width, int* height)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -70,3 +74,4 @@ bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
2
glfw/null_platform.h
vendored
2
glfw/null_platform.h
vendored
@@ -2,7 +2,7 @@
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2016-2017 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
|
||||
|
||||
5
glfw/null_window.c
vendored
5
glfw/null_window.c
vendored
@@ -2,7 +2,7 @@
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2016-2019 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
|
||||
@@ -24,6 +24,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@@ -333,3 +335,4 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
|
||||
// This seems like the most appropriate error to return here
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
||||
|
||||
35
glfw/osmesa_context.c
vendored
35
glfw/osmesa_context.c
vendored
@@ -2,7 +2,7 @@
|
||||
// GLFW 3.3 OSMesa - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2016-2017 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
|
||||
@@ -24,6 +24,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// Please use C89 style variable declarations in this file because VS 2010
|
||||
//========================================================================
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -47,7 +49,7 @@ static void makeContextCurrentOSMesa(_GLFWwindow* window)
|
||||
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.buffer = calloc(4, (size_t) width * height);
|
||||
window->context.osmesa.width = width;
|
||||
window->context.osmesa.height = height;
|
||||
}
|
||||
@@ -87,17 +89,17 @@ static void destroyContextOSMesa(_GLFWwindow* window)
|
||||
}
|
||||
}
|
||||
|
||||
static void swapBuffersOSMesa(_GLFWwindow* window)
|
||||
static void swapBuffersOSMesa(_GLFWwindow* window UNUSED)
|
||||
{
|
||||
// No double buffering on OSMesa
|
||||
}
|
||||
|
||||
static void swapIntervalOSMesa(int interval)
|
||||
static void swapIntervalOSMesa(int interval UNUSED)
|
||||
{
|
||||
// No swap interval on OSMesa
|
||||
}
|
||||
|
||||
static int extensionSupportedOSMesa(const char* extension)
|
||||
static int extensionSupportedOSMesa(const char* extension UNUSED)
|
||||
{
|
||||
// OSMesa does not have extensions
|
||||
return false;
|
||||
@@ -145,20 +147,13 @@ bool _glfwInitOSMesa(void)
|
||||
return 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");
|
||||
glfw_dlsym(_glfw.osmesa.CreateContextExt, _glfw.osmesa.handle, "OSMesaCreateContextExt");
|
||||
glfw_dlsym(_glfw.osmesa.CreateContextAttribs, _glfw.osmesa.handle, "OSMesaCreateContextAttribs");
|
||||
glfw_dlsym(_glfw.osmesa.DestroyContext, _glfw.osmesa.handle, "OSMesaDestroyContext");
|
||||
glfw_dlsym(_glfw.osmesa.MakeCurrent, _glfw.osmesa.handle, "OSMesaMakeCurrent");
|
||||
glfw_dlsym(_glfw.osmesa.GetColorBuffer, _glfw.osmesa.handle, "OSMesaGetColorBuffer");
|
||||
glfw_dlsym(_glfw.osmesa.GetDepthBuffer, _glfw.osmesa.handle, "OSMesaGetDepthBuffer");
|
||||
glfw_dlsym(_glfw.osmesa.GetProcAddress, _glfw.osmesa.handle, "OSMesaGetProcAddress");
|
||||
|
||||
if (!_glfw.osmesa.CreateContextExt ||
|
||||
!_glfw.osmesa.DestroyContext ||
|
||||
@@ -188,7 +183,7 @@ void _glfwTerminateOSMesa(void)
|
||||
|
||||
#define setAttrib(a, v) \
|
||||
{ \
|
||||
assert((size_t) (index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
|
||||
assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
|
||||
attribs[index++] = a; \
|
||||
attribs[index++] = v; \
|
||||
}
|
||||
|
||||
2
glfw/osmesa_context.h
vendored
2
glfw/osmesa_context.h
vendored
@@ -2,7 +2,7 @@
|
||||
// GLFW 3.3 OSMesa - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2016-2017 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
|
||||
|
||||
4
glfw/posix_thread.c
vendored
4
glfw/posix_thread.c
vendored
@@ -2,7 +2,7 @@
|
||||
// GLFW 3.3 POSIX - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2017 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
|
||||
@@ -24,6 +24,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
2
glfw/posix_thread.h
vendored
2
glfw/posix_thread.h
vendored
@@ -2,7 +2,7 @@
|
||||
// GLFW 3.3 POSIX - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2017 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
|
||||
|
||||
4
glfw/posix_time.c
vendored
4
glfw/posix_time.c
vendored
@@ -2,7 +2,7 @@
|
||||
// GLFW 3.3 POSIX - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2017 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
|
||||
@@ -24,6 +24,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
2
glfw/posix_time.h
vendored
2
glfw/posix_time.h
vendored
@@ -2,7 +2,7 @@
|
||||
// GLFW 3.3 POSIX - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2017 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
|
||||
|
||||
8
glfw/vulkan.c
vendored
8
glfw/vulkan.c
vendored
@@ -2,7 +2,7 @@
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2018 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
|
||||
@@ -24,6 +24,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// Please use C89 style variable declarations in this file because VS 2010
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@@ -66,7 +68,7 @@ bool _glfwInitVulkan(int mode)
|
||||
return false;
|
||||
}
|
||||
|
||||
_glfw.vk.GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)
|
||||
*(void **) &_glfw.vk.GetInstanceProcAddr =
|
||||
_glfw_dlsym(_glfw.vk.handle, "vkGetInstanceProcAddr");
|
||||
if (!_glfw.vk.GetInstanceProcAddr)
|
||||
{
|
||||
@@ -260,7 +262,7 @@ GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance,
|
||||
}
|
||||
#else
|
||||
if (!proc)
|
||||
proc = (GLFWvkproc) _glfw_dlsym(_glfw.vk.handle, procname);
|
||||
*(void **) &proc = _glfw_dlsym(_glfw.vk.handle, procname);
|
||||
#endif
|
||||
|
||||
return proc;
|
||||
|
||||
743
glfw/wgl_context.c
vendored
743
glfw/wgl_context.c
vendored
@@ -1,743 +0,0 @@
|
||||
//========================================================================
|
||||
// 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 = true;
|
||||
if (getPixelFormatAttrib(window, n, WGL_DOUBLE_BUFFER_ARB))
|
||||
u->doublebuffer = 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 = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_glfw.wgl.EXT_colorspace)
|
||||
{
|
||||
if (getPixelFormatAttrib(window, n, WGL_COLORSPACE_EXT) ==
|
||||
WGL_COLORSPACE_SRGB_EXT)
|
||||
{
|
||||
u->sRGB = 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 = true;
|
||||
if (pfd.dwFlags & PFD_DOUBLEBUFFER)
|
||||
u->doublebuffer = 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)
|
||||
{
|
||||
if (!window->monitor)
|
||||
{
|
||||
if (IsWindowsVistaOrGreater())
|
||||
{
|
||||
BOOL enabled;
|
||||
|
||||
// HACK: Use DwmFlush when desktop composition is enabled
|
||||
if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled)
|
||||
{
|
||||
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;
|
||||
|
||||
if (!window->monitor)
|
||||
{
|
||||
if (IsWindowsVistaOrGreater())
|
||||
{
|
||||
BOOL enabled;
|
||||
|
||||
// HACK: Disable WGL swap interval when desktop composition is enabled to
|
||||
// avoid interfering with DWM vsync
|
||||
if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled)
|
||||
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 true;
|
||||
}
|
||||
}
|
||||
|
||||
if (_glfw.wgl.GetExtensionsStringARB)
|
||||
{
|
||||
extensions = _glfw.wgl.GetExtensionsStringARB(wglGetCurrentDC());
|
||||
if (extensions)
|
||||
{
|
||||
if (_glfwStringInExtensionString(extension, extensions))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return 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
|
||||
//
|
||||
bool _glfwInitWGL(void)
|
||||
{
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
HGLRC prc, rc;
|
||||
HDC pdc, dc;
|
||||
|
||||
if (_glfw.wgl.instance)
|
||||
return true;
|
||||
|
||||
_glfw.wgl.instance = LoadLibraryA("opengl32.dll");
|
||||
if (!_glfw.wgl.instance)
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to load opengl32.dll");
|
||||
return 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 false;
|
||||
}
|
||||
|
||||
rc = wglCreateContext(dc);
|
||||
if (!rc)
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to create dummy context");
|
||||
return 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 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 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
|
||||
//
|
||||
bool _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 false;
|
||||
}
|
||||
|
||||
pixelFormat = choosePixelFormat(window, ctxconfig, fbconfig);
|
||||
if (!pixelFormat)
|
||||
return 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 false;
|
||||
}
|
||||
|
||||
if (!SetPixelFormat(window->context.wgl.dc, pixelFormat, &pfd))
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to set selected pixel format");
|
||||
return 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 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 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 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, 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 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 false;
|
||||
}
|
||||
|
||||
if (share)
|
||||
{
|
||||
if (!wglShareLists(share, window->context.wgl.handle))
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to enable sharing with specified OpenGL context");
|
||||
return 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 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
159
glfw/wgl_context.h
vendored
@@ -1,159 +0,0 @@
|
||||
//========================================================================
|
||||
// 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;
|
||||
bool EXT_swap_control;
|
||||
bool EXT_colorspace;
|
||||
bool ARB_multisample;
|
||||
bool ARB_framebuffer_sRGB;
|
||||
bool EXT_framebuffer_sRGB;
|
||||
bool ARB_pixel_format;
|
||||
bool ARB_create_context;
|
||||
bool ARB_create_context_profile;
|
||||
bool EXT_create_context_es2_profile;
|
||||
bool ARB_create_context_robustness;
|
||||
bool ARB_create_context_no_error;
|
||||
bool ARB_context_flush_control;
|
||||
|
||||
} _GLFWlibraryWGL;
|
||||
|
||||
|
||||
bool _glfwInitWGL(void);
|
||||
void _glfwTerminateWGL(void);
|
||||
bool _glfwCreateContextWGL(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig);
|
||||
|
||||
8
glfw/window.c
vendored
8
glfw/window.c
vendored
@@ -2,7 +2,7 @@
|
||||
// GLFW 3.3 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2019 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
|
||||
@@ -25,6 +25,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// Please use C89 style variable declarations in this file because VS 2010
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@@ -82,7 +84,7 @@ _GLFWwindow* _glfwFocusedWindow() {
|
||||
_GLFWwindow* _glfwWindowForId(GLFWid id) {
|
||||
_GLFWwindow *w = _glfw.windowListHead;
|
||||
while (w) {
|
||||
if (w->id == _glfw.focusedWindowId) return w;
|
||||
if (w->id == id) return w;
|
||||
w = w->next;
|
||||
}
|
||||
return NULL;
|
||||
@@ -181,7 +183,6 @@ void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor)
|
||||
window->monitor = monitor;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW public API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -1165,6 +1166,5 @@ GLFWAPI GLFWwindowcontentscalefun glfwSetWindowContentScaleCallback(GLFWwindow*
|
||||
GLFWAPI void glfwPostEmptyEvent(void)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
_glfwPlatformPostEmptyEvent();
|
||||
}
|
||||
|
||||
153
glfw/wl_init.c
vendored
153
glfw/wl_init.c
vendored
@@ -23,6 +23,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include "internal.h"
|
||||
@@ -31,7 +33,6 @@
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <linux/input.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -39,6 +40,16 @@
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <wayland-client.h>
|
||||
// Needed for the BTN_* defines
|
||||
#ifdef __has_include
|
||||
#if __has_include(<linux/input.h>)
|
||||
#include <linux/input.h>
|
||||
#elif __has_include(<dev/evdev/input.h>)
|
||||
#include <dev/evdev/input.h>
|
||||
#endif
|
||||
#else
|
||||
#include <linux/input.h>
|
||||
#endif
|
||||
|
||||
|
||||
static inline int min(int n1, int n2)
|
||||
@@ -46,7 +57,8 @@ static inline int min(int n1, int n2)
|
||||
return n1 < n2 ? n1 : n2;
|
||||
}
|
||||
|
||||
static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface, int* which)
|
||||
static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface,
|
||||
int* which)
|
||||
{
|
||||
int focus;
|
||||
_GLFWwindow* window = _glfw.windowListHead;
|
||||
@@ -79,12 +91,12 @@ static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface,
|
||||
return window;
|
||||
}
|
||||
|
||||
static void pointerHandleEnter(void* data,
|
||||
struct wl_pointer* pointer,
|
||||
static void pointerHandleEnter(void* data UNUSED,
|
||||
struct wl_pointer* pointer UNUSED,
|
||||
uint32_t serial,
|
||||
struct wl_surface* surface,
|
||||
wl_fixed_t sx,
|
||||
wl_fixed_t sy)
|
||||
wl_fixed_t sx UNUSED,
|
||||
wl_fixed_t sy UNUSED)
|
||||
{
|
||||
// Happens in the case we just destroyed the surface.
|
||||
if (!surface)
|
||||
@@ -109,10 +121,10 @@ static void pointerHandleEnter(void* data,
|
||||
_glfwInputCursorEnter(window, true);
|
||||
}
|
||||
|
||||
static void pointerHandleLeave(void* data,
|
||||
struct wl_pointer* pointer,
|
||||
static void pointerHandleLeave(void* data UNUSED,
|
||||
struct wl_pointer* pointer UNUSED,
|
||||
uint32_t serial,
|
||||
struct wl_surface* surface)
|
||||
struct wl_surface* surface UNUSED)
|
||||
{
|
||||
_GLFWwindow* window = _glfw.wl.pointerFocus;
|
||||
|
||||
@@ -154,9 +166,9 @@ static void setCursor(GLFWCursorShape shape)
|
||||
wl_surface_commit(surface);
|
||||
}
|
||||
|
||||
static void pointerHandleMotion(void* data,
|
||||
struct wl_pointer* pointer,
|
||||
uint32_t time,
|
||||
static void pointerHandleMotion(void* data UNUSED,
|
||||
struct wl_pointer* pointer UNUSED,
|
||||
uint32_t time UNUSED,
|
||||
wl_fixed_t sx,
|
||||
wl_fixed_t sy)
|
||||
{
|
||||
@@ -174,7 +186,8 @@ static void pointerHandleMotion(void* data,
|
||||
switch (window->wl.decorations.focus)
|
||||
{
|
||||
case mainWindow:
|
||||
_glfwInputCursorPos(window, window->wl.cursorPosX, window->wl.cursorPosY);
|
||||
_glfwInputCursorPos(window,
|
||||
window->wl.cursorPosX, window->wl.cursorPosY);
|
||||
return;
|
||||
case topDecoration:
|
||||
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
|
||||
@@ -208,16 +221,15 @@ static void pointerHandleMotion(void* data,
|
||||
setCursor(cursorShape);
|
||||
}
|
||||
|
||||
static void pointerHandleButton(void* data,
|
||||
struct wl_pointer* pointer,
|
||||
static void pointerHandleButton(void* data UNUSED,
|
||||
struct wl_pointer* pointer UNUSED,
|
||||
uint32_t serial,
|
||||
uint32_t time,
|
||||
uint32_t time UNUSED,
|
||||
uint32_t button,
|
||||
uint32_t state)
|
||||
{
|
||||
_GLFWwindow* window = _glfw.wl.pointerFocus;
|
||||
int glfwButton;
|
||||
|
||||
uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE;
|
||||
|
||||
if (!window)
|
||||
@@ -296,9 +308,9 @@ static void pointerHandleButton(void* data,
|
||||
_glfw.wl.xkb.states.modifiers);
|
||||
}
|
||||
|
||||
static void pointerHandleAxis(void* data,
|
||||
struct wl_pointer* pointer,
|
||||
uint32_t time,
|
||||
static void pointerHandleAxis(void* data UNUSED,
|
||||
struct wl_pointer* pointer UNUSED,
|
||||
uint32_t time UNUSED,
|
||||
uint32_t axis,
|
||||
wl_fixed_t value)
|
||||
{
|
||||
@@ -326,8 +338,8 @@ static const struct wl_pointer_listener pointerListener = {
|
||||
pointerHandleAxis,
|
||||
};
|
||||
|
||||
static void keyboardHandleKeymap(void* data,
|
||||
struct wl_keyboard* keyboard,
|
||||
static void keyboardHandleKeymap(void* data UNUSED,
|
||||
struct wl_keyboard* keyboard UNUSED,
|
||||
uint32_t format,
|
||||
int fd,
|
||||
uint32_t size)
|
||||
@@ -351,11 +363,11 @@ static void keyboardHandleKeymap(void* data,
|
||||
|
||||
}
|
||||
|
||||
static void keyboardHandleEnter(void* data,
|
||||
struct wl_keyboard* keyboard,
|
||||
uint32_t serial,
|
||||
static void keyboardHandleEnter(void* data UNUSED,
|
||||
struct wl_keyboard* keyboard UNUSED,
|
||||
uint32_t serial UNUSED,
|
||||
struct wl_surface* surface,
|
||||
struct wl_array* keys)
|
||||
struct wl_array* keys UNUSED)
|
||||
{
|
||||
// Happens in the case we just destroyed the surface.
|
||||
if (!surface)
|
||||
@@ -373,10 +385,10 @@ static void keyboardHandleEnter(void* data,
|
||||
_glfwInputWindowFocus(window, true);
|
||||
}
|
||||
|
||||
static void keyboardHandleLeave(void* data,
|
||||
struct wl_keyboard* keyboard,
|
||||
uint32_t serial,
|
||||
struct wl_surface* surface)
|
||||
static void keyboardHandleLeave(void* data UNUSED,
|
||||
struct wl_keyboard* keyboard UNUSED,
|
||||
uint32_t serial UNUSED,
|
||||
struct wl_surface* surface UNUSED)
|
||||
{
|
||||
_GLFWwindow* window = _glfw.wl.keyboardFocus;
|
||||
|
||||
@@ -388,7 +400,7 @@ static void keyboardHandleLeave(void* data,
|
||||
}
|
||||
|
||||
static void
|
||||
dispatchPendingKeyRepeats(id_type timer_id, void *data) {
|
||||
dispatchPendingKeyRepeats(id_type timer_id UNUSED, void *data UNUSED) {
|
||||
if (_glfw.wl.keyRepeatInfo.keyboardFocus != _glfw.wl.keyboardFocus || _glfw.wl.keyboardRepeatRate == 0) return;
|
||||
glfw_xkb_handle_key_event(_glfw.wl.keyRepeatInfo.keyboardFocus, &_glfw.wl.xkb, _glfw.wl.keyRepeatInfo.key, GLFW_REPEAT);
|
||||
changeTimerInterval(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, (1.0 / (double)_glfw.wl.keyboardRepeatRate));
|
||||
@@ -396,10 +408,10 @@ dispatchPendingKeyRepeats(id_type timer_id, void *data) {
|
||||
}
|
||||
|
||||
|
||||
static void keyboardHandleKey(void* data,
|
||||
struct wl_keyboard* keyboard,
|
||||
uint32_t serial,
|
||||
uint32_t time,
|
||||
static void keyboardHandleKey(void* data UNUSED,
|
||||
struct wl_keyboard* keyboard UNUSED,
|
||||
uint32_t serial UNUSED,
|
||||
uint32_t time UNUSED,
|
||||
uint32_t key,
|
||||
uint32_t state)
|
||||
{
|
||||
@@ -422,9 +434,9 @@ static void keyboardHandleKey(void* data,
|
||||
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, repeatable ? 1 : 0);
|
||||
}
|
||||
|
||||
static void keyboardHandleModifiers(void* data,
|
||||
struct wl_keyboard* keyboard,
|
||||
uint32_t serial,
|
||||
static void keyboardHandleModifiers(void* data UNUSED,
|
||||
struct wl_keyboard* keyboard UNUSED,
|
||||
uint32_t serial UNUSED,
|
||||
uint32_t modsDepressed,
|
||||
uint32_t modsLatched,
|
||||
uint32_t modsLocked,
|
||||
@@ -433,7 +445,7 @@ static void keyboardHandleModifiers(void* data,
|
||||
glfw_xkb_update_modifiers(&_glfw.wl.xkb, modsDepressed, modsLatched, modsLocked, 0, 0, group);
|
||||
}
|
||||
|
||||
static void keyboardHandleRepeatInfo(void* data,
|
||||
static void keyboardHandleRepeatInfo(void* data UNUSED,
|
||||
struct wl_keyboard* keyboard,
|
||||
int32_t rate,
|
||||
int32_t delay)
|
||||
@@ -454,7 +466,7 @@ static const struct wl_keyboard_listener keyboardListener = {
|
||||
keyboardHandleRepeatInfo,
|
||||
};
|
||||
|
||||
static void seatHandleCapabilities(void* data,
|
||||
static void seatHandleCapabilities(void* data UNUSED,
|
||||
struct wl_seat* seat,
|
||||
enum wl_seat_capability caps)
|
||||
{
|
||||
@@ -481,9 +493,9 @@ static void seatHandleCapabilities(void* data,
|
||||
}
|
||||
}
|
||||
|
||||
static void seatHandleName(void* data,
|
||||
struct wl_seat* seat,
|
||||
const char* name)
|
||||
static void seatHandleName(void* data UNUSED,
|
||||
struct wl_seat* seat UNUSED,
|
||||
const char* name UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -492,7 +504,7 @@ static const struct wl_seat_listener seatListener = {
|
||||
seatHandleName,
|
||||
};
|
||||
|
||||
static void wmBaseHandlePing(void* data,
|
||||
static void wmBaseHandlePing(void* data UNUSED,
|
||||
struct xdg_wm_base* wmBase,
|
||||
uint32_t serial)
|
||||
{
|
||||
@@ -503,7 +515,7 @@ static const struct xdg_wm_base_listener wmBaseListener = {
|
||||
wmBaseHandlePing
|
||||
};
|
||||
|
||||
static void registryHandleGlobal(void* data,
|
||||
static void registryHandleGlobal(void* data UNUSED,
|
||||
struct wl_registry* registry,
|
||||
uint32_t name,
|
||||
const char* interface,
|
||||
@@ -609,8 +621,8 @@ static void registryHandleGlobal(void* data,
|
||||
|
||||
}
|
||||
|
||||
static void registryHandleGlobalRemove(void *data,
|
||||
struct wl_registry *registry,
|
||||
static void registryHandleGlobalRemove(void *data UNUSED,
|
||||
struct wl_registry *registry UNUSED,
|
||||
uint32_t name)
|
||||
{
|
||||
_GLFWmonitor* monitor;
|
||||
@@ -642,19 +654,19 @@ static const struct wl_registry_listener registryListener = {
|
||||
|
||||
|
||||
static void registry_handle_global(void* data,
|
||||
struct wl_registry* registry,
|
||||
uint32_t name,
|
||||
struct wl_registry* registry UNUSED,
|
||||
uint32_t name UNUSED,
|
||||
const char* interface,
|
||||
uint32_t version) {
|
||||
uint32_t version UNUSED) {
|
||||
if (strcmp(interface, "zxdg_decoration_manager_v1") == 0) {
|
||||
bool *has_ssd = (bool*)data;
|
||||
if (has_ssd) *has_ssd = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void registry_handle_global_remove(void *data,
|
||||
struct wl_registry *registry,
|
||||
uint32_t name) {}
|
||||
static void registry_handle_global_remove(void *data UNUSED,
|
||||
struct wl_registry *registry UNUSED,
|
||||
uint32_t name UNUSED) {}
|
||||
GLFWAPI const char*
|
||||
glfwWaylandCheckForServerSideDecorations(void) {
|
||||
struct wl_display *display = wl_display_connect(NULL);
|
||||
@@ -679,13 +691,6 @@ glfwWaylandCheckForServerSideDecorations(void) {
|
||||
|
||||
int _glfwPlatformInit(void)
|
||||
{
|
||||
if (pipe2(_glfw.wl.eventLoopData.wakeupFds, O_CLOEXEC | O_NONBLOCK) != 0)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: failed to create self pipe");
|
||||
return false;
|
||||
}
|
||||
|
||||
_glfw.wl.cursor.handle = _glfw_dlopen("libwayland-cursor.so.0");
|
||||
if (!_glfw.wl.cursor.handle)
|
||||
{
|
||||
@@ -694,14 +699,10 @@ int _glfwPlatformInit(void)
|
||||
return 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_dlsym(_glfw.wl.cursor.theme_load, _glfw.wl.cursor.handle, "wl_cursor_theme_load");
|
||||
glfw_dlsym(_glfw.wl.cursor.theme_destroy, _glfw.wl.cursor.handle, "wl_cursor_theme_destroy");
|
||||
glfw_dlsym(_glfw.wl.cursor.theme_get_cursor, _glfw.wl.cursor.handle, "wl_cursor_theme_get_cursor");
|
||||
glfw_dlsym(_glfw.wl.cursor.image_get_buffer, _glfw.wl.cursor.handle, "wl_cursor_image_get_buffer");
|
||||
|
||||
_glfw.wl.egl.handle = _glfw_dlopen("libwayland-egl.so.1");
|
||||
if (!_glfw.wl.egl.handle)
|
||||
@@ -711,12 +712,9 @@ int _glfwPlatformInit(void)
|
||||
return 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");
|
||||
glfw_dlsym(_glfw.wl.egl.window_create, _glfw.wl.egl.handle, "wl_egl_window_create");
|
||||
glfw_dlsym(_glfw.wl.egl.window_destroy, _glfw.wl.egl.handle, "wl_egl_window_destroy");
|
||||
glfw_dlsym(_glfw.wl.egl.window_resize, _glfw.wl.egl.handle, "wl_egl_window_resize");
|
||||
|
||||
_glfw.wl.display = wl_display_connect(NULL);
|
||||
if (!_glfw.wl.display)
|
||||
@@ -725,7 +723,10 @@ int _glfwPlatformInit(void)
|
||||
"Wayland: Failed to connect to display");
|
||||
return false;
|
||||
}
|
||||
initPollData(&_glfw.wl.eventLoopData, _glfw.wl.eventLoopData.wakeupFds[0], wl_display_get_fd(_glfw.wl.display));
|
||||
if (!initPollData(&_glfw.wl.eventLoopData, wl_display_get_fd(_glfw.wl.display))) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Failed to initialize event loop data");
|
||||
}
|
||||
glfw_dbus_init(&_glfw.wl.dbus, &_glfw.wl.eventLoopData);
|
||||
_glfw.wl.keyRepeatInfo.keyRepeatTimer = addTimer(&_glfw.wl.eventLoopData, "wayland-key-repeat", 0.5, 0, true, dispatchPendingKeyRepeats, NULL, NULL);
|
||||
_glfw.wl.cursorAnimationTimer = addTimer(&_glfw.wl.eventLoopData, "wayland-cursor-animation", 0.5, 0, true, animateCursorImage, NULL, NULL);
|
||||
@@ -853,7 +854,7 @@ void _glfwPlatformTerminate(void)
|
||||
wl_display_flush(_glfw.wl.display);
|
||||
wl_display_disconnect(_glfw.wl.display);
|
||||
}
|
||||
closeFds(_glfw.wl.eventLoopData.wakeupFds, sizeof(_glfw.wl.eventLoopData.wakeupFds)/sizeof(_glfw.wl.eventLoopData.wakeupFds[0]));
|
||||
finalizePollData(&_glfw.wl.eventLoopData);
|
||||
free(_glfw.wl.clipboardString); _glfw.wl.clipboardString = NULL;
|
||||
free(_glfw.wl.primarySelectionString); _glfw.wl.primarySelectionString = NULL;
|
||||
free(_glfw.wl.pasteString); _glfw.wl.pasteString = NULL;
|
||||
|
||||
47
glfw/wl_monitor.c
vendored
47
glfw/wl_monitor.c
vendored
@@ -23,6 +23,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@@ -34,15 +36,15 @@
|
||||
|
||||
|
||||
static void outputHandleGeometry(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 wl_output* output UNUSED,
|
||||
int32_t x,
|
||||
int32_t y,
|
||||
int32_t physicalWidth,
|
||||
int32_t physicalHeight,
|
||||
int32_t subpixel UNUSED,
|
||||
const char* make,
|
||||
const char* model,
|
||||
int32_t transform UNUSED)
|
||||
{
|
||||
struct _GLFWmonitor *monitor = data;
|
||||
char name[1024];
|
||||
@@ -57,11 +59,11 @@ static void outputHandleGeometry(void* data,
|
||||
}
|
||||
|
||||
static void outputHandleMode(void* data,
|
||||
struct wl_output* output,
|
||||
uint32_t flags,
|
||||
int32_t width,
|
||||
int32_t height,
|
||||
int32_t refresh)
|
||||
struct wl_output* output UNUSED,
|
||||
uint32_t flags,
|
||||
int32_t width,
|
||||
int32_t height,
|
||||
int32_t refresh)
|
||||
{
|
||||
struct _GLFWmonitor *monitor = data;
|
||||
GLFWvidmode mode;
|
||||
@@ -71,7 +73,7 @@ static void outputHandleMode(void* data,
|
||||
mode.redBits = 8;
|
||||
mode.greenBits = 8;
|
||||
mode.blueBits = 8;
|
||||
mode.refreshRate = (int)round(refresh / 1000.0);
|
||||
mode.refreshRate = (int) round(refresh / 1000.0);
|
||||
|
||||
monitor->modeCount++;
|
||||
monitor->modes =
|
||||
@@ -82,7 +84,7 @@ static void outputHandleMode(void* data,
|
||||
monitor->wl.currentMode = monitor->modeCount - 1;
|
||||
}
|
||||
|
||||
static void outputHandleDone(void* data, struct wl_output* output)
|
||||
static void outputHandleDone(void* data, struct wl_output* output UNUSED)
|
||||
{
|
||||
struct _GLFWmonitor *monitor = data;
|
||||
for (int i = 0; i < _glfw.monitorCount; i++) {
|
||||
@@ -93,8 +95,8 @@ static void outputHandleDone(void* data, struct wl_output* output)
|
||||
}
|
||||
|
||||
static void outputHandleScale(void* data,
|
||||
struct wl_output* output,
|
||||
int32_t factor)
|
||||
struct wl_output* output UNUSED,
|
||||
int32_t factor)
|
||||
{
|
||||
struct _GLFWmonitor *monitor = data;
|
||||
if (factor > 0 && factor < 24)
|
||||
@@ -173,7 +175,9 @@ void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
|
||||
*yscale = (float) monitor->wl.scale;
|
||||
}
|
||||
|
||||
void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int *width, int *height)
|
||||
void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor,
|
||||
int* xpos, int* ypos,
|
||||
int* width, int* height)
|
||||
{
|
||||
if (xpos)
|
||||
*xpos = monitor->wl.x;
|
||||
@@ -196,14 +200,15 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
|
||||
*mode = monitor->modes[monitor->wl.currentMode];
|
||||
}
|
||||
|
||||
bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor UNUSED, GLFWgammaramp* ramp UNUSED)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Gamma ramp access is not available");
|
||||
return false;
|
||||
}
|
||||
|
||||
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
|
||||
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor UNUSED,
|
||||
const GLFWgammaramp* ramp UNUSED)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Gamma ramp access is not available");
|
||||
|
||||
14
glfw/wl_platform.h
vendored
14
glfw/wl_platform.h
vendored
@@ -133,10 +133,10 @@ typedef struct _GLFWdecorationWayland
|
||||
typedef struct _GLFWwindowWayland
|
||||
{
|
||||
int width, height;
|
||||
bool visible;
|
||||
bool maximized;
|
||||
bool hovered;
|
||||
bool transparent;
|
||||
bool visible;
|
||||
bool maximized;
|
||||
bool hovered;
|
||||
bool transparent;
|
||||
struct wl_surface* surface;
|
||||
struct wl_egl_window* native;
|
||||
struct wl_callback* callback;
|
||||
@@ -167,10 +167,10 @@ typedef struct _GLFWwindowWayland
|
||||
|
||||
struct zwp_idle_inhibitor_v1* idleInhibitor;
|
||||
|
||||
bool fullscreened;
|
||||
bool fullscreened;
|
||||
|
||||
struct {
|
||||
bool serverSide;
|
||||
bool serverSide;
|
||||
struct wl_buffer* buffer;
|
||||
_GLFWdecorationWayland top, left, right, bottom;
|
||||
int focus;
|
||||
@@ -295,7 +295,7 @@ typedef struct _GLFWlibraryWayland
|
||||
typedef struct _GLFWmonitorWayland
|
||||
{
|
||||
struct wl_output* output;
|
||||
int name;
|
||||
uint32_t name;
|
||||
int currentMode;
|
||||
|
||||
int x;
|
||||
|
||||
157
glfw/wl_window.c
vendored
157
glfw/wl_window.c
vendored
@@ -23,6 +23,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
@@ -239,7 +241,7 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image)
|
||||
if (fd < 0)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Creating a buffer file for %d B failed: %m",
|
||||
"Wayland: Creating a buffer file for %d B failed: %%m",
|
||||
length);
|
||||
return NULL;
|
||||
}
|
||||
@@ -248,7 +250,7 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image)
|
||||
if (data == MAP_FAILED)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: mmap failed: %m");
|
||||
"Wayland: mmap failed: %%m");
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
@@ -363,12 +365,12 @@ static void destroyDecorations(_GLFWwindow* window)
|
||||
}
|
||||
|
||||
static void xdgDecorationHandleConfigure(void* data,
|
||||
struct zxdg_toplevel_decoration_v1* decoration,
|
||||
struct zxdg_toplevel_decoration_v1* decoration UNUSED,
|
||||
uint32_t mode)
|
||||
{
|
||||
_GLFWwindow* window = data;
|
||||
window->wl.decorations.serverSide = (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
|
||||
if (!window->wl.decorations.serverSide)
|
||||
window->wl.decorations.serverSide = (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
|
||||
if (!window->wl.decorations.serverSide)
|
||||
createDecorations(window);
|
||||
}
|
||||
|
||||
@@ -377,7 +379,7 @@ static const struct zxdg_toplevel_decoration_v1_listener xdgDecorationListener =
|
||||
};
|
||||
|
||||
static void handleEnter(void *data,
|
||||
struct wl_surface *surface,
|
||||
struct wl_surface *surface UNUSED,
|
||||
struct wl_output *output)
|
||||
{
|
||||
_GLFWwindow* window = data;
|
||||
@@ -400,7 +402,7 @@ static void handleEnter(void *data,
|
||||
}
|
||||
|
||||
static void handleLeave(void *data,
|
||||
struct wl_surface *surface,
|
||||
struct wl_surface *surface UNUSED,
|
||||
struct wl_output *output)
|
||||
{
|
||||
_GLFWwindow* window = data;
|
||||
@@ -496,15 +498,14 @@ setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor, bool on)
|
||||
}
|
||||
|
||||
bool
|
||||
_glfwPlatformToggleFullscreen(_GLFWwindow *window, unsigned int flags) {
|
||||
(void) flags;
|
||||
_glfwPlatformToggleFullscreen(_GLFWwindow *window, unsigned int flags UNUSED) {
|
||||
bool already_fullscreen = window->wl.fullscreened;
|
||||
setFullscreen(window, NULL, !already_fullscreen);
|
||||
return !already_fullscreen;
|
||||
}
|
||||
|
||||
static void xdgToplevelHandleConfigure(void* data,
|
||||
struct xdg_toplevel* toplevel,
|
||||
struct xdg_toplevel* toplevel UNUSED,
|
||||
int32_t width,
|
||||
int32_t height,
|
||||
struct wl_array* states)
|
||||
@@ -562,7 +563,7 @@ static void xdgToplevelHandleConfigure(void* data,
|
||||
}
|
||||
|
||||
static void xdgToplevelHandleClose(void* data,
|
||||
struct xdg_toplevel* toplevel)
|
||||
struct xdg_toplevel* toplevel UNUSED)
|
||||
{
|
||||
_GLFWwindow* window = data;
|
||||
_glfwInputWindowCloseRequest(window);
|
||||
@@ -573,7 +574,7 @@ static const struct xdg_toplevel_listener xdgToplevelListener = {
|
||||
xdgToplevelHandleClose
|
||||
};
|
||||
|
||||
static void xdgSurfaceHandleConfigure(void* data,
|
||||
static void xdgSurfaceHandleConfigure(void* data UNUSED,
|
||||
struct xdg_surface* surface,
|
||||
uint32_t serial)
|
||||
{
|
||||
@@ -726,7 +727,7 @@ incrementCursorImage(_GLFWwindow* window)
|
||||
}
|
||||
|
||||
void
|
||||
animateCursorImage(id_type timer_id, void *data) {
|
||||
animateCursorImage(id_type timer_id UNUSED, void *data UNUSED) {
|
||||
incrementCursorImage(_glfw.wl.pointerFocus);
|
||||
}
|
||||
|
||||
@@ -739,6 +740,8 @@ abortOnFatalError(int last_error) {
|
||||
_glfwInputWindowCloseRequest(window);
|
||||
window = window->next;
|
||||
}
|
||||
// ensure the tick callback is called
|
||||
_glfw.wl.eventLoopData.wakeup_data_read = true;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -746,16 +749,17 @@ handleEvents(double timeout)
|
||||
{
|
||||
struct wl_display* display = _glfw.wl.display;
|
||||
errno = 0;
|
||||
EVDBG("starting handleEvents(%.2f)", timeout);
|
||||
|
||||
while (wl_display_prepare_read(display) != 0) {
|
||||
while(1) {
|
||||
errno = 0;
|
||||
int num_dispatched = wl_display_dispatch_pending(display);
|
||||
if (num_dispatched == 0) return;
|
||||
if (num_dispatched < 0) {
|
||||
if (errno == EAGAIN) continue;
|
||||
int last_error = wl_display_get_error(display);
|
||||
if (last_error) abortOnFatalError(last_error);
|
||||
wl_display_cancel_read(display);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@@ -774,9 +778,12 @@ handleEvents(double timeout)
|
||||
}
|
||||
|
||||
bool display_read_ok = pollForEvents(&_glfw.wl.eventLoopData, timeout);
|
||||
EVDBG("display_read_ok: %d", display_read_ok);
|
||||
if (display_read_ok) {
|
||||
wl_display_read_events(display);
|
||||
wl_display_dispatch_pending(display);
|
||||
int num = wl_display_dispatch_pending(display);
|
||||
(void)num;
|
||||
EVDBG("dispatched %d Wayland events", num);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -784,6 +791,8 @@ handleEvents(double timeout)
|
||||
}
|
||||
glfw_ibus_dispatch(&_glfw.wl.xkb.ibus);
|
||||
glfw_dbus_session_bus_dispatch();
|
||||
EVDBG("other dispatch done");
|
||||
if (_glfw.wl.eventLoopData.wakeup_fd_ready) check_for_wakeup_events(&_glfw.wl.eventLoopData);
|
||||
}
|
||||
|
||||
static struct wl_cursor*
|
||||
@@ -914,6 +923,7 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
|
||||
destroyDecorations(window);
|
||||
if (window->wl.xdg.decoration)
|
||||
zxdg_toplevel_decoration_v1_destroy(window->wl.xdg.decoration);
|
||||
|
||||
if (window->wl.decorations.buffer)
|
||||
wl_buffer_destroy(window->wl.decorations.buffer);
|
||||
|
||||
@@ -944,14 +954,14 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
|
||||
xdg_toplevel_set_title(window->wl.xdg.toplevel, title);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
|
||||
int count, const GLFWimage* images)
|
||||
void _glfwPlatformSetWindowIcon(_GLFWwindow* window UNUSED,
|
||||
int count UNUSED, const GLFWimage* images UNUSED)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Setting window icon not supported");
|
||||
}
|
||||
|
||||
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
|
||||
void _glfwPlatformGetWindowPos(_GLFWwindow* window UNUSED, int* xpos UNUSED, int* ypos UNUSED)
|
||||
{
|
||||
// A Wayland client is not aware of its position, so just warn and leave it
|
||||
// as (0, 0)
|
||||
@@ -960,7 +970,7 @@ void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
|
||||
"Wayland: Window position retrieval not supported");
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
|
||||
void _glfwPlatformSetWindowPos(_GLFWwindow* window UNUSED, int xpos UNUSED, int ypos UNUSED)
|
||||
{
|
||||
// A Wayland client can not set its position, so just warn
|
||||
|
||||
@@ -1001,13 +1011,15 @@ void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom)
|
||||
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window UNUSED,
|
||||
int numer UNUSED, int denom UNUSED)
|
||||
{
|
||||
// TODO: find out how to trigger a resize.
|
||||
// The actual limits are checked in the xdg_toplevel::configure handler.
|
||||
}
|
||||
|
||||
void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height)
|
||||
void _glfwPlatformGetFramebufferSize(_GLFWwindow* window,
|
||||
int* width, int* height)
|
||||
{
|
||||
_glfwPlatformGetWindowSize(window, width, height);
|
||||
*width *= window->wl.scale;
|
||||
@@ -1040,7 +1052,7 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
|
||||
*yscale = (float) window->wl.scale;
|
||||
}
|
||||
|
||||
double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window)
|
||||
double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED)
|
||||
{
|
||||
return 0.5;
|
||||
}
|
||||
@@ -1096,7 +1108,7 @@ void _glfwPlatformHideWindow(_GLFWwindow* window)
|
||||
window->wl.visible = false;
|
||||
}
|
||||
|
||||
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window)
|
||||
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window UNUSED)
|
||||
{
|
||||
// TODO
|
||||
static bool notified = false;
|
||||
@@ -1107,7 +1119,7 @@ void _glfwPlatformRequestWindowAttention(_GLFWwindow* window)
|
||||
}
|
||||
}
|
||||
|
||||
int _glfwPlatformWindowBell(_GLFWwindow* window)
|
||||
int _glfwPlatformWindowBell(_GLFWwindow* window UNUSED)
|
||||
{
|
||||
// TODO: Use an actual Wayland API to implement this when one becomes available
|
||||
static char tty[L_ctermid + 1];
|
||||
@@ -1120,7 +1132,7 @@ int _glfwPlatformWindowBell(_GLFWwindow* window)
|
||||
return false;
|
||||
}
|
||||
|
||||
void _glfwPlatformFocusWindow(_GLFWwindow* window)
|
||||
void _glfwPlatformFocusWindow(_GLFWwindow* window UNUSED)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Focusing a window requires user interaction");
|
||||
@@ -1128,9 +1140,9 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window)
|
||||
|
||||
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
|
||||
_GLFWmonitor* monitor,
|
||||
int xpos, int ypos,
|
||||
int width, int height,
|
||||
int refreshRate)
|
||||
int xpos UNUSED, int ypos UNUSED,
|
||||
int width UNUSED, int height UNUSED,
|
||||
int refreshRate UNUSED)
|
||||
{
|
||||
setFullscreen(window, monitor, monitor != NULL);
|
||||
_glfwInputWindowMonitor(window, monitor);
|
||||
@@ -1141,12 +1153,12 @@ int _glfwPlatformWindowFocused(_GLFWwindow* window)
|
||||
return _glfw.wl.keyboardFocus == window;
|
||||
}
|
||||
|
||||
int _glfwPlatformWindowOccluded(_GLFWwindow* window)
|
||||
int _glfwPlatformWindowOccluded(_GLFWwindow* window UNUSED)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int _glfwPlatformWindowIconified(_GLFWwindow* window)
|
||||
int _glfwPlatformWindowIconified(_GLFWwindow* window UNUSED)
|
||||
{
|
||||
// xdg-shell doesn’t give any way to request whether a surface is
|
||||
// iconified.
|
||||
@@ -1173,7 +1185,7 @@ int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
|
||||
return window->wl.transparent;
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, bool enabled)
|
||||
void _glfwPlatformSetWindowResizable(_GLFWwindow* window UNUSED, bool enabled UNUSED)
|
||||
{
|
||||
// TODO
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
@@ -1191,19 +1203,19 @@ void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, bool enabled)
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, bool enabled)
|
||||
void _glfwPlatformSetWindowFloating(_GLFWwindow* window UNUSED, bool enabled UNUSED)
|
||||
{
|
||||
// TODO
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Window attribute setting not implemented yet");
|
||||
}
|
||||
|
||||
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window)
|
||||
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window UNUSED)
|
||||
{
|
||||
return 1.f;
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity)
|
||||
void _glfwPlatformSetWindowOpacity(_GLFWwindow* window UNUSED, float opacity UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1227,7 +1239,7 @@ void _glfwPlatformWaitEventsTimeout(double timeout)
|
||||
|
||||
void _glfwPlatformPostEmptyEvent(void)
|
||||
{
|
||||
while (write(_glfw.wl.eventLoopData.wakeupFds[1], "w", 1) < 0 && errno == EINTR);
|
||||
wakeupEventLoop(&_glfw.wl.eventLoopData);
|
||||
}
|
||||
|
||||
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
|
||||
@@ -1251,7 +1263,7 @@ void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
|
||||
void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode UNUSED)
|
||||
{
|
||||
_glfwPlatformSetCursor(window, window->wl.currentCursor);
|
||||
}
|
||||
@@ -1268,7 +1280,7 @@ int _glfwPlatformGetKeyScancode(int key)
|
||||
|
||||
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||
const GLFWimage* image,
|
||||
int xhot, int yhot, int count)
|
||||
int xhot, int yhot, int count UNUSED)
|
||||
{
|
||||
cursor->wl.buffer = createShmBuffer(image);
|
||||
if (!cursor->wl.buffer)
|
||||
@@ -1302,11 +1314,11 @@ void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
|
||||
}
|
||||
|
||||
static void handleRelativeMotion(void* data,
|
||||
struct zwp_relative_pointer_v1* pointer,
|
||||
uint32_t timeHi,
|
||||
uint32_t timeLo,
|
||||
wl_fixed_t dx,
|
||||
wl_fixed_t dy,
|
||||
struct zwp_relative_pointer_v1* pointer UNUSED,
|
||||
uint32_t timeHi UNUSED,
|
||||
uint32_t timeLo UNUSED,
|
||||
wl_fixed_t dx UNUSED,
|
||||
wl_fixed_t dy UNUSED,
|
||||
wl_fixed_t dxUnaccel,
|
||||
wl_fixed_t dyUnaccel)
|
||||
{
|
||||
@@ -1324,8 +1336,8 @@ static const struct zwp_relative_pointer_v1_listener relativePointerListener = {
|
||||
handleRelativeMotion
|
||||
};
|
||||
|
||||
static void handleLocked(void* data,
|
||||
struct zwp_locked_pointer_v1* lockedPointer)
|
||||
static void handleLocked(void* data UNUSED,
|
||||
struct zwp_locked_pointer_v1* lockedPointer UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1343,10 +1355,10 @@ static void unlockPointer(_GLFWwindow* window)
|
||||
window->wl.pointerLock.lockedPointer = NULL;
|
||||
}
|
||||
|
||||
static void lockPointer(_GLFWwindow* window);
|
||||
static void lockPointer(_GLFWwindow* window UNUSED);
|
||||
|
||||
static void handleUnlocked(void* data,
|
||||
struct zwp_locked_pointer_v1* lockedPointer)
|
||||
static void handleUnlocked(void* data UNUSED,
|
||||
struct zwp_locked_pointer_v1* lockedPointer UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1468,12 +1480,12 @@ static void send_text(char *text, int fd)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void _glfwSendClipboardText(void *data, struct wl_data_source *data_source, const char *mime_type, int fd) {
|
||||
static void _glfwSendClipboardText(void *data UNUSED, struct wl_data_source *data_source UNUSED, const char *mime_type UNUSED, int fd) {
|
||||
send_text(_glfw.wl.clipboardString, fd);
|
||||
}
|
||||
|
||||
static void _glfwSendPrimarySelectionText(void *data, struct zwp_primary_selection_source_v1 *primary_selection_source,
|
||||
const char *mime_type, int fd) {
|
||||
static void _glfwSendPrimarySelectionText(void *data UNUSED, struct zwp_primary_selection_source_v1 *primary_selection_source UNUSED,
|
||||
const char *mime_type UNUSED, int fd) {
|
||||
send_text(_glfw.wl.primarySelectionString, fd);
|
||||
}
|
||||
|
||||
@@ -1538,28 +1550,28 @@ static char* read_data_offer(struct wl_data_offer *data_offer, const char *mime)
|
||||
return read_offer_string(pipefd[0]);
|
||||
}
|
||||
|
||||
static void data_source_canceled(void *data, struct wl_data_source *wl_data_source) {
|
||||
static void data_source_canceled(void *data UNUSED, struct wl_data_source *wl_data_source) {
|
||||
if (_glfw.wl.dataSourceForClipboard == wl_data_source)
|
||||
_glfw.wl.dataSourceForClipboard = NULL;
|
||||
wl_data_source_destroy(wl_data_source);
|
||||
}
|
||||
|
||||
static void primary_selection_source_canceled(void *data, struct zwp_primary_selection_source_v1 *primary_selection_source) {
|
||||
static void primary_selection_source_canceled(void *data UNUSED, struct zwp_primary_selection_source_v1 *primary_selection_source) {
|
||||
if (_glfw.wl.dataSourceForPrimarySelection == primary_selection_source)
|
||||
_glfw.wl.dataSourceForPrimarySelection = NULL;
|
||||
zwp_primary_selection_source_v1_destroy(primary_selection_source);
|
||||
}
|
||||
|
||||
static void data_source_target(void *data, struct wl_data_source *wl_data_source, const char* mime) {
|
||||
static void data_source_target(void *data UNUSED, struct wl_data_source *wl_data_source UNUSED, const char* mime UNUSED) {
|
||||
}
|
||||
|
||||
const static struct wl_data_source_listener data_source_listener = {
|
||||
static const struct wl_data_source_listener data_source_listener = {
|
||||
.send = _glfwSendClipboardText,
|
||||
.cancelled = data_source_canceled,
|
||||
.target = data_source_target,
|
||||
};
|
||||
|
||||
const static struct zwp_primary_selection_source_v1_listener primary_selection_source_listener = {
|
||||
static const struct zwp_primary_selection_source_v1_listener primary_selection_source_listener = {
|
||||
.send = _glfwSendPrimarySelectionText,
|
||||
.cancelled = primary_selection_source_canceled,
|
||||
};
|
||||
@@ -1582,7 +1594,7 @@ static void prune_unclaimed_primary_selection_offers(void) {
|
||||
}
|
||||
}
|
||||
|
||||
static void mark_selection_offer(void *data, struct wl_data_device *data_device, struct wl_data_offer *data_offer)
|
||||
static void mark_selection_offer(void *data UNUSED, struct wl_data_device *data_device UNUSED, struct wl_data_offer *data_offer)
|
||||
{
|
||||
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||
if (_glfw.wl.dataOffers[i].id == data_offer) {
|
||||
@@ -1594,7 +1606,7 @@ static void mark_selection_offer(void *data, struct wl_data_device *data_device,
|
||||
prune_unclaimed_data_offers();
|
||||
}
|
||||
|
||||
static void mark_primary_selection_offer(void *data, struct zwp_primary_selection_device_v1* primary_selection_device,
|
||||
static void mark_primary_selection_offer(void *data UNUSED, struct zwp_primary_selection_device_v1* primary_selection_device UNUSED,
|
||||
struct zwp_primary_selection_offer_v1 *primary_selection_offer) {
|
||||
for (size_t i = 0; i < arraysz(_glfw.wl.primarySelectionOffers); i++) {
|
||||
if (_glfw.wl.primarySelectionOffers[i].id == primary_selection_offer) {
|
||||
@@ -1617,7 +1629,7 @@ static void set_offer_mimetype(struct _GLFWWaylandDataOffer* offer, const char*
|
||||
offer->has_uri_list = 1;
|
||||
}
|
||||
|
||||
static void handle_offer_mimetype(void *data, struct wl_data_offer* id, const char *mime) {
|
||||
static void handle_offer_mimetype(void *data UNUSED, struct wl_data_offer* id, const char *mime) {
|
||||
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||
if (_glfw.wl.dataOffers[i].id == id) {
|
||||
set_offer_mimetype(&_glfw.wl.dataOffers[i], mime);
|
||||
@@ -1626,7 +1638,7 @@ static void handle_offer_mimetype(void *data, struct wl_data_offer* id, const ch
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_primary_selection_offer_mimetype(void *data, struct zwp_primary_selection_offer_v1* id, const char *mime) {
|
||||
static void handle_primary_selection_offer_mimetype(void *data UNUSED, struct zwp_primary_selection_offer_v1* id, const char *mime) {
|
||||
for (size_t i = 0; i < arraysz(_glfw.wl.primarySelectionOffers); i++) {
|
||||
if (_glfw.wl.primarySelectionOffers[i].id == id) {
|
||||
set_offer_mimetype((struct _GLFWWaylandDataOffer*)&_glfw.wl.primarySelectionOffers[i], mime);
|
||||
@@ -1635,7 +1647,7 @@ static void handle_primary_selection_offer_mimetype(void *data, struct zwp_prima
|
||||
}
|
||||
}
|
||||
|
||||
static void data_offer_source_actions(void *data, struct wl_data_offer* id, uint32_t actions) {
|
||||
static void data_offer_source_actions(void *data UNUSED, struct wl_data_offer* id, uint32_t actions) {
|
||||
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||
if (_glfw.wl.dataOffers[i].id == id) {
|
||||
_glfw.wl.dataOffers[i].source_actions = actions;
|
||||
@@ -1644,7 +1656,7 @@ static void data_offer_source_actions(void *data, struct wl_data_offer* id, uint
|
||||
}
|
||||
}
|
||||
|
||||
static void data_offer_action(void *data, struct wl_data_offer* id, uint32_t action) {
|
||||
static void data_offer_action(void *data UNUSED, struct wl_data_offer* id, uint32_t action) {
|
||||
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||
if (_glfw.wl.dataOffers[i].id == id) {
|
||||
_glfw.wl.dataOffers[i].dnd_action = action;
|
||||
@@ -1664,7 +1676,7 @@ static const struct zwp_primary_selection_offer_v1_listener primary_selection_of
|
||||
.offer = handle_primary_selection_offer_mimetype,
|
||||
};
|
||||
|
||||
static void handle_data_offer(void *data, struct wl_data_device *wl_data_device, struct wl_data_offer *id) {
|
||||
static void handle_data_offer(void *data UNUSED, struct wl_data_device *wl_data_device UNUSED, struct wl_data_offer *id) {
|
||||
size_t smallest_idx = SIZE_MAX, pos = 0;
|
||||
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||
if (_glfw.wl.dataOffers[i].idx && _glfw.wl.dataOffers[i].idx < smallest_idx) {
|
||||
@@ -1685,7 +1697,7 @@ end:
|
||||
wl_data_offer_add_listener(id, &data_offer_listener, NULL);
|
||||
}
|
||||
|
||||
static void handle_primary_selection_offer(void *data, struct zwp_primary_selection_device_v1 *zwp_primary_selection_device_v1, struct zwp_primary_selection_offer_v1 *id) {
|
||||
static void handle_primary_selection_offer(void *data UNUSED, struct zwp_primary_selection_device_v1 *zwp_primary_selection_device_v1 UNUSED, struct zwp_primary_selection_offer_v1 *id) {
|
||||
size_t smallest_idx = SIZE_MAX, pos = 0;
|
||||
for (size_t i = 0; i < arraysz(_glfw.wl.primarySelectionOffers); i++) {
|
||||
if (_glfw.wl.primarySelectionOffers[i].idx && _glfw.wl.primarySelectionOffers[i].idx < smallest_idx) {
|
||||
@@ -1706,7 +1718,7 @@ end:
|
||||
zwp_primary_selection_offer_v1_add_listener(id, &primary_selection_offer_listener, NULL);
|
||||
}
|
||||
|
||||
static void drag_enter(void *data, struct wl_data_device *wl_data_device, uint32_t serial, struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *id) {
|
||||
static void drag_enter(void *data UNUSED, struct wl_data_device *wl_data_device UNUSED, uint32_t serial, struct wl_surface *surface, wl_fixed_t x UNUSED, wl_fixed_t y UNUSED, struct wl_data_offer *id) {
|
||||
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||
if (_glfw.wl.dataOffers[i].id == id) {
|
||||
_glfw.wl.dataOffers[i].offer_type = DRAG_AND_DROP;
|
||||
@@ -1720,7 +1732,7 @@ static void drag_enter(void *data, struct wl_data_device *wl_data_device, uint32
|
||||
prune_unclaimed_data_offers();
|
||||
}
|
||||
|
||||
static void drag_leave(void *data, struct wl_data_device *wl_data_device) {
|
||||
static void drag_leave(void *data UNUSED, struct wl_data_device *wl_data_device UNUSED) {
|
||||
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||
if (_glfw.wl.dataOffers[i].offer_type == DRAG_AND_DROP) {
|
||||
wl_data_offer_destroy(_glfw.wl.dataOffers[i].id);
|
||||
@@ -1729,7 +1741,7 @@ static void drag_leave(void *data, struct wl_data_device *wl_data_device) {
|
||||
}
|
||||
}
|
||||
|
||||
static void drop(void *data, struct wl_data_device *wl_data_device) {
|
||||
static void drop(void *data, struct wl_data_device *wl_data_device UNUSED) {
|
||||
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||
if (_glfw.wl.dataOffers[i].offer_type == DRAG_AND_DROP) {
|
||||
char *uri_list = read_data_offer(_glfw.wl.dataOffers[i].id, URI_LIST_MIME);
|
||||
@@ -1761,10 +1773,10 @@ static void drop(void *data, struct wl_data_device *wl_data_device) {
|
||||
}
|
||||
}
|
||||
|
||||
static void motion(void *data, struct wl_data_device *wl_data_device, uint32_t time, wl_fixed_t x, wl_fixed_t y) {
|
||||
static void motion(void *data UNUSED, struct wl_data_device *wl_data_device UNUSED, uint32_t time UNUSED, wl_fixed_t x UNUSED, wl_fixed_t y UNUSED) {
|
||||
}
|
||||
|
||||
const static struct wl_data_device_listener data_device_listener = {
|
||||
static const struct wl_data_device_listener data_device_listener = {
|
||||
.data_offer = handle_data_offer,
|
||||
.selection = mark_selection_offer,
|
||||
.enter = drag_enter,
|
||||
@@ -1773,7 +1785,7 @@ const static struct wl_data_device_listener data_device_listener = {
|
||||
.leave = drag_leave,
|
||||
};
|
||||
|
||||
const static struct zwp_primary_selection_device_v1_listener primary_selection_device_listener = {
|
||||
static const struct zwp_primary_selection_device_v1_listener primary_selection_device_listener = {
|
||||
.data_offer = handle_primary_selection_offer,
|
||||
.selection = mark_primary_selection_offer,
|
||||
};
|
||||
@@ -1853,7 +1865,7 @@ void _glfwPlatformSetClipboardString(const char* string)
|
||||
wl_data_source_offer(_glfw.wl.dataSourceForClipboard, "STRING");
|
||||
wl_data_source_offer(_glfw.wl.dataSourceForClipboard, "UTF8_STRING");
|
||||
struct wl_callback *callback = wl_display_sync(_glfw.wl.display);
|
||||
const static struct wl_callback_listener clipboard_copy_callback_listener = {.done = clipboard_copy_callback_done};
|
||||
static const struct wl_callback_listener clipboard_copy_callback_listener = {.done = clipboard_copy_callback_done};
|
||||
wl_callback_add_listener(callback, &clipboard_copy_callback_listener, _glfw.wl.dataSourceForClipboard);
|
||||
}
|
||||
|
||||
@@ -1902,7 +1914,7 @@ void _glfwPlatformSetPrimarySelectionString(const char* string)
|
||||
zwp_primary_selection_source_v1_offer(_glfw.wl.dataSourceForPrimarySelection, "STRING");
|
||||
zwp_primary_selection_source_v1_offer(_glfw.wl.dataSourceForPrimarySelection, "UTF8_STRING");
|
||||
struct wl_callback *callback = wl_display_sync(_glfw.wl.display);
|
||||
const static struct wl_callback_listener primary_selection_copy_callback_listener = {.done = primary_selection_copy_callback_done};
|
||||
static const struct wl_callback_listener primary_selection_copy_callback_listener = {.done = primary_selection_copy_callback_done};
|
||||
wl_callback_add_listener(callback, &primary_selection_copy_callback_listener, _glfw.wl.dataSourceForPrimarySelection);
|
||||
}
|
||||
|
||||
@@ -1992,7 +2004,7 @@ _glfwPlatformUpdateIMEState(_GLFWwindow *w, int which, int a, int b, int c, int
|
||||
}
|
||||
|
||||
static void
|
||||
frame_handle_redraw(void *data, struct wl_callback *callback, uint32_t time) {
|
||||
frame_handle_redraw(void *data, struct wl_callback *callback, uint32_t time UNUSED) {
|
||||
_GLFWwindow* window = (_GLFWwindow*) data;
|
||||
if (callback == window->wl.frameCallbackData.current_wl_callback) {
|
||||
window->wl.frameCallbackData.callback(window->wl.frameCallbackData.id);
|
||||
@@ -2001,6 +2013,7 @@ frame_handle_redraw(void *data, struct wl_callback *callback, uint32_t time) {
|
||||
wl_callback_destroy(callback);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW native API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
172
glfw/x11_init.c
vendored
172
glfw/x11_init.c
vendored
@@ -2,7 +2,7 @@
|
||||
// GLFW 3.3 X11 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2019 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
|
||||
@@ -24,6 +24,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include "internal.h"
|
||||
@@ -46,10 +48,9 @@ static Atom getSupportedAtom(Atom* supportedAtoms,
|
||||
unsigned long atomCount,
|
||||
const char* atomName)
|
||||
{
|
||||
unsigned long i;
|
||||
const Atom atom = XInternAtom(_glfw.x11.display, atomName, False);
|
||||
|
||||
for (i = 0; i < atomCount; i++)
|
||||
for (unsigned long i = 0; i < atomCount; i++)
|
||||
{
|
||||
if (supportedAtoms[i] == atom)
|
||||
return atom;
|
||||
@@ -62,18 +63,12 @@ static Atom getSupportedAtom(Atom* supportedAtoms,
|
||||
//
|
||||
static void detectEWMH(void)
|
||||
{
|
||||
// First we read the _NET_SUPPORTING_WM_CHECK property on the root window
|
||||
Window* windowFromRoot = NULL;
|
||||
Window* windowFromChild = NULL;
|
||||
|
||||
// First we need a couple of atoms
|
||||
const Atom supportingWmCheck =
|
||||
XInternAtom(_glfw.x11.display, "_NET_SUPPORTING_WM_CHECK", False);
|
||||
const Atom wmSupported =
|
||||
XInternAtom(_glfw.x11.display, "_NET_SUPPORTED", False);
|
||||
|
||||
// Then we look for the _NET_SUPPORTING_WM_CHECK property of the root window
|
||||
if (!_glfwGetWindowPropertyX11(_glfw.x11.root,
|
||||
supportingWmCheck,
|
||||
_glfw.x11.NET_SUPPORTING_WM_CHECK,
|
||||
XA_WINDOW,
|
||||
(unsigned char**) &windowFromRoot))
|
||||
{
|
||||
@@ -82,10 +77,12 @@ static void detectEWMH(void)
|
||||
|
||||
_glfwGrabErrorHandlerX11();
|
||||
|
||||
// It should be the ID of a child window (of the root)
|
||||
// Then we look for the same property on the child window
|
||||
// If it exists, it should be the XID of a top-level window
|
||||
// Then we look for the same property on that window
|
||||
|
||||
Window* windowFromChild = NULL;
|
||||
if (!_glfwGetWindowPropertyX11(*windowFromRoot,
|
||||
supportingWmCheck,
|
||||
_glfw.x11.NET_SUPPORTING_WM_CHECK,
|
||||
XA_WINDOW,
|
||||
(unsigned char**) &windowFromChild))
|
||||
{
|
||||
@@ -95,7 +92,7 @@ static void detectEWMH(void)
|
||||
|
||||
_glfwReleaseErrorHandlerX11();
|
||||
|
||||
// It should be the ID of that same child window
|
||||
// If the property exists, it should contain the XID of the window
|
||||
if (*windowFromRoot != *windowFromChild)
|
||||
{
|
||||
XFree(windowFromRoot);
|
||||
@@ -107,18 +104,20 @@ static void detectEWMH(void)
|
||||
XFree(windowFromChild);
|
||||
|
||||
// We are now fairly sure that an EWMH-compliant window manager is running
|
||||
// We can now start querying the WM about what features it supports by
|
||||
// looking in the _NET_SUPPORTED property on the root window
|
||||
// It should contain a list of supported EWMH protocol and state atoms
|
||||
|
||||
Atom* supportedAtoms;
|
||||
unsigned long atomCount;
|
||||
|
||||
// Now we need to check the _NET_SUPPORTED property of the root window
|
||||
// It should be a list of supported WM protocol and state atoms
|
||||
atomCount = _glfwGetWindowPropertyX11(_glfw.x11.root,
|
||||
wmSupported,
|
||||
Atom* supportedAtoms = NULL;
|
||||
const unsigned long atomCount = _glfwGetWindowPropertyX11(_glfw.x11.root,
|
||||
_glfw.x11.NET_SUPPORTED,
|
||||
XA_ATOM,
|
||||
(unsigned char**) &supportedAtoms);
|
||||
if (!supportedAtoms)
|
||||
return;
|
||||
|
||||
// See which of the atoms we support that are supported by the WM
|
||||
|
||||
_glfw.x11.NET_WM_STATE =
|
||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE");
|
||||
_glfw.x11.NET_WM_STATE_ABOVE =
|
||||
@@ -148,8 +147,7 @@ static void detectEWMH(void)
|
||||
_glfw.x11.NET_REQUEST_FRAME_EXTENTS =
|
||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_REQUEST_FRAME_EXTENTS");
|
||||
|
||||
if (supportedAtoms)
|
||||
XFree(supportedAtoms);
|
||||
XFree(supportedAtoms);
|
||||
}
|
||||
|
||||
// Look for and initialize supported X11 extensions
|
||||
@@ -159,14 +157,10 @@ static bool initExtensions(void)
|
||||
_glfw.x11.vidmode.handle = _glfw_dlopen("libXxf86vm.so.1");
|
||||
if (_glfw.x11.vidmode.handle)
|
||||
{
|
||||
_glfw.x11.vidmode.QueryExtension = (PFN_XF86VidModeQueryExtension)
|
||||
_glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeQueryExtension");
|
||||
_glfw.x11.vidmode.GetGammaRamp = (PFN_XF86VidModeGetGammaRamp)
|
||||
_glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRamp");
|
||||
_glfw.x11.vidmode.SetGammaRamp = (PFN_XF86VidModeSetGammaRamp)
|
||||
_glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeSetGammaRamp");
|
||||
_glfw.x11.vidmode.GetGammaRampSize = (PFN_XF86VidModeGetGammaRampSize)
|
||||
_glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRampSize");
|
||||
glfw_dlsym(_glfw.x11.vidmode.QueryExtension, _glfw.x11.vidmode.handle, "XF86VidModeQueryExtension");
|
||||
glfw_dlsym(_glfw.x11.vidmode.GetGammaRamp, _glfw.x11.vidmode.handle, "XF86VidModeGetGammaRamp");
|
||||
glfw_dlsym(_glfw.x11.vidmode.SetGammaRamp, _glfw.x11.vidmode.handle, "XF86VidModeSetGammaRamp");
|
||||
glfw_dlsym(_glfw.x11.vidmode.GetGammaRampSize, _glfw.x11.vidmode.handle, "XF86VidModeGetGammaRampSize");
|
||||
|
||||
_glfw.x11.vidmode.available =
|
||||
XF86VidModeQueryExtension(_glfw.x11.display,
|
||||
@@ -181,10 +175,8 @@ static bool initExtensions(void)
|
||||
#endif
|
||||
if (_glfw.x11.xi.handle)
|
||||
{
|
||||
_glfw.x11.xi.QueryVersion = (PFN_XIQueryVersion)
|
||||
_glfw_dlsym(_glfw.x11.xi.handle, "XIQueryVersion");
|
||||
_glfw.x11.xi.SelectEvents = (PFN_XISelectEvents)
|
||||
_glfw_dlsym(_glfw.x11.xi.handle, "XISelectEvents");
|
||||
glfw_dlsym(_glfw.x11.xi.QueryVersion, _glfw.x11.xi.handle, "XIQueryVersion");
|
||||
glfw_dlsym(_glfw.x11.xi.SelectEvents, _glfw.x11.xi.handle, "XISelectEvents");
|
||||
|
||||
if (XQueryExtension(_glfw.x11.display,
|
||||
"XInputExtension",
|
||||
@@ -211,42 +203,24 @@ static bool initExtensions(void)
|
||||
#endif
|
||||
if (_glfw.x11.randr.handle)
|
||||
{
|
||||
_glfw.x11.randr.AllocGamma = (PFN_XRRAllocGamma)
|
||||
_glfw_dlsym(_glfw.x11.randr.handle, "XRRAllocGamma");
|
||||
_glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma)
|
||||
_glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeGamma");
|
||||
_glfw.x11.randr.FreeCrtcInfo = (PFN_XRRFreeCrtcInfo)
|
||||
_glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeCrtcInfo");
|
||||
_glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma)
|
||||
_glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeGamma");
|
||||
_glfw.x11.randr.FreeOutputInfo = (PFN_XRRFreeOutputInfo)
|
||||
_glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeOutputInfo");
|
||||
_glfw.x11.randr.FreeScreenResources = (PFN_XRRFreeScreenResources)
|
||||
_glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeScreenResources");
|
||||
_glfw.x11.randr.GetCrtcGamma = (PFN_XRRGetCrtcGamma)
|
||||
_glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGamma");
|
||||
_glfw.x11.randr.GetCrtcGammaSize = (PFN_XRRGetCrtcGammaSize)
|
||||
_glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGammaSize");
|
||||
_glfw.x11.randr.GetCrtcInfo = (PFN_XRRGetCrtcInfo)
|
||||
_glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcInfo");
|
||||
_glfw.x11.randr.GetOutputInfo = (PFN_XRRGetOutputInfo)
|
||||
_glfw_dlsym(_glfw.x11.randr.handle, "XRRGetOutputInfo");
|
||||
_glfw.x11.randr.GetOutputPrimary = (PFN_XRRGetOutputPrimary)
|
||||
_glfw_dlsym(_glfw.x11.randr.handle, "XRRGetOutputPrimary");
|
||||
_glfw.x11.randr.GetScreenResourcesCurrent = (PFN_XRRGetScreenResourcesCurrent)
|
||||
_glfw_dlsym(_glfw.x11.randr.handle, "XRRGetScreenResourcesCurrent");
|
||||
_glfw.x11.randr.QueryExtension = (PFN_XRRQueryExtension)
|
||||
_glfw_dlsym(_glfw.x11.randr.handle, "XRRQueryExtension");
|
||||
_glfw.x11.randr.QueryVersion = (PFN_XRRQueryVersion)
|
||||
_glfw_dlsym(_glfw.x11.randr.handle, "XRRQueryVersion");
|
||||
_glfw.x11.randr.SelectInput = (PFN_XRRSelectInput)
|
||||
_glfw_dlsym(_glfw.x11.randr.handle, "XRRSelectInput");
|
||||
_glfw.x11.randr.SetCrtcConfig = (PFN_XRRSetCrtcConfig)
|
||||
_glfw_dlsym(_glfw.x11.randr.handle, "XRRSetCrtcConfig");
|
||||
_glfw.x11.randr.SetCrtcGamma = (PFN_XRRSetCrtcGamma)
|
||||
_glfw_dlsym(_glfw.x11.randr.handle, "XRRSetCrtcGamma");
|
||||
_glfw.x11.randr.UpdateConfiguration = (PFN_XRRUpdateConfiguration)
|
||||
_glfw_dlsym(_glfw.x11.randr.handle, "XRRUpdateConfiguration");
|
||||
glfw_dlsym(_glfw.x11.randr.AllocGamma, _glfw.x11.randr.handle, "XRRAllocGamma");
|
||||
glfw_dlsym(_glfw.x11.randr.FreeGamma, _glfw.x11.randr.handle, "XRRFreeGamma");
|
||||
glfw_dlsym(_glfw.x11.randr.FreeCrtcInfo, _glfw.x11.randr.handle, "XRRFreeCrtcInfo");
|
||||
glfw_dlsym(_glfw.x11.randr.FreeGamma, _glfw.x11.randr.handle, "XRRFreeGamma");
|
||||
glfw_dlsym(_glfw.x11.randr.FreeOutputInfo, _glfw.x11.randr.handle, "XRRFreeOutputInfo");
|
||||
glfw_dlsym(_glfw.x11.randr.FreeScreenResources, _glfw.x11.randr.handle, "XRRFreeScreenResources");
|
||||
glfw_dlsym(_glfw.x11.randr.GetCrtcGamma, _glfw.x11.randr.handle, "XRRGetCrtcGamma");
|
||||
glfw_dlsym(_glfw.x11.randr.GetCrtcGammaSize, _glfw.x11.randr.handle, "XRRGetCrtcGammaSize");
|
||||
glfw_dlsym(_glfw.x11.randr.GetCrtcInfo, _glfw.x11.randr.handle, "XRRGetCrtcInfo");
|
||||
glfw_dlsym(_glfw.x11.randr.GetOutputInfo, _glfw.x11.randr.handle, "XRRGetOutputInfo");
|
||||
glfw_dlsym(_glfw.x11.randr.GetOutputPrimary, _glfw.x11.randr.handle, "XRRGetOutputPrimary");
|
||||
glfw_dlsym(_glfw.x11.randr.GetScreenResourcesCurrent, _glfw.x11.randr.handle, "XRRGetScreenResourcesCurrent");
|
||||
glfw_dlsym(_glfw.x11.randr.QueryExtension, _glfw.x11.randr.handle, "XRRQueryExtension");
|
||||
glfw_dlsym(_glfw.x11.randr.QueryVersion, _glfw.x11.randr.handle, "XRRQueryVersion");
|
||||
glfw_dlsym(_glfw.x11.randr.SelectInput, _glfw.x11.randr.handle, "XRRSelectInput");
|
||||
glfw_dlsym(_glfw.x11.randr.SetCrtcConfig, _glfw.x11.randr.handle, "XRRSetCrtcConfig");
|
||||
glfw_dlsym(_glfw.x11.randr.SetCrtcGamma, _glfw.x11.randr.handle, "XRRSetCrtcGamma");
|
||||
glfw_dlsym(_glfw.x11.randr.UpdateConfiguration, _glfw.x11.randr.handle, "XRRUpdateConfiguration");
|
||||
|
||||
if (XRRQueryExtension(_glfw.x11.display,
|
||||
&_glfw.x11.randr.eventBase,
|
||||
@@ -303,12 +277,9 @@ static bool initExtensions(void)
|
||||
#endif
|
||||
if (_glfw.x11.xcursor.handle)
|
||||
{
|
||||
_glfw.x11.xcursor.ImageCreate = (PFN_XcursorImageCreate)
|
||||
_glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageCreate");
|
||||
_glfw.x11.xcursor.ImageDestroy = (PFN_XcursorImageDestroy)
|
||||
_glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageDestroy");
|
||||
_glfw.x11.xcursor.ImageLoadCursor = (PFN_XcursorImageLoadCursor)
|
||||
_glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageLoadCursor");
|
||||
glfw_dlsym(_glfw.x11.xcursor.ImageCreate, _glfw.x11.xcursor.handle, "XcursorImageCreate");
|
||||
glfw_dlsym(_glfw.x11.xcursor.ImageDestroy, _glfw.x11.xcursor.handle, "XcursorImageDestroy");
|
||||
glfw_dlsym(_glfw.x11.xcursor.ImageLoadCursor, _glfw.x11.xcursor.handle, "XcursorImageLoadCursor");
|
||||
}
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
@@ -318,12 +289,9 @@ static bool initExtensions(void)
|
||||
#endif
|
||||
if (_glfw.x11.xinerama.handle)
|
||||
{
|
||||
_glfw.x11.xinerama.IsActive = (PFN_XineramaIsActive)
|
||||
_glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaIsActive");
|
||||
_glfw.x11.xinerama.QueryExtension = (PFN_XineramaQueryExtension)
|
||||
_glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaQueryExtension");
|
||||
_glfw.x11.xinerama.QueryScreens = (PFN_XineramaQueryScreens)
|
||||
_glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaQueryScreens");
|
||||
glfw_dlsym(_glfw.x11.xinerama.IsActive, _glfw.x11.xinerama.handle, "XineramaIsActive");
|
||||
glfw_dlsym(_glfw.x11.xinerama.QueryExtension, _glfw.x11.xinerama.handle, "XineramaQueryExtension");
|
||||
glfw_dlsym(_glfw.x11.xinerama.QueryScreens, _glfw.x11.xinerama.handle, "XineramaQueryScreens");
|
||||
|
||||
if (XineramaQueryExtension(_glfw.x11.display,
|
||||
&_glfw.x11.xinerama.major,
|
||||
@@ -341,12 +309,9 @@ static bool initExtensions(void)
|
||||
#endif
|
||||
if (_glfw.x11.xrender.handle)
|
||||
{
|
||||
_glfw.x11.xrender.QueryExtension = (PFN_XRenderQueryExtension)
|
||||
_glfw_dlsym(_glfw.x11.xrender.handle, "XRenderQueryExtension");
|
||||
_glfw.x11.xrender.QueryVersion = (PFN_XRenderQueryVersion)
|
||||
_glfw_dlsym(_glfw.x11.xrender.handle, "XRenderQueryVersion");
|
||||
_glfw.x11.xrender.FindVisualFormat = (PFN_XRenderFindVisualFormat)
|
||||
_glfw_dlsym(_glfw.x11.xrender.handle, "XRenderFindVisualFormat");
|
||||
glfw_dlsym(_glfw.x11.xrender.QueryExtension, _glfw.x11.xrender.handle, "XRenderQueryExtension");
|
||||
glfw_dlsym(_glfw.x11.xrender.QueryVersion, _glfw.x11.xrender.handle, "XRenderQueryVersion");
|
||||
glfw_dlsym(_glfw.x11.xrender.FindVisualFormat, _glfw.x11.xrender.handle, "XRenderFindVisualFormat");
|
||||
|
||||
if (XRenderQueryExtension(_glfw.x11.display,
|
||||
&_glfw.x11.xrender.errorBase,
|
||||
@@ -387,9 +352,6 @@ static bool initExtensions(void)
|
||||
if (!glfw_xkb_update_x11_keyboard_id(&_glfw.x11.xkb)) return false;
|
||||
if (!glfw_xkb_compile_keymap(&_glfw.x11.xkb, NULL)) return false;
|
||||
|
||||
// Detect whether an EWMH-conformant window manager is running
|
||||
detectEWMH();
|
||||
|
||||
// String format atoms
|
||||
_glfw.x11.NULL_ = XInternAtom(_glfw.x11.display, "NULL", False);
|
||||
_glfw.x11.UTF8_STRING = XInternAtom(_glfw.x11.display, "UTF8_STRING", False);
|
||||
@@ -433,6 +395,10 @@ static bool initExtensions(void)
|
||||
XInternAtom(_glfw.x11.display, "WM_STATE", False);
|
||||
_glfw.x11.WM_DELETE_WINDOW =
|
||||
XInternAtom(_glfw.x11.display, "WM_DELETE_WINDOW", False);
|
||||
_glfw.x11.NET_SUPPORTED =
|
||||
XInternAtom(_glfw.x11.display, "_NET_SUPPORTED", False);
|
||||
_glfw.x11.NET_SUPPORTING_WM_CHECK =
|
||||
XInternAtom(_glfw.x11.display, "_NET_SUPPORTING_WM_CHECK", False);
|
||||
_glfw.x11.NET_WM_ICON =
|
||||
XInternAtom(_glfw.x11.display, "_NET_WM_ICON", False);
|
||||
_glfw.x11.NET_WM_PING =
|
||||
@@ -457,6 +423,9 @@ static bool initExtensions(void)
|
||||
_glfw.x11.NET_WM_CM_Sx = XInternAtom(_glfw.x11.display, name, False);
|
||||
}
|
||||
|
||||
// Detect whether an EWMH-conformant window manager is running
|
||||
detectEWMH();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -536,7 +505,7 @@ static Window createHelperWindow(void)
|
||||
|
||||
// X error handler
|
||||
//
|
||||
static int errorHandler(Display *display, XErrorEvent* event)
|
||||
static int errorHandler(Display *display UNUSED, XErrorEvent* event)
|
||||
{
|
||||
_glfw.x11.errorCode = event->error_code;
|
||||
return 0;
|
||||
@@ -611,6 +580,7 @@ Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot)
|
||||
return cursor;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -620,13 +590,6 @@ int _glfwPlatformInit(void)
|
||||
XInitThreads();
|
||||
XrmInitialize();
|
||||
|
||||
if (pipe2(_glfw.x11.eventLoopData.wakeupFds, O_CLOEXEC | O_NONBLOCK) != 0)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"X11: failed to create self pipe");
|
||||
return false;
|
||||
}
|
||||
|
||||
_glfw.x11.display = XOpenDisplay(NULL);
|
||||
if (!_glfw.x11.display)
|
||||
{
|
||||
@@ -645,7 +608,10 @@ int _glfwPlatformInit(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
initPollData(&_glfw.x11.eventLoopData, _glfw.x11.eventLoopData.wakeupFds[0], ConnectionNumber(_glfw.x11.display));
|
||||
if (!initPollData(&_glfw.x11.eventLoopData, ConnectionNumber(_glfw.x11.display))) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"X11: Failed to initialize event loop data");
|
||||
}
|
||||
glfw_dbus_init(&_glfw.x11.dbus, &_glfw.x11.eventLoopData);
|
||||
|
||||
_glfw.x11.screen = DefaultScreen(_glfw.x11.display);
|
||||
@@ -754,7 +720,7 @@ void _glfwPlatformTerminate(void)
|
||||
#if defined(__linux__)
|
||||
_glfwTerminateJoysticksLinux();
|
||||
#endif
|
||||
closeFds(_glfw.x11.eventLoopData.wakeupFds, sizeof(_glfw.x11.eventLoopData.wakeupFds)/sizeof(_glfw.x11.eventLoopData.wakeupFds[0]));
|
||||
finalizePollData(&_glfw.x11.eventLoopData);
|
||||
}
|
||||
|
||||
const char* _glfwPlatformGetVersionString(void)
|
||||
|
||||
94
glfw/x11_monitor.c
vendored
94
glfw/x11_monitor.c
vendored
@@ -2,7 +2,7 @@
|
||||
// GLFW 3.3 X11 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2019 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
|
||||
@@ -24,6 +24,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@@ -54,9 +56,7 @@ static int calculateRefreshRate(const XRRModeInfo* mi)
|
||||
//
|
||||
static const XRRModeInfo* getModeInfo(const XRRScreenResources* sr, RRMode id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sr->nmode; i++)
|
||||
for (int i = 0; i < sr->nmode; i++)
|
||||
{
|
||||
if (sr->modes[i].id == id)
|
||||
return sr->modes + i;
|
||||
@@ -102,7 +102,7 @@ void _glfwPollMonitorsX11(void)
|
||||
{
|
||||
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
|
||||
{
|
||||
int i, j, disconnectedCount, screenCount = 0;
|
||||
int disconnectedCount, screenCount = 0;
|
||||
_GLFWmonitor** disconnected = NULL;
|
||||
XineramaScreenInfo* screens = NULL;
|
||||
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display,
|
||||
@@ -122,14 +122,11 @@ void _glfwPollMonitorsX11(void)
|
||||
_glfw.monitorCount * sizeof(_GLFWmonitor*));
|
||||
}
|
||||
|
||||
for (i = 0; i < sr->noutput; i++)
|
||||
for (int i = 0; i < sr->noutput; i++)
|
||||
{
|
||||
int type, widthMM, heightMM;
|
||||
XRROutputInfo* oi;
|
||||
XRRCrtcInfo* ci;
|
||||
_GLFWmonitor* monitor;
|
||||
int j, type, widthMM, heightMM;
|
||||
|
||||
oi = XRRGetOutputInfo(_glfw.x11.display, sr, sr->outputs[i]);
|
||||
XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, sr->outputs[i]);
|
||||
if (oi->connection != RR_Connected || oi->crtc == None)
|
||||
{
|
||||
XRRFreeOutputInfo(oi);
|
||||
@@ -152,7 +149,7 @@ void _glfwPollMonitorsX11(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, oi->crtc);
|
||||
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, oi->crtc);
|
||||
if (!ci)
|
||||
{
|
||||
XRRFreeOutputInfo(oi);
|
||||
@@ -169,7 +166,7 @@ void _glfwPollMonitorsX11(void)
|
||||
heightMM = oi->mm_height;
|
||||
}
|
||||
|
||||
monitor = _glfwAllocMonitor(oi->name, widthMM, heightMM);
|
||||
_GLFWmonitor* monitor = _glfwAllocMonitor(oi->name, widthMM, heightMM);
|
||||
monitor->x11.output = sr->outputs[i];
|
||||
monitor->x11.crtc = oi->crtc;
|
||||
|
||||
@@ -177,8 +174,8 @@ void _glfwPollMonitorsX11(void)
|
||||
{
|
||||
if (screens[j].x_org == ci->x &&
|
||||
screens[j].y_org == ci->y &&
|
||||
screens[j].width == ci->width &&
|
||||
screens[j].height == ci->height)
|
||||
screens[j].width == (short int)ci->width &&
|
||||
screens[j].height == (short int)ci->height)
|
||||
{
|
||||
monitor->x11.index = j;
|
||||
break;
|
||||
@@ -201,7 +198,7 @@ void _glfwPollMonitorsX11(void)
|
||||
if (screens)
|
||||
XFree(screens);
|
||||
|
||||
for (i = 0; i < disconnectedCount; i++)
|
||||
for (int i = 0; i < disconnectedCount; i++)
|
||||
{
|
||||
if (disconnected[i])
|
||||
_glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0);
|
||||
@@ -226,24 +223,19 @@ 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);
|
||||
const GLFWvidmode* best = _glfwChooseVideoMode(monitor, desired);
|
||||
_glfwPlatformGetVideoMode(monitor, ¤t);
|
||||
if (_glfwCompareVideoModes(¤t, 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);
|
||||
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
||||
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
||||
XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);
|
||||
|
||||
for (i = 0; i < oi->nmode; i++)
|
||||
for (int i = 0; i < oi->nmode; i++)
|
||||
{
|
||||
const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]);
|
||||
if (!modeIsGood(mi))
|
||||
@@ -284,14 +276,11 @@ 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);
|
||||
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
||||
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
||||
|
||||
XRRSetCrtcConfig(_glfw.x11.display,
|
||||
sr, monitor->x11.crtc,
|
||||
@@ -314,7 +303,7 @@ void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor)
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
|
||||
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -322,11 +311,9 @@ 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);
|
||||
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
||||
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
||||
if (ci)
|
||||
{
|
||||
if (xpos)
|
||||
@@ -340,7 +327,7 @@ void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
|
||||
void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor UNUSED,
|
||||
float* xscale, float* yscale)
|
||||
{
|
||||
if (xscale)
|
||||
@@ -349,17 +336,15 @@ void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
|
||||
*yscale = _glfw.x11.contentScaleY;
|
||||
}
|
||||
|
||||
void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int *width, int *height)
|
||||
void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int* width, int* height)
|
||||
{
|
||||
int areaX = 0, areaY = 0, areaWidth = 0, areaHeight = 0;
|
||||
|
||||
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);
|
||||
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
||||
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
||||
|
||||
areaX = ci->x;
|
||||
areaY = ci->y;
|
||||
@@ -451,24 +436,20 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
|
||||
|
||||
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);
|
||||
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
||||
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
||||
XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);
|
||||
|
||||
result = calloc(oi->nmode, sizeof(GLFWvidmode));
|
||||
|
||||
for (i = 0; i < oi->nmode; i++)
|
||||
for (int i = 0; i < oi->nmode; i++)
|
||||
{
|
||||
const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]);
|
||||
if (!modeIsGood(mi))
|
||||
continue;
|
||||
|
||||
const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci);
|
||||
int j;
|
||||
|
||||
for (j = 0; j < *count; j++)
|
||||
{
|
||||
@@ -502,11 +483,9 @@ 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);
|
||||
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
||||
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
||||
|
||||
if (ci) {
|
||||
const XRRModeInfo* mi = getModeInfo(sr, ci->mode);
|
||||
@@ -570,7 +549,7 @@ 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)
|
||||
if (XRRGetCrtcGammaSize(_glfw.x11.display, monitor->x11.crtc) != (int)ramp->size)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"X11: Gamma ramp size must match current ramp size");
|
||||
@@ -595,7 +574,8 @@ void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
|
||||
(unsigned short*) ramp->green,
|
||||
(unsigned short*) ramp->blue);
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"X11: Gamma ramp access not supported by server");
|
||||
}
|
||||
|
||||
25
glfw/x11_platform.h
vendored
25
glfw/x11_platform.h
vendored
@@ -2,7 +2,7 @@
|
||||
// GLFW 3.3 X11 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2019 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
|
||||
@@ -182,11 +182,11 @@ typedef struct _GLFWwindowX11
|
||||
Colormap colormap;
|
||||
Window handle;
|
||||
|
||||
bool iconified;
|
||||
bool maximized;
|
||||
bool iconified;
|
||||
bool maximized;
|
||||
|
||||
// Whether the visual supports framebuffer transparency
|
||||
bool transparent;
|
||||
bool transparent;
|
||||
|
||||
// Cached position and size used to filter out duplicate events
|
||||
int width, height;
|
||||
@@ -227,6 +227,8 @@ typedef struct _GLFWlibraryX11
|
||||
_GLFWwindow* disabledCursorWindow;
|
||||
|
||||
// Window manager atoms
|
||||
Atom NET_SUPPORTED;
|
||||
Atom NET_SUPPORTING_WM_CHECK;
|
||||
Atom WM_PROTOCOLS;
|
||||
Atom WM_STATE;
|
||||
Atom WM_DELETE_WINDOW;
|
||||
@@ -284,14 +286,14 @@ typedef struct _GLFWlibraryX11
|
||||
Atom RESOURCE_MANAGER;
|
||||
|
||||
struct {
|
||||
bool available;
|
||||
bool available;
|
||||
void* handle;
|
||||
int eventBase;
|
||||
int errorBase;
|
||||
int major;
|
||||
int minor;
|
||||
bool gammaBroken;
|
||||
bool monitorBroken;
|
||||
bool gammaBroken;
|
||||
bool monitorBroken;
|
||||
PFN_XRRAllocGamma AllocGamma;
|
||||
PFN_XRRFreeCrtcInfo FreeCrtcInfo;
|
||||
PFN_XRRFreeGamma FreeGamma;
|
||||
@@ -336,7 +338,7 @@ typedef struct _GLFWlibraryX11
|
||||
} xcursor;
|
||||
|
||||
struct {
|
||||
bool available;
|
||||
bool available;
|
||||
void* handle;
|
||||
int major;
|
||||
int minor;
|
||||
@@ -346,7 +348,7 @@ typedef struct _GLFWlibraryX11
|
||||
} xinerama;
|
||||
|
||||
struct {
|
||||
bool available;
|
||||
bool available;
|
||||
void* handle;
|
||||
int eventBase;
|
||||
int errorBase;
|
||||
@@ -357,7 +359,7 @@ typedef struct _GLFWlibraryX11
|
||||
} vidmode;
|
||||
|
||||
struct {
|
||||
bool available;
|
||||
bool available;
|
||||
void* handle;
|
||||
int majorOpcode;
|
||||
int eventBase;
|
||||
@@ -369,7 +371,7 @@ typedef struct _GLFWlibraryX11
|
||||
} xi;
|
||||
|
||||
struct {
|
||||
bool available;
|
||||
bool available;
|
||||
void* handle;
|
||||
int major;
|
||||
int minor;
|
||||
@@ -406,6 +408,7 @@ typedef struct _GLFWcursorX11
|
||||
|
||||
} _GLFWcursorX11;
|
||||
|
||||
|
||||
void _glfwPollMonitorsX11(void);
|
||||
void _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired);
|
||||
void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor);
|
||||
|
||||
120
glfw/x11_window.c
vendored
120
glfw/x11_window.c
vendored
@@ -2,7 +2,7 @@
|
||||
// GLFW 3.3 X11 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
// Copyright (c) 2006-2019 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
|
||||
@@ -24,6 +24,8 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include "internal.h"
|
||||
@@ -51,6 +53,7 @@
|
||||
|
||||
#define _GLFW_XDND_VERSION 5
|
||||
|
||||
|
||||
// Wait for data to arrive using poll
|
||||
// This avoids blocking other threads via the per-display Xlib lock that also
|
||||
// covers GLX functions
|
||||
@@ -70,6 +73,7 @@ handleEvents(double timeout) {
|
||||
glfw_ibus_dispatch(&_glfw.x11.xkb.ibus);
|
||||
glfw_dbus_session_bus_dispatch();
|
||||
EVDBG("other dispatch done");
|
||||
if (_glfw.x11.eventLoopData.wakeup_fd_ready) check_for_wakeup_events(&_glfw.x11.eventLoopData);
|
||||
}
|
||||
|
||||
static bool
|
||||
@@ -138,7 +142,7 @@ static int getWindowState(_GLFWwindow* window)
|
||||
|
||||
// Returns whether the event is a selection event
|
||||
//
|
||||
static Bool isSelectionEvent(Display* display, XEvent* event, XPointer pointer)
|
||||
static Bool isSelectionEvent(Display* display UNUSED, XEvent* event, XPointer pointer UNUSED)
|
||||
{
|
||||
if (event->xany.window != _glfw.x11.helperWindowHandle)
|
||||
return False;
|
||||
@@ -150,7 +154,7 @@ static Bool isSelectionEvent(Display* display, XEvent* event, XPointer pointer)
|
||||
|
||||
// Returns whether it is a _NET_FRAME_EXTENTS event for the specified window
|
||||
//
|
||||
static Bool isFrameExtentsEvent(Display* display, XEvent* event, XPointer pointer)
|
||||
static Bool isFrameExtentsEvent(Display* display UNUSED, XEvent* event, XPointer pointer)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) pointer;
|
||||
return event->type == PropertyNotify &&
|
||||
@@ -161,7 +165,7 @@ static Bool isFrameExtentsEvent(Display* display, XEvent* event, XPointer pointe
|
||||
|
||||
// Returns whether it is a property event for the specified selection transfer
|
||||
//
|
||||
static Bool isSelPropNewValueNotify(Display* display, XEvent* event, XPointer pointer)
|
||||
static Bool isSelPropNewValueNotify(Display* display UNUSED, XEvent* event, XPointer pointer)
|
||||
{
|
||||
XEvent* notification = (XEvent*) pointer;
|
||||
return event->type == PropertyNotify &&
|
||||
@@ -197,10 +201,7 @@ static int translateState(int state)
|
||||
static void sendEventToWM(_GLFWwindow* window, Atom type,
|
||||
long a, long b, long c, long d, long e)
|
||||
{
|
||||
XEvent event;
|
||||
memset(&event, 0, sizeof(event));
|
||||
|
||||
event.type = ClientMessage;
|
||||
XEvent event = { ClientMessage };
|
||||
event.xclient.window = window->x11.handle;
|
||||
event.xclient.format = 32; // Data is 32-bit longs
|
||||
event.xclient.message_type = type;
|
||||
@@ -328,8 +329,7 @@ set_fullscreen(_GLFWwindow *window, bool on) {
|
||||
}
|
||||
|
||||
bool
|
||||
_glfwPlatformToggleFullscreen(_GLFWwindow *window, unsigned int flags) {
|
||||
(void) flags;
|
||||
_glfwPlatformToggleFullscreen(_GLFWwindow *window, unsigned int flags UNUSED) {
|
||||
bool already_fullscreen = is_window_fullscreen(window);
|
||||
set_fullscreen(window, !already_fullscreen);
|
||||
return !already_fullscreen;
|
||||
@@ -841,11 +841,8 @@ static void handleSelectionRequest(XEvent* event)
|
||||
{
|
||||
const XSelectionRequestEvent* request = &event->xselectionrequest;
|
||||
|
||||
XEvent reply;
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
|
||||
XEvent reply = { SelectionNotify };
|
||||
reply.xselection.property = writeTargetToProperty(request);
|
||||
reply.xselection.type = SelectionNotify;
|
||||
reply.xselection.display = request->display;
|
||||
reply.xselection.requestor = request->requestor;
|
||||
reply.xselection.selection = request->selection;
|
||||
@@ -857,7 +854,6 @@ static void handleSelectionRequest(XEvent* event)
|
||||
|
||||
static const char* getSelectionString(Atom selection)
|
||||
{
|
||||
size_t i;
|
||||
char** selectionString = NULL;
|
||||
const Atom targets[] = { _glfw.x11.UTF8_STRING, XA_STRING };
|
||||
const size_t targetCount = sizeof(targets) / sizeof(targets[0]);
|
||||
@@ -878,7 +874,7 @@ static const char* getSelectionString(Atom selection)
|
||||
free(*selectionString);
|
||||
*selectionString = NULL;
|
||||
|
||||
for (i = 0; i < targetCount; i++)
|
||||
for (size_t i = 0; i < targetCount; i++)
|
||||
{
|
||||
char* data;
|
||||
Atom actualType;
|
||||
@@ -1075,7 +1071,6 @@ static void onConfigChange(void)
|
||||
//
|
||||
static void processEvent(XEvent *event)
|
||||
{
|
||||
_GLFWwindow* window = NULL;
|
||||
static bool keymap_dirty = false;
|
||||
#define UPDATE_KEYMAP_IF_NEEDED if (keymap_dirty) { keymap_dirty = false; glfw_xkb_compile_keymap(&_glfw.x11.xkb, NULL); }
|
||||
|
||||
@@ -1170,6 +1165,7 @@ static void processEvent(XEvent *event)
|
||||
return;
|
||||
}
|
||||
|
||||
_GLFWwindow* window = NULL;
|
||||
if (XFindContext(_glfw.x11.display,
|
||||
event->xany.window,
|
||||
_glfw.x11.context,
|
||||
@@ -1487,10 +1483,7 @@ static void processEvent(XEvent *event)
|
||||
}
|
||||
else if (_glfw.x11.xdnd.version >= 2)
|
||||
{
|
||||
XEvent reply;
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
|
||||
reply.type = ClientMessage;
|
||||
XEvent reply = { ClientMessage };
|
||||
reply.xclient.window = _glfw.x11.xdnd.source;
|
||||
reply.xclient.message_type = _glfw.x11.XdndFinished;
|
||||
reply.xclient.format = 32;
|
||||
@@ -1523,10 +1516,7 @@ static void processEvent(XEvent *event)
|
||||
|
||||
_glfwInputCursorPos(window, xpos, ypos);
|
||||
|
||||
XEvent reply;
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
|
||||
reply.type = ClientMessage;
|
||||
XEvent reply = { ClientMessage };
|
||||
reply.xclient.window = _glfw.x11.xdnd.source;
|
||||
reply.xclient.message_type = _glfw.x11.XdndStatus;
|
||||
reply.xclient.format = 32;
|
||||
@@ -1579,10 +1569,7 @@ static void processEvent(XEvent *event)
|
||||
|
||||
if (_glfw.x11.xdnd.version >= 2)
|
||||
{
|
||||
XEvent reply;
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
|
||||
reply.type = ClientMessage;
|
||||
XEvent reply = { ClientMessage };
|
||||
reply.xclient.window = _glfw.x11.xdnd.source;
|
||||
reply.xclient.message_type = _glfw.x11.XdndFinished;
|
||||
reply.xclient.format = 32;
|
||||
@@ -1601,9 +1588,6 @@ static void processEvent(XEvent *event)
|
||||
|
||||
case FocusIn:
|
||||
{
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
disableCursor(window);
|
||||
|
||||
if (event->xfocus.mode == NotifyGrab ||
|
||||
event->xfocus.mode == NotifyUngrab)
|
||||
{
|
||||
@@ -1612,15 +1596,15 @@ static void processEvent(XEvent *event)
|
||||
return;
|
||||
}
|
||||
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
disableCursor(window);
|
||||
|
||||
_glfwInputWindowFocus(window, true);
|
||||
return;
|
||||
}
|
||||
|
||||
case FocusOut:
|
||||
{
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
enableCursor(window);
|
||||
|
||||
if (event->xfocus.mode == NotifyGrab ||
|
||||
event->xfocus.mode == NotifyUngrab)
|
||||
{
|
||||
@@ -1629,6 +1613,9 @@ static void processEvent(XEvent *event)
|
||||
return;
|
||||
}
|
||||
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
enableCursor(window);
|
||||
|
||||
if (window->monitor && window->autoIconify)
|
||||
_glfwPlatformIconifyWindow(window);
|
||||
|
||||
@@ -2025,8 +2012,8 @@ void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
|
||||
int minwidth, int minheight,
|
||||
int maxwidth, int maxheight)
|
||||
int minwidth UNUSED, int minheight UNUSED,
|
||||
int maxwidth UNUSED, int maxheight UNUSED)
|
||||
{
|
||||
int width, height;
|
||||
_glfwPlatformGetWindowSize(window, &width, &height);
|
||||
@@ -2034,7 +2021,7 @@ void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
|
||||
XFlush(_glfw.x11.display);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom)
|
||||
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer UNUSED, int denom UNUSED)
|
||||
{
|
||||
int width, height;
|
||||
_glfwPlatformGetWindowSize(window, &width, &height);
|
||||
@@ -2107,7 +2094,7 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
||||
XFree(extents);
|
||||
}
|
||||
|
||||
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
|
||||
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window UNUSED,
|
||||
float* xscale, float* yscale)
|
||||
{
|
||||
if (xscale)
|
||||
@@ -2116,7 +2103,7 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
|
||||
*yscale = _glfw.x11.contentScaleY;
|
||||
}
|
||||
|
||||
double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window)
|
||||
double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED)
|
||||
{
|
||||
return 0.5;
|
||||
}
|
||||
@@ -2215,7 +2202,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
|
||||
_GLFWmonitor* monitor,
|
||||
int xpos, int ypos,
|
||||
int width, int height,
|
||||
int refreshRate)
|
||||
int refreshRate UNUSED)
|
||||
{
|
||||
if (window->monitor == monitor)
|
||||
{
|
||||
@@ -2245,13 +2232,14 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
|
||||
|
||||
if (window->monitor)
|
||||
{
|
||||
if (!_glfwPlatformWindowVisible(window))
|
||||
{
|
||||
XMapRaised(_glfw.x11.display, window->x11.handle);
|
||||
waitForVisibilityNotify(window);
|
||||
}
|
||||
updateWindowMode(window);
|
||||
acquireMonitor(window);
|
||||
if (!_glfwPlatformWindowVisible(window))
|
||||
{
|
||||
XMapRaised(_glfw.x11.display, window->x11.handle);
|
||||
waitForVisibilityNotify(window);
|
||||
}
|
||||
|
||||
updateWindowMode(window);
|
||||
acquireMonitor(window);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2272,7 +2260,7 @@ int _glfwPlatformWindowFocused(_GLFWwindow* window)
|
||||
return window->x11.handle == focused;
|
||||
}
|
||||
|
||||
int _glfwPlatformWindowOccluded(_GLFWwindow* window)
|
||||
int _glfwPlatformWindowOccluded(_GLFWwindow* window UNUSED)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -2294,10 +2282,13 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window)
|
||||
Atom* states;
|
||||
unsigned long i;
|
||||
bool maximized = false;
|
||||
|
||||
if (!_glfw.x11.NET_WM_STATE ||
|
||||
!_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT ||
|
||||
!_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ)
|
||||
!_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT ||
|
||||
!_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ)
|
||||
{
|
||||
return maximized;
|
||||
}
|
||||
const unsigned long count =
|
||||
_glfwGetWindowPropertyX11(window->x11.handle,
|
||||
_glfw.x11.NET_WM_STATE,
|
||||
@@ -2350,7 +2341,7 @@ int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
|
||||
return XGetSelectionOwner(_glfw.x11.display, _glfw.x11.NET_WM_CM_Sx) != None;
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, bool enabled)
|
||||
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, bool enabled UNUSED)
|
||||
{
|
||||
int width, height;
|
||||
_glfwPlatformGetWindowSize(window, &width, &height);
|
||||
@@ -2485,14 +2476,12 @@ void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity)
|
||||
}
|
||||
|
||||
static inline unsigned
|
||||
dispatch_x11_queued_events(void) {
|
||||
unsigned dispatched = 0;
|
||||
while (XQLength(_glfw.x11.display) > 0)
|
||||
{
|
||||
dispatch_x11_queued_events(int num_events) {
|
||||
unsigned dispatched = num_events > 0 ? num_events : 0;
|
||||
while (num_events-- > 0) {
|
||||
XEvent event;
|
||||
XNextEvent(_glfw.x11.display, &event);
|
||||
processEvent(&event);
|
||||
dispatched += 1;
|
||||
}
|
||||
return dispatched;
|
||||
}
|
||||
@@ -2503,10 +2492,9 @@ _glfwDispatchX11Events(void) {
|
||||
unsigned dispatched = 0;
|
||||
|
||||
#if defined(__linux__)
|
||||
_glfwDetectJoystickConnectionLinux();
|
||||
if (_glfw.hints.init.enableJoysticks) _glfwDetectJoystickConnectionLinux();
|
||||
#endif
|
||||
XPending(_glfw.x11.display);
|
||||
dispatched += dispatch_x11_queued_events();
|
||||
dispatched += dispatch_x11_queued_events(XEventsQueued(_glfw.x11.display, QueuedAfterFlush));
|
||||
|
||||
window = _glfw.x11.disabledCursorWindow;
|
||||
if (window)
|
||||
@@ -2524,8 +2512,10 @@ _glfwDispatchX11Events(void) {
|
||||
}
|
||||
|
||||
XFlush(_glfw.x11.display);
|
||||
// XFlush can cause events to be queued
|
||||
dispatched += dispatch_x11_queued_events();
|
||||
// XFlush can cause events to be queued, we dont use QueuedAfterFlush here
|
||||
// as something might have inserted events into the queue, but we want to guarantee
|
||||
// a flush.
|
||||
dispatched += dispatch_x11_queued_events(XEventsQueued(_glfw.x11.display, QueuedAlready));
|
||||
return dispatched;
|
||||
}
|
||||
|
||||
@@ -2549,7 +2539,7 @@ void _glfwPlatformWaitEventsTimeout(double timeout)
|
||||
|
||||
void _glfwPlatformPostEmptyEvent(void)
|
||||
{
|
||||
while (write(_glfw.x11.eventLoopData.wakeupFds[1], "w", 1) < 0 && errno == EINTR);
|
||||
wakeupEventLoop(&_glfw.x11.eventLoopData);
|
||||
}
|
||||
|
||||
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
|
||||
@@ -2608,7 +2598,7 @@ int _glfwPlatformGetKeyScancode(int key)
|
||||
|
||||
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||
const GLFWimage* image,
|
||||
int xhot, int yhot, int count)
|
||||
int xhot, int yhot, int count UNUSED)
|
||||
{
|
||||
cursor->x11.handle = _glfwCreateCursorX11(image, xhot, yhot);
|
||||
if (!cursor->x11.handle)
|
||||
@@ -2654,7 +2644,7 @@ void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
|
||||
XFreeCursor(_glfw.x11.display, cursor->x11.handle);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
||||
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor UNUSED)
|
||||
{
|
||||
if (window->cursorMode == GLFW_CURSOR_NORMAL)
|
||||
{
|
||||
|
||||
12
glfw/xkb_glfw.c
vendored
12
glfw/xkb_glfw.c
vendored
@@ -29,6 +29,7 @@
|
||||
#include <stdlib.h>
|
||||
#include "internal.h"
|
||||
#include "xkb_glfw.h"
|
||||
START_ALLOW_CASE_RANGE
|
||||
|
||||
#define debug(...) if (_glfw.hints.init.debugKeyboard) printf(__VA_ARGS__);
|
||||
|
||||
@@ -101,7 +102,7 @@ glfw_key_for_sym(xkb_keysym_t key) {
|
||||
#define S(f, t) case XKB_KEY_##f: return GLFW_KEY_##t
|
||||
#define F(f, t) S(f, t)
|
||||
#define R(s, e, gs, ...) case XKB_KEY_##s ... XKB_KEY_##e: return GLFW_KEY_##gs + key - XKB_KEY_##s
|
||||
#define D(s, e, gs, ...) R(s, e, gs)
|
||||
#define D(s, e, gs, ...) R(s, e, gs, __VA_ARGS__)
|
||||
map_key(key)
|
||||
S(KP_Up, UP);
|
||||
S(KP_Down, DOWN);
|
||||
@@ -115,7 +116,7 @@ glfw_key_for_sym(xkb_keysym_t key) {
|
||||
#undef D
|
||||
#undef R
|
||||
#undef S
|
||||
};
|
||||
}
|
||||
|
||||
xkb_keysym_t
|
||||
glfw_xkb_sym_for_key(int key) {
|
||||
@@ -133,6 +134,7 @@ glfw_xkb_sym_for_key(int key) {
|
||||
#undef R
|
||||
#undef S
|
||||
}
|
||||
END_ALLOW_CASE_RANGE
|
||||
|
||||
#ifdef _GLFW_X11
|
||||
|
||||
@@ -167,7 +169,7 @@ glfw_xkb_update_x11_keyboard_id(_GLFWXKBData *xkb) {
|
||||
if (conn) keymap = xkb_x11_keymap_new_from_device(xkb->context, conn, xkb->keyboard_device_id, XKB_KEYMAP_COMPILE_NO_FLAGS); \
|
||||
}
|
||||
|
||||
#define xkb_glfw_load_state(keymap, state, ...) {\
|
||||
#define xkb_glfw_load_state(keymap, state) {\
|
||||
xcb_connection_t* conn = XGetXCBConnection(_glfw.x11.display); \
|
||||
if (conn) state = xkb_x11_state_new_from_device(keymap, conn, xkb->keyboard_device_id); \
|
||||
}
|
||||
@@ -175,7 +177,7 @@ glfw_xkb_update_x11_keyboard_id(_GLFWXKBData *xkb) {
|
||||
#else
|
||||
|
||||
#define xkb_glfw_load_keymap(keymap, map_str) keymap = xkb_keymap_new_from_string(xkb->context, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, 0);
|
||||
#define xkb_glfw_load_state(keymap, state, ...) state = xkb_state_new(keymap);
|
||||
#define xkb_glfw_load_state(keymap, state) state = xkb_state_new(keymap);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -335,7 +337,7 @@ glfw_xkb_should_repeat(_GLFWXKBData *xkb, xkb_keycode_t scancode) {
|
||||
}
|
||||
|
||||
|
||||
static KeyEvent key_event = {};
|
||||
static KeyEvent key_event = {0};
|
||||
|
||||
static inline xkb_keysym_t
|
||||
compose_symbol(struct xkb_compose_state *composeState, xkb_keysym_t sym, int *compose_completed) {
|
||||
|
||||
@@ -25,9 +25,9 @@ static inline ssize_t ms_write(int fd, const void* buf, size_t count) { return _
|
||||
|
||||
static inline bool
|
||||
ensure_space(GlobalData *global, size_t sz) {
|
||||
if (global->output_sz < sz + global->output_pos) {
|
||||
if (global->output_sz < sz + global->output_pos || !global->output) {
|
||||
size_t before = global->output_sz;
|
||||
global->output_sz += MAX(sz, (64 * 1024));
|
||||
global->output_sz += MAX(sz, (64u * 1024u));
|
||||
global->output = realloc(global->output, sizeof(text_t) * global->output_sz);
|
||||
if (!global->output) {
|
||||
global->output_sz = before;
|
||||
|
||||
@@ -350,7 +350,9 @@ default=(?m)^\s*(.+)\s*$
|
||||
The regular expression to use when :option:`kitty +kitten hints --type`=regex.
|
||||
If you specify a group in the regular expression only the group
|
||||
will be matched. This allow you to match text ignoring a prefix/suffix, as
|
||||
needed. The default expression matches lines.
|
||||
needed. The default expression matches lines. To match text over
|
||||
multiple lines you should prefix the regular expression with :code:`(?ms)`,
|
||||
which turns on MULTILINE and DOTALL modes for the regex engine.
|
||||
|
||||
|
||||
--url-prefixes
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import importlib
|
||||
import os
|
||||
import sys
|
||||
from contextlib import suppress
|
||||
from functools import partial
|
||||
|
||||
aliases = {'url_hints': 'hints'}
|
||||
@@ -15,13 +16,18 @@ def resolved_kitten(k):
|
||||
return aliases.get(k, k).replace('-', '_')
|
||||
|
||||
|
||||
def path_to_custom_kitten(config_dir, kitten):
|
||||
path = os.path.expanduser(kitten)
|
||||
if not os.path.isabs(path):
|
||||
path = os.path.join(config_dir, path)
|
||||
path = os.path.abspath(path)
|
||||
return path
|
||||
|
||||
|
||||
def import_kitten_main_module(config_dir, kitten):
|
||||
if kitten.endswith('.py'):
|
||||
path_modified = False
|
||||
path = os.path.expanduser(kitten)
|
||||
if not os.path.isabs(path):
|
||||
path = os.path.join(config_dir, path)
|
||||
path = os.path.abspath(path)
|
||||
path = path_to_custom_kitten(config_dir, kitten)
|
||||
if os.path.dirname(path):
|
||||
sys.path.insert(0, os.path.dirname(path))
|
||||
path_modified = True
|
||||
@@ -90,12 +96,24 @@ def deserialize(output):
|
||||
|
||||
def run_kitten(kitten, run_name='__main__'):
|
||||
import runpy
|
||||
original_kitten_name = kitten
|
||||
kitten = resolved_kitten(kitten)
|
||||
set_debug(kitten)
|
||||
try:
|
||||
with suppress(ImportError):
|
||||
runpy.run_module('kittens.{}.main'.format(kitten), run_name=run_name)
|
||||
except ImportError:
|
||||
raise SystemExit('No kitten named {}'.format(kitten))
|
||||
return
|
||||
# Look for a custom kitten
|
||||
if not kitten.endswith('.py'):
|
||||
kitten += '.py'
|
||||
from kitty.constants import config_dir
|
||||
path = path_to_custom_kitten(config_dir, kitten)
|
||||
if not os.path.exists(path):
|
||||
print('Available builtin kittens:', file=sys.stderr)
|
||||
for kitten in all_kitten_names():
|
||||
print(kitten, file=sys.stderr)
|
||||
raise SystemExit('No kitten named {}'.format(original_kitten_name))
|
||||
m = runpy.run_path(path, init_globals={'sys': sys, 'os': os}, run_name='__run_kitten__')
|
||||
m['main'](sys.argv)
|
||||
|
||||
|
||||
def all_kitten_names():
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
@@ -93,6 +94,18 @@ def parse_ssh_args(args):
|
||||
return ssh_args, server_args, passthrough
|
||||
|
||||
|
||||
def quote(x):
|
||||
# we have to escape unbalanced quotes and other unparseable
|
||||
# args as they will break the shell script
|
||||
# But we do not want to quote things like * or 'echo hello'
|
||||
# See https://github.com/kovidgoyal/kitty/issues/1787
|
||||
try:
|
||||
shlex.split(x)
|
||||
except ValueError:
|
||||
x = shlex.quote(x)
|
||||
return x
|
||||
|
||||
|
||||
def main(args):
|
||||
ssh_args, server_args, passthrough = parse_ssh_args(args[1:])
|
||||
if passthrough:
|
||||
@@ -101,7 +114,7 @@ def main(args):
|
||||
terminfo = subprocess.check_output(['infocmp']).decode('utf-8')
|
||||
sh_script = SHELL_SCRIPT.replace('TERMINFO', terminfo, 1)
|
||||
if len(server_args) > 1:
|
||||
command_to_execute = ["'{}'".format(c.replace("'", """'"'"'""")) for c in server_args[1:]]
|
||||
command_to_execute = [quote(c) for c in server_args[1:]]
|
||||
command_to_execute = 'exec ' + ' '.join(command_to_execute)
|
||||
else:
|
||||
command_to_execute = ''
|
||||
|
||||
@@ -240,11 +240,10 @@ class Table:
|
||||
|
||||
|
||||
def is_index(w):
|
||||
try:
|
||||
with suppress(Exception):
|
||||
int(w.lstrip(INDEX_CHAR), 16)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
return False
|
||||
|
||||
|
||||
class UnicodeInput(Handler):
|
||||
@@ -295,9 +294,10 @@ class UnicodeInput(Handler):
|
||||
self.current_char = None
|
||||
if self.mode is HEX:
|
||||
with suppress(Exception):
|
||||
if self.line_edit.current_input.startswith(INDEX_CHAR) and len(self.line_edit.current_input) > 1:
|
||||
self.current_char = chr(self.table.codepoint_at_hint(self.line_edit.current_input[1:]))
|
||||
else:
|
||||
if self.line_edit.current_input.startswith(INDEX_CHAR):
|
||||
if len(self.line_edit.current_input) > 1:
|
||||
self.current_char = chr(self.table.codepoint_at_hint(self.line_edit.current_input[1:]))
|
||||
elif self.line_edit.current_input:
|
||||
code = int(self.line_edit.current_input, 16)
|
||||
self.current_char = chr(code)
|
||||
elif self.mode is NAME:
|
||||
@@ -392,19 +392,20 @@ class UnicodeInput(Handler):
|
||||
try:
|
||||
val = int(self.line_edit.current_input, 16)
|
||||
except Exception:
|
||||
return
|
||||
if key_event.key is TAB:
|
||||
self.line_edit.current_input = hex(val + 0x10)[2:]
|
||||
self.refresh()
|
||||
return
|
||||
if key_event.key is UP:
|
||||
self.line_edit.current_input = hex(val + 1)[2:]
|
||||
self.refresh()
|
||||
return
|
||||
if key_event.key is DOWN:
|
||||
self.line_edit.current_input = hex(val - 1)[2:]
|
||||
self.refresh()
|
||||
return
|
||||
pass
|
||||
else:
|
||||
if key_event.key is TAB:
|
||||
self.line_edit.current_input = hex(val + 0x10)[2:]
|
||||
self.refresh()
|
||||
return
|
||||
if key_event.key is UP:
|
||||
self.line_edit.current_input = hex(val + 1)[2:]
|
||||
self.refresh()
|
||||
return
|
||||
if key_event.key is DOWN:
|
||||
self.line_edit.current_input = hex(val - 1)[2:]
|
||||
self.refresh()
|
||||
return
|
||||
if self.mode is NAME and key_event.type is not RELEASE and not key_event.mods:
|
||||
if key_event.key is TAB:
|
||||
if key_event.mods == SHIFT:
|
||||
|
||||
@@ -7,5 +7,5 @@ out vec4 color;
|
||||
|
||||
void main() {
|
||||
color = texture(image, texcoord);
|
||||
color = vec4(color.rgb / color.a, color.a);
|
||||
color = vec4(color.rgb, color.a);
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ class Borders:
|
||||
bw, pw = self.border_width, self.padding_width
|
||||
if bw + pw <= 0:
|
||||
return
|
||||
draw_borders = bw > 0 and draw_window_borders and len(windows) > 1
|
||||
draw_borders = bw > 0 and draw_window_borders
|
||||
if draw_borders:
|
||||
border_data = current_layout.resolve_borders(windows, active_window)
|
||||
|
||||
|
||||
@@ -6,12 +6,12 @@ import atexit
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
from contextlib import suppress
|
||||
from functools import partial
|
||||
from gettext import gettext as _
|
||||
from weakref import WeakValueDictionary
|
||||
from contextlib import suppress
|
||||
|
||||
from .child import cached_process_data
|
||||
from .child import cached_process_data, cwd_of_process
|
||||
from .cli import create_opts, parse_args
|
||||
from .conf.utils import to_cmdline
|
||||
from .config import initial_window_size_func, prepare_config_file_for_editing
|
||||
@@ -25,8 +25,8 @@ from .fast_data_types import (
|
||||
change_os_window_state, create_os_window, current_os_window,
|
||||
destroy_global_data, get_clipboard_string, global_font_size,
|
||||
mark_os_window_for_close, os_window_font_size, patch_global_colors,
|
||||
set_clipboard_string, set_in_sequence_mode, toggle_fullscreen,
|
||||
toggle_maximized
|
||||
safe_pipe, set_clipboard_string, set_in_sequence_mode, thread_write,
|
||||
toggle_fullscreen, toggle_maximized
|
||||
)
|
||||
from .keys import get_shortcut, shortcut_matches
|
||||
from .layout import set_layout_options
|
||||
@@ -846,7 +846,8 @@ class Boss:
|
||||
def set_active_tab(self, tab):
|
||||
tm = self.active_tab_manager
|
||||
if tm is not None:
|
||||
tm.set_active_tab(tab)
|
||||
return tm.set_active_tab(tab)
|
||||
return False
|
||||
|
||||
def next_tab(self):
|
||||
tm = self.active_tab_manager
|
||||
@@ -918,11 +919,22 @@ class Boss:
|
||||
else:
|
||||
import subprocess
|
||||
env, stdin = self.process_stdin_source(stdin=source, window=window)
|
||||
cwd = None
|
||||
if cwd_from:
|
||||
with suppress(Exception):
|
||||
cwd = cwd_of_process(cwd_from)
|
||||
if stdin:
|
||||
p = subprocess.Popen(cmd, env=env, stdin=subprocess.PIPE)
|
||||
p.communicate(stdin)
|
||||
r, w = safe_pipe(False)
|
||||
try:
|
||||
subprocess.Popen(cmd, env=env, stdin=r, cwd=cwd)
|
||||
except Exception:
|
||||
os.close(w)
|
||||
else:
|
||||
thread_write(w, stdin)
|
||||
finally:
|
||||
os.close(r)
|
||||
else:
|
||||
subprocess.Popen(cmd)
|
||||
subprocess.Popen(cmd, env=env, cwd=cwd)
|
||||
|
||||
def args_to_special_window(self, args, cwd_from=None):
|
||||
args = list(args)
|
||||
@@ -977,10 +989,14 @@ class Boss:
|
||||
def _new_window(self, args, cwd_from=None):
|
||||
tab = self.active_tab
|
||||
if tab is not None:
|
||||
location = None
|
||||
if args and args[0].startswith('!'):
|
||||
location = args[0][1:].lower()
|
||||
args = args[1:]
|
||||
if args:
|
||||
return tab.new_special_window(self.args_to_special_window(args, cwd_from=cwd_from))
|
||||
return tab.new_special_window(self.args_to_special_window(args, cwd_from=cwd_from), location=location)
|
||||
else:
|
||||
return tab.new_window(cwd_from=cwd_from)
|
||||
return tab.new_window(cwd_from=cwd_from, location=location)
|
||||
|
||||
def new_window(self, *args):
|
||||
self._new_window(args)
|
||||
|
||||
@@ -51,10 +51,48 @@ vec4 alpha_blend_premul(vec3 over, float over_alpha, vec3 under, float under_alp
|
||||
float alpha = mix(under_alpha, 1.0f, over_alpha);
|
||||
return vec4(premul_blend(over, over_alpha, under), alpha);
|
||||
}
|
||||
|
||||
vec4 blend_onto_opaque_premul(vec3 over, float over_alpha, vec3 under) {
|
||||
// same as alpha_blend_premul with under_alpha = 1 outputs a blended color
|
||||
// with alpha 1 which is effectively pre-multiplied since alpha is 1
|
||||
return vec4(premul_blend(over, over_alpha, under), 1.0);
|
||||
}
|
||||
|
||||
|
||||
// }}}
|
||||
|
||||
|
||||
/*
|
||||
* Explanation of rendering:
|
||||
* There are a couple of cases, in order of increasing complexity:
|
||||
* 1) Simple -- this path is used when there are either no images, or all images are
|
||||
* drawn on top of text and the background is opaque. In this case, there is a single pass,
|
||||
* of this shader with cell foreground and background colors blended directly.
|
||||
* Expected output is a color premultiplied by alpha, with an alpha specified as well.
|
||||
*
|
||||
* 2) Interleaved -- this path is used if background is not opaque and there are images or
|
||||
* if the background is opaque but there are images under text. Rendering happens in
|
||||
* multiple passes drawing the background and foreground separately and blending.
|
||||
*
|
||||
* 2a) Opaque bg with images under text
|
||||
* There are multiple passes, each pass is blended onto the previous using the opaque blend func (alpha, 1- alpha):
|
||||
* 1) Draw only the background -- expected output is color with alpha 1
|
||||
* 2) Draw the images that are supposed to be below text. This happens in the graphics shader
|
||||
* 3) Draw the special cells (selection/cursor). Output is same as from step 1, with bg_alpha 1 for special cells and 0 otherwise
|
||||
* 4) Draw the foreground -- expected output is color with alpha which is blended using the opaque blend func
|
||||
* 5) Draw the images that are supposed to be above text again in the graphics shader
|
||||
*
|
||||
* 2b) Transparent bg with images
|
||||
* First everything is rendered into a framebuffer, and then the framebauffer is blended onto
|
||||
* the screen. The framebuffer is needed because it allows access to the background color pixels
|
||||
* to blend with the image pixels. The steps are basically the same as for 2a.
|
||||
*
|
||||
* In this shader exactly *one* of SIMPLE, SPECIAL, FOREGROUND or BACKGROUND will be defined, corresponding
|
||||
* to the appropriate rendering pass from above.
|
||||
*/
|
||||
#ifdef NEEDS_FOREGROUND
|
||||
vec4 calculate_foreground() {
|
||||
// returns the effective foreground color in pre-multiplied form
|
||||
vec4 text_fg = texture(sprites, sprite_pos);
|
||||
vec3 fg = mix(foreground, text_fg.rgb, colored_sprite);
|
||||
float text_alpha = text_fg.a;
|
||||
@@ -70,15 +108,12 @@ vec4 calculate_foreground() {
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
#ifdef BACKGROUND
|
||||
#ifdef SIMPLE
|
||||
vec4 fg = calculate_foreground();
|
||||
#ifdef TRANSPARENT
|
||||
// bg_alpha is doubled to match rendering in the SIMPLE case
|
||||
// and also rendering of the margin/padding, see https://github.com/kovidgoyal/kitty/pull/1291
|
||||
// to test use background_opacity, window_margin_width and icat to display
|
||||
// an image.
|
||||
final_color = vec4(background.rgb * bg_alpha * bg_alpha, bg_alpha);
|
||||
final_color = alpha_blend_premul(fg.rgb, fg.a, background.rgb * bg_alpha, bg_alpha);
|
||||
#else
|
||||
final_color = vec4(background.rgb, 1.0f);
|
||||
final_color = blend_onto_opaque_premul(fg.rgb, fg.a, background.rgb);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -90,29 +125,22 @@ void main() {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(FOREGROUND) || defined(SIMPLE)
|
||||
// FOREGROUND or SIMPLE
|
||||
vec4 fg = calculate_foreground(); // pre-multiplied foreground
|
||||
#ifdef BACKGROUND
|
||||
#ifdef TRANSPARENT
|
||||
final_color = vec4(background.rgb * bg_alpha, bg_alpha);
|
||||
#else
|
||||
final_color = vec4(background.rgb, 1.0f);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef FOREGROUND
|
||||
// FOREGROUND
|
||||
vec4 fg = calculate_foreground(); // pre-multiplied 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);
|
||||
#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);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#include "loop-utils.h"
|
||||
#include "state.h"
|
||||
#include "threading.h"
|
||||
#include "screen.h"
|
||||
@@ -16,10 +17,16 @@
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
#include <sys/socket.h>
|
||||
#include <signal.h>
|
||||
extern PyTypeObject Screen_Type;
|
||||
|
||||
#ifdef DEBUG_EVENT_LOOP
|
||||
#define EVDBG(...) log_event(__VA_ARGS__)
|
||||
#else
|
||||
#define EVDBG(...)
|
||||
#endif
|
||||
|
||||
#define EXTRA_FDS 2
|
||||
#ifndef MSG_NOSIGNAL
|
||||
// Apple does not implement MSG_NOSIGNAL
|
||||
@@ -46,6 +53,7 @@ typedef struct {
|
||||
int talk_fd, listen_fd;
|
||||
Message *messages;
|
||||
size_t messages_capacity, messages_count;
|
||||
LoopData io_loop_data;
|
||||
} ChildMonitor;
|
||||
|
||||
|
||||
@@ -77,7 +85,6 @@ static pthread_mutex_t children_lock;
|
||||
static bool kill_signal_received = false;
|
||||
static ChildMonitor *the_monitor = NULL;
|
||||
static uint8_t drain_buf[1024];
|
||||
static int signal_fds[2], wakeup_fds[2];
|
||||
|
||||
|
||||
typedef struct {
|
||||
@@ -110,39 +117,6 @@ set_maximum_wait(double val) {
|
||||
if (val >= 0 && (val < maximum_wait || maximum_wait < 0)) maximum_wait = val;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_signal(int sig_num) {
|
||||
int save_err = errno;
|
||||
unsigned char byte = (unsigned char)sig_num;
|
||||
while(true) {
|
||||
ssize_t ret = write(signal_fds[1], &byte, 1);
|
||||
if (ret < 0 && errno == EINTR) continue;
|
||||
break;
|
||||
}
|
||||
errno = save_err;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
self_pipe(int fds[2]) {
|
||||
#ifdef __APPLE__
|
||||
int flags;
|
||||
flags = pipe(fds);
|
||||
if (flags != 0) return false;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
flags = fcntl(fds[i], F_GETFD);
|
||||
if (flags == -1) { return false; }
|
||||
if (fcntl(fds[i], F_SETFD, flags | FD_CLOEXEC) == -1) { return false; }
|
||||
flags = fcntl(fds[i], F_GETFL);
|
||||
if (flags == -1) { return false; }
|
||||
if (fcntl(fds[i], F_SETFL, flags | O_NONBLOCK) == -1) { return false; }
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
return pipe2(fds, O_CLOEXEC | O_NONBLOCK) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
||||
ChildMonitor *self;
|
||||
@@ -156,13 +130,9 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
||||
PyErr_Format(PyExc_RuntimeError, "Failed to create children_lock mutex: %s", strerror(ret));
|
||||
return NULL;
|
||||
}
|
||||
if (!self_pipe(wakeup_fds)) return PyErr_SetFromErrno(PyExc_OSError);
|
||||
if (!self_pipe(signal_fds)) return PyErr_SetFromErrno(PyExc_OSError);
|
||||
struct sigaction act = {.sa_handler=handle_signal};
|
||||
#define SA(which) { if (sigaction(which, &act, NULL) != 0) return PyErr_SetFromErrno(PyExc_OSError); if (siginterrupt(which, false) != 0) return PyErr_SetFromErrno(PyExc_OSError);}
|
||||
SA(SIGINT); SA(SIGTERM); SA(SIGCHLD);
|
||||
#undef SA
|
||||
self = (ChildMonitor *)type->tp_alloc(type, 0);
|
||||
if (!init_loop_data(&self->io_loop_data)) return PyErr_SetFromErrno(PyExc_OSError);
|
||||
if (!install_signal_handlers(&self->io_loop_data)) return PyErr_SetFromErrno(PyExc_OSError);
|
||||
self->talk_fd = talk_fd;
|
||||
self->listen_fd = listen_fd;
|
||||
if (self == NULL) return PyErr_NoMemory();
|
||||
@@ -172,7 +142,7 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
||||
parse_func = parse_worker_dump;
|
||||
} else parse_func = parse_worker;
|
||||
self->count = 0;
|
||||
fds[0].fd = wakeup_fds[0]; fds[1].fd = signal_fds[0];
|
||||
fds[0].fd = self->io_loop_data.wakeup_read_fd; fds[1].fd = self->io_loop_data.signal_read_fd;
|
||||
fds[0].events = POLLIN; fds[1].events = POLLIN;
|
||||
the_monitor = self;
|
||||
|
||||
@@ -193,22 +163,12 @@ dealloc(ChildMonitor* self) {
|
||||
add_queue_count--;
|
||||
FREE_CHILD(add_queue[add_queue_count]);
|
||||
}
|
||||
close(wakeup_fds[0]);
|
||||
close(wakeup_fds[1]);
|
||||
close(signal_fds[0]);
|
||||
close(signal_fds[1]);
|
||||
free_loop_data(&self->io_loop_data);
|
||||
}
|
||||
|
||||
void
|
||||
wakeup_io_loop(bool in_signal_handler) {
|
||||
while(true) {
|
||||
ssize_t ret = write(wakeup_fds[1], "w", 1);
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
if (!in_signal_handler) perror("Failed to write to wakeup fd with error");
|
||||
}
|
||||
break;
|
||||
}
|
||||
static void
|
||||
wakeup_io_loop(ChildMonitor *self, bool in_signal_handler) {
|
||||
wakeup_loop(&self->io_loop_data, in_signal_handler);
|
||||
}
|
||||
|
||||
static void* io_loop(void *data);
|
||||
@@ -231,11 +191,10 @@ start(PyObject *s, PyObject *a UNUSED) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
wakeup(PYNOARG) {
|
||||
wakeup(ChildMonitor *self, PyObject *args UNUSED) {
|
||||
#define wakeup_doc "wakeup() -> wakeup the ChildMonitor I/O thread, forcing it to exit from poll() if it is waiting there."
|
||||
wakeup_io_loop(false);
|
||||
wakeup_io_loop(self, false);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
@@ -254,7 +213,7 @@ add_child(ChildMonitor *self, PyObject *args) {
|
||||
INCREF_CHILD(add_queue[add_queue_count]);
|
||||
add_queue_count++;
|
||||
children_mutex(unlock);
|
||||
wakeup_io_loop(false);
|
||||
wakeup_io_loop(self, false);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
@@ -301,7 +260,7 @@ schedule_write_to_child(unsigned long id, unsigned int num, ...) {
|
||||
screen->write_buf = PyMem_RawRealloc(screen->write_buf, screen->write_buf_sz);
|
||||
if (screen->write_buf == NULL) { fatal("Out of memory."); }
|
||||
}
|
||||
if (screen->write_buf_used) wakeup_io_loop(false);
|
||||
if (screen->write_buf_used) wakeup_io_loop(self, false);
|
||||
screen_mutex(unlock, write);
|
||||
break;
|
||||
}
|
||||
@@ -323,12 +282,9 @@ needs_write(ChildMonitor UNUSED *self, PyObject *args) {
|
||||
static PyObject *
|
||||
shutdown_monitor(ChildMonitor *self, PyObject *a UNUSED) {
|
||||
#define shutdown_monitor_doc "shutdown_monitor() -> Shutdown the monitor loop."
|
||||
signal(SIGINT, SIG_DFL);
|
||||
signal(SIGTERM, SIG_DFL);
|
||||
signal(SIGCHLD, SIG_DFL);
|
||||
self->shutting_down = true;
|
||||
wakeup_talk_loop(false);
|
||||
wakeup_io_loop(false);
|
||||
wakeup_io_loop(self, false);
|
||||
int ret = pthread_join(self->io_thread, NULL);
|
||||
if (ret != 0) return PyErr_Format(PyExc_OSError, "Failed to join() I/O thread with error: %s", strerror(ret));
|
||||
if (talk_thread_started) {
|
||||
@@ -339,15 +295,17 @@ shutdown_monitor(ChildMonitor *self, PyObject *a UNUSED) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static inline void
|
||||
static inline bool
|
||||
do_parse(ChildMonitor *self, Screen *screen, double now) {
|
||||
bool input_read = false;
|
||||
screen_mutex(lock, read);
|
||||
if (screen->read_buf_sz || screen->pending_mode.used) {
|
||||
double time_since_new_input = now - screen->new_input_at;
|
||||
if (time_since_new_input >= OPT(input_delay)) {
|
||||
bool read_buf_full = screen->read_buf_sz >= READ_BUF_SZ;
|
||||
input_read = true;
|
||||
parse_func(screen, self->dump_callback, now);
|
||||
if (read_buf_full) wakeup_io_loop(false); // Ensure the read fd has POLLIN set
|
||||
if (read_buf_full) wakeup_io_loop(self, false); // Ensure the read fd has POLLIN set
|
||||
screen->new_input_at = 0;
|
||||
if (screen->pending_mode.activated_at) {
|
||||
double time_since_pending = MAX(0, now - screen->pending_mode.activated_at);
|
||||
@@ -356,12 +314,14 @@ do_parse(ChildMonitor *self, Screen *screen, double now) {
|
||||
} else set_maximum_wait(OPT(input_delay) - time_since_new_input);
|
||||
}
|
||||
screen_mutex(unlock, read);
|
||||
return input_read;
|
||||
}
|
||||
|
||||
static void
|
||||
static bool
|
||||
parse_input(ChildMonitor *self) {
|
||||
// Parse all available input that was read in the I/O thread.
|
||||
size_t count = 0, remove_count = 0;
|
||||
bool input_read = false;
|
||||
double now = monotonic();
|
||||
PyObject *msg = NULL;
|
||||
children_mutex(lock);
|
||||
@@ -416,10 +376,11 @@ parse_input(ChildMonitor *self) {
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
if (!scratch[i].needs_removal) {
|
||||
do_parse(self, scratch[i].screen, now);
|
||||
if (do_parse(self, scratch[i].screen, now)) input_read = true;
|
||||
}
|
||||
DECREF_CHILD(scratch[i]);
|
||||
}
|
||||
return input_read;
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -432,7 +393,7 @@ mark_child_for_close(ChildMonitor *self, id_type window_id) {
|
||||
}
|
||||
}
|
||||
children_mutex(unlock);
|
||||
wakeup_io_loop(false);
|
||||
wakeup_io_loop(self, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -521,9 +482,7 @@ pyset_iutf8(ChildMonitor *self, PyObject *args) {
|
||||
#undef INCREF_CHILD
|
||||
#undef DECREF_CHILD
|
||||
|
||||
static double last_render_at = -DBL_MAX;
|
||||
|
||||
extern void cocoa_update_title(PyObject*);
|
||||
extern void cocoa_update_menu_bar_title(PyObject*);
|
||||
|
||||
static inline void
|
||||
collect_cursor_info(CursorRenderInfo *ans, Window *w, double now, OSWindow *os_window) {
|
||||
@@ -559,7 +518,7 @@ update_window_title(Window *w, OSWindow *os_window) {
|
||||
Py_INCREF(os_window->window_title);
|
||||
set_os_window_title(os_window, PyUnicode_AsUTF8(w->title));
|
||||
#ifdef __APPLE__
|
||||
if (os_window->is_focused && OPT(macos_show_window_title_in_menubar)) cocoa_update_title(w->title);
|
||||
if (os_window->is_focused && OPT(macos_show_window_title_in_menubar)) cocoa_update_menu_bar_title(w->title);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
@@ -672,10 +631,19 @@ draw_resizing_text(OSWindow *w) {
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool
|
||||
no_render_frame_received_recently(OSWindow *w, double now, double max_wait) {
|
||||
bool ans = now - w->last_render_frame_received_at > max_wait;
|
||||
if (ans) log_error("No render frame received in %f seconds, re-requesting at: %f", max_wait, now);
|
||||
return ans;
|
||||
}
|
||||
|
||||
static inline void
|
||||
render(double now) {
|
||||
render(double now, bool input_read) {
|
||||
EVDBG("input_read: %d", input_read);
|
||||
static double last_render_at = -DBL_MAX;
|
||||
double time_since_last_render = now - last_render_at;
|
||||
if (time_since_last_render < OPT(repaint_delay)) {
|
||||
if (!input_read && time_since_last_render < OPT(repaint_delay)) {
|
||||
set_maximum_wait(OPT(repaint_delay) - time_since_last_render);
|
||||
return;
|
||||
}
|
||||
@@ -688,7 +656,7 @@ render(double now) {
|
||||
continue;
|
||||
}
|
||||
if (USE_RENDER_FRAMES && w->render_state != RENDER_FRAME_READY) {
|
||||
if (w->render_state == RENDER_FRAME_NOT_REQUESTED) request_frame_render(w);
|
||||
if (w->render_state == RENDER_FRAME_NOT_REQUESTED || no_render_frame_received_recently(w, now, 0.25)) request_frame_render(w);
|
||||
continue;
|
||||
}
|
||||
make_os_window_context_current(w);
|
||||
@@ -723,7 +691,7 @@ typedef struct { int fd; uint8_t *buf; size_t sz; } ThreadWriteData;
|
||||
|
||||
static inline ThreadWriteData*
|
||||
alloc_twd(size_t sz) {
|
||||
ThreadWriteData *data = malloc(sizeof(ThreadWriteData));
|
||||
ThreadWriteData *data = calloc(1, sizeof(ThreadWriteData));
|
||||
if (data != NULL) {
|
||||
data->sz = sz;
|
||||
data->buf = malloc(sz);
|
||||
@@ -771,11 +739,25 @@ static void*
|
||||
thread_write(void *x) {
|
||||
ThreadWriteData *data = (ThreadWriteData*)x;
|
||||
set_thread_name("KittyWriteStdin");
|
||||
FILE *f = fdopen(data->fd, "w");
|
||||
if (fwrite(data->buf, 1, data->sz, f) != data->sz) {
|
||||
log_error("Failed to write all data");
|
||||
int flags = fcntl(data->fd, F_GETFL, 0);
|
||||
if (flags == -1) { free_twd(data); return 0; }
|
||||
flags &= ~O_NONBLOCK;
|
||||
fcntl(data->fd, F_SETFL, flags);
|
||||
size_t pos = 0;
|
||||
while (pos < data->sz) {
|
||||
errno = 0;
|
||||
ssize_t nbytes = write(data->fd, data->buf + pos, data->sz - pos);
|
||||
if (nbytes < 0) {
|
||||
if (errno == EAGAIN || errno == EINTR) continue;
|
||||
break;
|
||||
}
|
||||
if (nbytes == 0) break;
|
||||
pos += nbytes;
|
||||
}
|
||||
fclose(f);
|
||||
if (pos < data->sz) {
|
||||
log_error("Failed to write all data to STDIN of child process with error: %s", strerror(errno));
|
||||
}
|
||||
safe_close(data->fd);
|
||||
free_twd(data);
|
||||
return 0;
|
||||
}
|
||||
@@ -792,7 +774,8 @@ cm_thread_write(PyObject UNUSED *self, PyObject *args) {
|
||||
data->fd = fd;
|
||||
memcpy(data->buf, buf, data->sz);
|
||||
int ret = pthread_create(&thread, NULL, thread_write, data);
|
||||
if (ret != 0) { free_twd(data); return PyErr_SetFromErrno(PyExc_OSError); }
|
||||
if (ret != 0) { safe_close(fd); free_twd(data); return PyErr_SetFromErrno(PyExc_OSError); }
|
||||
pthread_detach(thread);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
@@ -913,21 +896,23 @@ static void process_global_state(void *data);
|
||||
|
||||
static void
|
||||
do_state_check(id_type timer_id UNUSED, void *data) {
|
||||
ChildMonitor *self = data;
|
||||
process_global_state(self);
|
||||
EVDBG("State check timer fired");
|
||||
process_global_state(data);
|
||||
}
|
||||
|
||||
static id_type state_check_timer = 0;
|
||||
|
||||
static void
|
||||
process_global_state(void *data) {
|
||||
EVDBG("Processing global state");
|
||||
ChildMonitor *self = data;
|
||||
maximum_wait = -1;
|
||||
bool state_check_timer_enabled = false;
|
||||
|
||||
double now = monotonic();
|
||||
if (global_state.has_pending_resizes) process_pending_resizes(now);
|
||||
render(now);
|
||||
bool input_read = parse_input(self);
|
||||
render(now, input_read);
|
||||
#ifdef __APPLE__
|
||||
if (cocoa_pending_actions) {
|
||||
if (cocoa_pending_actions & PREFERENCES_WINDOW) { call_boss(edit_config_file, NULL); }
|
||||
@@ -941,7 +926,6 @@ process_global_state(void *data) {
|
||||
cocoa_pending_actions = 0;
|
||||
}
|
||||
#endif
|
||||
parse_input(self);
|
||||
if (global_state.terminate) {
|
||||
global_state.terminate = false;
|
||||
close_all_windows();
|
||||
@@ -954,7 +938,8 @@ process_global_state(void *data) {
|
||||
if (global_state.has_pending_closes) has_open_windows = process_pending_closes(self);
|
||||
if (has_open_windows) {
|
||||
if (maximum_wait >= 0) {
|
||||
state_check_timer_enabled = true;
|
||||
if (maximum_wait == 0) request_tick_callback();
|
||||
else state_check_timer_enabled = true;
|
||||
}
|
||||
} else {
|
||||
stop_main_loop();
|
||||
@@ -1005,7 +990,7 @@ hangup(pid_t pid) {
|
||||
|
||||
static inline void
|
||||
cleanup_child(ssize_t i) {
|
||||
close(children[i].fd);
|
||||
safe_close(children[i].fd);
|
||||
hangup(children[i].pid);
|
||||
}
|
||||
|
||||
@@ -1074,35 +1059,28 @@ drain_fd(int fd) {
|
||||
ssize_t len = read(fd, drain_buf, sizeof(drain_buf));
|
||||
if (len < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
if (errno != EIO) perror("Call to read() from drain fd failed");
|
||||
break;
|
||||
}
|
||||
if (len > 0) continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
read_signals(int fd, bool *kill_signal, bool *child_died) {
|
||||
static char buf[256];
|
||||
while(true) {
|
||||
ssize_t len = read(fd, buf, sizeof(buf));
|
||||
if (len < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
if (errno != EIO) perror("Call to read() from read_signals() failed");
|
||||
typedef struct { bool kill_signal, child_died; } SignalSet;
|
||||
|
||||
static void
|
||||
handle_signal(int signum, void *data) {
|
||||
SignalSet *ss = data;
|
||||
switch(signum) {
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
ss->kill_signal = true;
|
||||
break;
|
||||
case SIGCHLD:
|
||||
ss->child_died = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
for (ssize_t i = 0; i < len; i++) {
|
||||
switch(buf[i]) {
|
||||
case SIGCHLD:
|
||||
*child_died = true; break;
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
*kill_signal = true; break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1212,11 +1190,11 @@ io_loop(void *data) {
|
||||
if (ret > 0) {
|
||||
if (fds[0].revents && POLLIN) drain_fd(fds[0].fd); // wakeup
|
||||
if (fds[1].revents && POLLIN) {
|
||||
SignalSet ss = {0};
|
||||
data_received = true;
|
||||
bool kill_signal = false, child_died = false;
|
||||
read_signals(fds[1].fd, &kill_signal, &child_died);
|
||||
if (kill_signal) { children_mutex(lock); kill_signal_received = true; children_mutex(unlock); }
|
||||
if (child_died) reap_children(self, OPT(close_on_child_death));
|
||||
read_signals(fds[1].fd, handle_signal, &ss);
|
||||
if (ss.kill_signal) { children_mutex(lock); kill_signal_received = true; children_mutex(unlock); }
|
||||
if (ss.child_died) reap_children(self, OPT(close_on_child_death));
|
||||
}
|
||||
for (i = 0; i < self->count; i++) {
|
||||
if (fds[EXTRA_FDS + i].revents & (POLLIN | POLLHUP)) {
|
||||
@@ -1296,14 +1274,14 @@ typedef struct {
|
||||
PeerReadData *reads;
|
||||
PeerWriteData *writes;
|
||||
PeerWriteData *queued_writes;
|
||||
int wakeup_fds[2];
|
||||
LoopData loop_data;
|
||||
pthread_mutex_t peer_lock;
|
||||
} TalkData;
|
||||
|
||||
static TalkData talk_data = {0};
|
||||
typedef struct pollfd PollFD;
|
||||
#define PEER_LIMIT 256
|
||||
#define nuke_socket(s) { shutdown(s, SHUT_RDWR); close(s); }
|
||||
#define nuke_socket(s) { shutdown(s, SHUT_RDWR); safe_close(s); }
|
||||
|
||||
static inline bool
|
||||
accept_peer(int listen_fd, bool shutting_down) {
|
||||
@@ -1336,7 +1314,7 @@ read_from_peer(ChildMonitor *self, int s) {
|
||||
if (rd->fd == s) {
|
||||
if (rd->used >= rd->capacity) {
|
||||
if (rd->capacity >= 1024 * 1024) failed("Ignoring too large message from peer");
|
||||
rd->capacity = MAX(8192, rd->capacity * 2);
|
||||
rd->capacity = MAX(8192u, rd->capacity * 2);
|
||||
rd->data = realloc(rd->data, rd->capacity);
|
||||
if (!rd->data) failed("Out of memory");
|
||||
}
|
||||
@@ -1424,7 +1402,7 @@ prune_finished_writes(void) {
|
||||
PeerWriteData *wd = talk_data.writes + i;
|
||||
if (wd->finished) {
|
||||
remove_poll_fd(wd->fd);
|
||||
shutdown(wd->fd, SHUT_WR); close(wd->fd);
|
||||
shutdown(wd->fd, SHUT_WR); safe_close(wd->fd);
|
||||
free(wd->data);
|
||||
ssize_t num_to_right = talk_data.num_writes - 1 - i;
|
||||
if (num_to_right > 0) memmove(talk_data.writes + i, talk_data.writes + i + 1, num_to_right * sizeof(PeerWriteData));
|
||||
@@ -1436,15 +1414,7 @@ prune_finished_writes(void) {
|
||||
|
||||
static void
|
||||
wakeup_talk_loop(bool in_signal_handler) {
|
||||
if (talk_data.wakeup_fds[1] <= 0) return;
|
||||
while(true) {
|
||||
ssize_t ret = write(talk_data.wakeup_fds[1], "w", 1);
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
if (!in_signal_handler) perror("Failed to write to talk wakeup fd with error");
|
||||
}
|
||||
break;
|
||||
}
|
||||
wakeup_loop(&talk_data.loop_data, in_signal_handler);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -1473,7 +1443,7 @@ talk_loop(void *data) {
|
||||
ChildMonitor *self = (ChildMonitor*)data;
|
||||
set_thread_name("KittyPeerMon");
|
||||
if ((pthread_mutex_init(&talk_data.peer_lock, NULL)) != 0) { perror("Failed to create peer mutex"); return 0; }
|
||||
if (!self_pipe(talk_data.wakeup_fds)) { perror("Failed to create wakeup fds for talk thread"); return 0; }
|
||||
if (!init_loop_data(&talk_data.loop_data)) { log_error("Failed to create wakeup fd for talk thread with error: %s", strerror(errno)); }
|
||||
ensure_space_for(&talk_data, fds, PollFD, 8, fds_capacity, 8, false);
|
||||
#define add_listener(which) \
|
||||
if (self->which > -1) { \
|
||||
@@ -1481,7 +1451,7 @@ talk_loop(void *data) {
|
||||
}
|
||||
add_listener(talk_fd); add_listener(listen_fd);
|
||||
#undef add_listener
|
||||
talk_data.fds[talk_data.num_listen_fds].fd = talk_data.wakeup_fds[0]; talk_data.fds[talk_data.num_listen_fds++].events = POLLIN;
|
||||
talk_data.fds[talk_data.num_listen_fds].fd = talk_data.loop_data.wakeup_read_fd; talk_data.fds[talk_data.num_listen_fds++].events = POLLIN;
|
||||
|
||||
while (LIKELY(!self->shutting_down)) {
|
||||
for (size_t i = 0; i < talk_data.num_listen_fds + talk_data.num_talk_fds; i++) { talk_data.fds[i].revents = 0; }
|
||||
@@ -1504,7 +1474,7 @@ talk_loop(void *data) {
|
||||
} else if (ret < 0) { if (errno != EAGAIN && errno != EINTR) perror("poll() on talk fds failed"); }
|
||||
}
|
||||
end:
|
||||
close(talk_data.wakeup_fds[0]); close(talk_data.wakeup_fds[1]);
|
||||
free_loop_data(&talk_data.loop_data);
|
||||
free(talk_data.fds); free(talk_data.reads); free(talk_data.writes); free(talk_data.queued_writes);
|
||||
return 0;
|
||||
}
|
||||
@@ -1530,8 +1500,8 @@ add_peer_writer(int fd, const char* msg, size_t msg_sz) {
|
||||
|
||||
static void
|
||||
send_response(int fd, const char *msg, size_t msg_sz) {
|
||||
if (msg == NULL) { shutdown(fd, SHUT_WR); close(fd); return; }
|
||||
if (!add_peer_writer(fd, msg, msg_sz)) { shutdown(fd, SHUT_WR); close(fd); }
|
||||
if (msg == NULL) { shutdown(fd, SHUT_WR); safe_close(fd); return; }
|
||||
if (!add_peer_writer(fd, msg, msg_sz)) { shutdown(fd, SHUT_WR); safe_close(fd); }
|
||||
else wakeup_talk_loop(false);
|
||||
}
|
||||
|
||||
@@ -1565,18 +1535,20 @@ PyTypeObject ChildMonitor_Type = {
|
||||
|
||||
|
||||
static PyObject*
|
||||
safe_pipe(PYNOARG) {
|
||||
safe_pipe(PyObject *self UNUSED, PyObject *args) {
|
||||
int nonblock = 1;
|
||||
if (!PyArg_ParseTuple(args, "|p", &nonblock)) return NULL;
|
||||
int fds[2] = {0};
|
||||
if (!self_pipe(fds)) return PyErr_SetFromErrno(PyExc_OSError);
|
||||
if (!self_pipe(fds, nonblock)) return PyErr_SetFromErrno(PyExc_OSError);
|
||||
return Py_BuildValue("ii", fds[0], fds[1]);
|
||||
}
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
METHODB(safe_pipe, METH_NOARGS),
|
||||
METHODB(safe_pipe, METH_VARARGS),
|
||||
{"add_timer", (PyCFunction)add_python_timer, METH_VARARGS, ""},
|
||||
{"remove_timer", (PyCFunction)remove_python_timer, METH_VARARGS, ""},
|
||||
METHODB(monitor_pid, METH_VARARGS),
|
||||
{"set_iutf8", (PyCFunction)pyset_iutf8, METH_VARARGS, ""},
|
||||
{"set_iutf8_winid", (PyCFunction)pyset_iutf8, METH_VARARGS, ""},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
||||
@@ -78,8 +78,14 @@ spawn(PyObject *self UNUSED, PyObject *args) {
|
||||
|
||||
pid_t pid = fork();
|
||||
switch(pid) {
|
||||
case 0:
|
||||
case 0: {
|
||||
// child
|
||||
sigset_t signals = {0};
|
||||
struct sigaction act = {.sa_handler=SIG_DFL};
|
||||
#define SA(which) { if (sigaction(which, &act, NULL) != 0) exit_on_err("sigaction() in child process failed"); }
|
||||
SA(SIGINT); SA(SIGTERM); SA(SIGCHLD);
|
||||
#undef SA
|
||||
if (sigprocmask(SIG_SETMASK, &signals, NULL) != 0) exit_on_err("sigprocmask() in child process failed");
|
||||
// Use only signal-safe functions (man 7 signal-safety)
|
||||
if (chdir(cwd) != 0) { if (chdir("/") != 0) {} }; // ignore failure to chdir to /
|
||||
if (setsid() == -1) exit_on_err("setsid() in child process failed");
|
||||
@@ -91,28 +97,28 @@ spawn(PyObject *self UNUSED, PyObject *args) {
|
||||
// On BSD open() does not establish the controlling terminal
|
||||
if (ioctl(tfd, TIOCSCTTY, 0) == -1) exit_on_err("Failed to set controlling terminal with TIOCSCTTY");
|
||||
#endif
|
||||
close(tfd);
|
||||
safe_close(tfd);
|
||||
|
||||
// Redirect stdin/stdout/stderr to the pty
|
||||
if (dup2(slave, 1) == -1) exit_on_err("dup2() failed for fd number 1");
|
||||
if (dup2(slave, 2) == -1) exit_on_err("dup2() failed for fd number 2");
|
||||
if (stdin_read_fd > -1) {
|
||||
if (dup2(stdin_read_fd, 0) == -1) exit_on_err("dup2() failed for fd number 0");
|
||||
close(stdin_read_fd);
|
||||
close(stdin_write_fd);
|
||||
safe_close(stdin_read_fd);
|
||||
safe_close(stdin_write_fd);
|
||||
} else {
|
||||
if (dup2(slave, 0) == -1) exit_on_err("dup2() failed for fd number 0");
|
||||
}
|
||||
close(slave);
|
||||
close(master);
|
||||
safe_close(slave);
|
||||
safe_close(master);
|
||||
|
||||
// Wait for READY_SIGNAL which indicates kitty has setup the screen object
|
||||
close(ready_write_fd);
|
||||
safe_close(ready_write_fd);
|
||||
wait_for_terminal_ready(ready_read_fd);
|
||||
close(ready_read_fd);
|
||||
safe_close(ready_read_fd);
|
||||
|
||||
// Close any extra fds inherited from parent
|
||||
for (int c = 3; c < 201; c++) close(c);
|
||||
for (int c = 3; c < 201; c++) safe_close(c);
|
||||
|
||||
environ = env;
|
||||
// for some reason SIGPIPE is set to SIG_IGN, so reset it, needed by bash,
|
||||
@@ -129,6 +135,7 @@ spawn(PyObject *self UNUSED, PyObject *args) {
|
||||
execlp("sh", "sh", "-c", "read w", NULL);
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
case -1:
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
break;
|
||||
|
||||
@@ -180,7 +180,7 @@ class Child:
|
||||
self.forked = True
|
||||
master, slave = os.openpty() # Note that master and slave are in blocking mode
|
||||
remove_cloexec(slave)
|
||||
fast_data_types.set_iutf8(master, True)
|
||||
fast_data_types.set_iutf8_fd(master, True)
|
||||
stdin, self.stdin = self.stdin, None
|
||||
ready_read_fd, ready_write_fd = os.pipe()
|
||||
remove_cloexec(ready_read_fd)
|
||||
|
||||
@@ -212,6 +212,14 @@ def wrap(text, limit=80):
|
||||
return reversed(lines)
|
||||
|
||||
|
||||
def get_defaults_from_seq(seq):
|
||||
ans = {}
|
||||
for opt in seq:
|
||||
if not isinstance(opt, str):
|
||||
ans[opt['dest']] = defval_for_opt(opt)
|
||||
return ans
|
||||
|
||||
|
||||
default_msg = ('''\
|
||||
Run the :italic:`{appname}` terminal emulator. You can also specify the :italic:`program`
|
||||
to run inside :italic:`{appname}` as normal arguments following the :italic:`options`.
|
||||
|
||||
300
kitty/cmds.py
300
kitty/cmds.py
@@ -7,7 +7,7 @@ import os
|
||||
import sys
|
||||
from contextlib import suppress
|
||||
|
||||
from .cli import parse_args
|
||||
from .cli import parse_args, parse_option_spec, get_defaults_from_seq
|
||||
from .config import parse_config, parse_send_text_bytes
|
||||
from .constants import appname
|
||||
from .fast_data_types import focus_os_window
|
||||
@@ -36,7 +36,33 @@ class UnknownLayout(ValueError):
|
||||
cmap = {}
|
||||
|
||||
|
||||
def cmd(short_desc, desc=None, options_spec=None, no_response=False, argspec='...', string_return_is_error=False, args_count=None):
|
||||
def cmd(
|
||||
short_desc,
|
||||
desc=None,
|
||||
options_spec=None,
|
||||
no_response=False,
|
||||
argspec='...',
|
||||
string_return_is_error=False,
|
||||
args_count=None,
|
||||
):
|
||||
|
||||
if options_spec:
|
||||
defaults = None
|
||||
|
||||
def get_defaut_value(name, missing=None):
|
||||
nonlocal defaults
|
||||
if defaults is None:
|
||||
defaults = get_defaults_from_seq(parse_option_spec(options_spec)[0])
|
||||
return defaults.get(name, missing)
|
||||
else:
|
||||
def get_defaut_value(name, missing=None):
|
||||
return missing
|
||||
|
||||
def payload_get(payload, key, opt_name=None):
|
||||
ans = payload.get(key, payload_get)
|
||||
if ans is not payload_get:
|
||||
return ans
|
||||
return get_defaut_value(opt_name or key)
|
||||
|
||||
def w(func):
|
||||
func.short_desc = short_desc
|
||||
@@ -49,6 +75,8 @@ def cmd(short_desc, desc=None, options_spec=None, no_response=False, argspec='..
|
||||
func.no_response = no_response
|
||||
func.string_return_is_error = string_return_is_error
|
||||
func.args_count = 0 if not argspec else args_count
|
||||
func.get_default = get_defaut_value
|
||||
func.payload_get = payload_get
|
||||
cmap[func.name] = func
|
||||
return func
|
||||
return w
|
||||
@@ -109,6 +137,9 @@ def windows_for_payload(boss, window, payload):
|
||||
argspec=''
|
||||
)
|
||||
def cmd_ls(global_opts, opts, args):
|
||||
'''
|
||||
No payload
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
@@ -135,6 +166,11 @@ By default, the font size is only changed in the active OS window,
|
||||
this option will cause it to be changed in all OS windows.
|
||||
''')
|
||||
def cmd_set_font_size(global_opts, opts, args):
|
||||
'''
|
||||
size+: The new font size in pts (a positive number)
|
||||
all: Boolean whether to change font size in the current window or all windows
|
||||
increment_op: The string ``+`` or ``-`` to interpret size as an increment
|
||||
'''
|
||||
if not args:
|
||||
raise SystemExit('No font size specified')
|
||||
fs = args[0]
|
||||
@@ -143,7 +179,9 @@ def cmd_set_font_size(global_opts, opts, args):
|
||||
|
||||
|
||||
def set_font_size(boss, window, payload):
|
||||
boss.change_font_size(payload['all'], payload['increment_op'], payload['size'])
|
||||
boss.change_font_size(
|
||||
cmd_set_font_size.payload_get(payload, 'all'),
|
||||
payload.get('increment_op', None), payload['size'])
|
||||
# }}}
|
||||
|
||||
|
||||
@@ -170,6 +208,12 @@ are sent as is, not interpreted for escapes.
|
||||
argspec='[TEXT TO SEND]'
|
||||
)
|
||||
def cmd_send_text(global_opts, opts, args):
|
||||
'''
|
||||
text+: The text being sent
|
||||
is_binary+: If False text is interpreted as a python string literal instead of plain text
|
||||
match: A string indicating the window to send text to
|
||||
match_tab: A string indicating the tab to send text to
|
||||
'''
|
||||
limit = 1024
|
||||
ret = {'match': opts.match, 'is_binary': False, 'match_tab': opts.match_tab}
|
||||
|
||||
@@ -235,12 +279,14 @@ def cmd_send_text(global_opts, opts, args):
|
||||
|
||||
def send_text(boss, window, payload):
|
||||
windows = [boss.active_window]
|
||||
match = payload['match']
|
||||
pg = cmd_send_text.payload_get
|
||||
match = pg(payload, 'match')
|
||||
if match:
|
||||
windows = tuple(boss.match_windows(match))
|
||||
if payload['match_tab']:
|
||||
mt = pg(payload, 'match_tab')
|
||||
if mt:
|
||||
windows = []
|
||||
tabs = tuple(boss.match_tabs(payload['match_tab']))
|
||||
tabs = tuple(boss.match_tabs(mt))
|
||||
if not tabs:
|
||||
raise MatchError(payload['match_tab'], 'tabs')
|
||||
for tab in tabs:
|
||||
@@ -269,19 +315,25 @@ want to allow other programs to change it afterwards, use this option.
|
||||
argspec='TITLE ...'
|
||||
)
|
||||
def cmd_set_window_title(global_opts, opts, args):
|
||||
'''
|
||||
title+: The new title
|
||||
match: Which windows to change the title in
|
||||
temporary: Boolean indicating if the change is temporary or permanent
|
||||
'''
|
||||
return {'title': ' '.join(args), 'match': opts.match, 'temporary': opts.temporary}
|
||||
|
||||
|
||||
def set_window_title(boss, window, payload):
|
||||
windows = [window or boss.active_window]
|
||||
match = payload['match']
|
||||
pg = cmd_set_window_title.payload_get
|
||||
match = pg(payload, 'match')
|
||||
if match:
|
||||
windows = tuple(boss.match_windows(match))
|
||||
if not windows:
|
||||
raise MatchError(match)
|
||||
for window in windows:
|
||||
if window:
|
||||
if payload['temporary']:
|
||||
if pg(payload, 'temporary'):
|
||||
window.override_title = None
|
||||
window.title_changed(payload['title'])
|
||||
else:
|
||||
@@ -301,11 +353,16 @@ def set_window_title(boss, window, payload):
|
||||
argspec='TITLE ...'
|
||||
)
|
||||
def cmd_set_tab_title(global_opts, opts, args):
|
||||
'''
|
||||
title+: The new title
|
||||
match: Which tab to change the title of
|
||||
'''
|
||||
return {'title': ' '.join(args), 'match': opts.match}
|
||||
|
||||
|
||||
def set_tab_title(boss, window, payload):
|
||||
match = payload['match']
|
||||
pg = cmd_set_tab_title.payload_get
|
||||
match = pg(payload, 'match')
|
||||
if match:
|
||||
tabs = tuple(boss.match_tabs(match))
|
||||
if not tabs:
|
||||
@@ -327,6 +384,10 @@ def set_tab_title(boss, window, payload):
|
||||
argspec='LAYOUT_NAME'
|
||||
)
|
||||
def cmd_goto_layout(global_opts, opts, args):
|
||||
'''
|
||||
layout+: The new layout name
|
||||
match: Which tab to change the layout of
|
||||
'''
|
||||
try:
|
||||
return {'layout': args[0], 'match': opts.match}
|
||||
except IndexError:
|
||||
@@ -334,7 +395,8 @@ def cmd_goto_layout(global_opts, opts, args):
|
||||
|
||||
|
||||
def goto_layout(boss, window, payload):
|
||||
match = payload['match']
|
||||
pg = cmd_goto_layout.payload_get
|
||||
match = pg(payload, 'match')
|
||||
if match:
|
||||
if match == 'all':
|
||||
tabs = tuple(boss.all_tabs)
|
||||
@@ -361,11 +423,15 @@ def goto_layout(boss, window, payload):
|
||||
options_spec=MATCH_TAB_OPTION,
|
||||
)
|
||||
def cmd_last_used_layout(global_opts, opts, args):
|
||||
'''
|
||||
match: Which tab to change the layout of
|
||||
'''
|
||||
return {'match': opts.match}
|
||||
|
||||
|
||||
def last_used_layout(boss, window, payload):
|
||||
match = payload['match']
|
||||
pg = cmd_last_used_layout.payload_get
|
||||
match = pg(payload, 'match')
|
||||
if match:
|
||||
if match == 'all':
|
||||
tabs = tuple(boss.all_tabs)
|
||||
@@ -392,17 +458,22 @@ If specified close the window this command is run in, rather than the active win
|
||||
argspec=''
|
||||
)
|
||||
def cmd_close_window(global_opts, opts, args):
|
||||
'''
|
||||
match: Which window to close
|
||||
self: Boolean indicating whether to close the window the command is run in
|
||||
'''
|
||||
return {'match': opts.match, 'self': opts.self}
|
||||
|
||||
|
||||
def close_window(boss, window, payload):
|
||||
match = payload['match']
|
||||
pg = cmd_close_window.payload_get
|
||||
match = pg(payload, 'match')
|
||||
if match:
|
||||
windows = tuple(boss.match_windows(match))
|
||||
if not windows:
|
||||
raise MatchError(match)
|
||||
else:
|
||||
windows = [window if window and payload['self'] else boss.active_window]
|
||||
windows = [window if window and pg(payload, 'self') else boss.active_window]
|
||||
for window in windows:
|
||||
if window:
|
||||
boss.close_window(window)
|
||||
@@ -437,22 +508,29 @@ If specified resize the window this command is run in, rather than the active wi
|
||||
string_return_is_error=True
|
||||
)
|
||||
def cmd_resize_window(global_opts, opts, args):
|
||||
'''
|
||||
match: Which window to resize
|
||||
self: Boolean indicating whether to close the window the command is run in
|
||||
increment: Integer specifying the resize increment
|
||||
axis: One of :code:`horizontal, vertical` or :code:`reset`
|
||||
'''
|
||||
return {'match': opts.match, 'increment': opts.increment, 'axis': opts.axis, 'self': opts.self}
|
||||
|
||||
|
||||
def resize_window(boss, window, payload):
|
||||
match = payload['match']
|
||||
pg = cmd_resize_window.payload_get
|
||||
match = pg(payload, 'match')
|
||||
if match:
|
||||
windows = tuple(boss.match_windows(match))
|
||||
if not windows:
|
||||
raise MatchError(match)
|
||||
else:
|
||||
windows = [window if window and payload['self'] else boss.active_window]
|
||||
windows = [window if window and pg(payload, 'self') else boss.active_window]
|
||||
resized = False
|
||||
if windows and windows[0]:
|
||||
resized = boss.resize_layout_window(
|
||||
windows[0], increment=payload['increment'], is_horizontal=payload['axis'] == 'horizontal',
|
||||
reset=payload['axis'] == 'reset'
|
||||
windows[0], increment=pg(payload, 'increment'), is_horizontal=pg(payload, 'axis') == 'horizontal',
|
||||
reset=pg(payload, 'axis') == 'reset'
|
||||
)
|
||||
return resized
|
||||
# }}}
|
||||
@@ -469,17 +547,22 @@ If specified close the tab this command is run in, rather than the active tab.
|
||||
argspec=''
|
||||
)
|
||||
def cmd_close_tab(global_opts, opts, args):
|
||||
'''
|
||||
match: Which tab to close
|
||||
self: Boolean indicating whether to close the window the command is run in
|
||||
'''
|
||||
return {'match': opts.match, 'self': opts.self}
|
||||
|
||||
|
||||
def close_tab(boss, window, payload):
|
||||
match = payload['match']
|
||||
pg = cmd_close_tab.payload_get
|
||||
match = pg(payload, 'match')
|
||||
if match:
|
||||
tabs = tuple(boss.match_tabs(match))
|
||||
if not tabs:
|
||||
raise MatchError(match, 'tabs')
|
||||
else:
|
||||
tabs = [boss.tab_for_window(window) if window and payload['self'] else boss.active_tab]
|
||||
tabs = [boss.tab_for_window(window) if window and pg(payload, 'self') else boss.active_tab]
|
||||
for tab in tabs:
|
||||
if window:
|
||||
if tab:
|
||||
@@ -537,6 +620,15 @@ the id of the new window will not be printed out.
|
||||
argspec='[CMD ...]'
|
||||
)
|
||||
def cmd_new_window(global_opts, opts, args):
|
||||
'''
|
||||
args+: The command line to run in the new window, as a list, use an empty list to run the default shell
|
||||
match: The tab to open the new window in
|
||||
title: Title for the new window
|
||||
cwd: Working directory for the new window
|
||||
tab_title: Title for the new tab
|
||||
window_type: One of :code:`kitty` or :code:`os`
|
||||
keep_focus: Boolean indicating whether the current window should retain focus or not
|
||||
'''
|
||||
if opts.no_response:
|
||||
global_opts.no_command_response = True
|
||||
return {'match': opts.match, 'title': opts.title, 'cwd': opts.cwd,
|
||||
@@ -546,28 +638,29 @@ def cmd_new_window(global_opts, opts, args):
|
||||
|
||||
|
||||
def new_window(boss, window, payload):
|
||||
w = SpecialWindow(cmd=payload['args'] or None, override_title=payload['title'], cwd=payload['cwd'])
|
||||
pg = cmd_new_window.payload_get
|
||||
w = SpecialWindow(cmd=payload['args'] or None, override_title=pg(payload, 'title'), cwd=pg(payload, 'cwd'))
|
||||
old_window = boss.active_window
|
||||
if payload['new_tab']:
|
||||
if pg(payload, 'new_tab'):
|
||||
boss._new_tab(w)
|
||||
tab = boss.active_tab
|
||||
if payload['tab_title']:
|
||||
tab.set_title(payload['tab_title'])
|
||||
if pg(payload, 'tab_title'):
|
||||
tab.set_title(pg(payload, 'tab_title'))
|
||||
wid = boss.active_window.id
|
||||
if payload['keep_focus'] and old_window:
|
||||
if pg(payload, 'keep_focus') and old_window:
|
||||
boss.set_active_window(old_window)
|
||||
return None if payload['no_response'] else str(wid)
|
||||
return None if pg(payload, 'no_response') else str(wid)
|
||||
|
||||
if payload['window_type'] == 'os':
|
||||
if pg(payload, 'window_type') == 'os':
|
||||
boss._new_os_window(w)
|
||||
wid = boss.active_window.id
|
||||
if payload['keep_focus'] and old_window:
|
||||
if pg(payload, 'keep_focus') and old_window:
|
||||
os_window_id = boss.set_active_window(old_window)
|
||||
if os_window_id:
|
||||
focus_os_window(os_window_id)
|
||||
return None if payload['no_response'] else str(wid)
|
||||
return None if pg(payload, 'no_response') else str(wid)
|
||||
|
||||
match = payload['match']
|
||||
match = pg(payload, 'match')
|
||||
if match:
|
||||
tabs = tuple(boss.match_tabs(match))
|
||||
if not tabs:
|
||||
@@ -576,9 +669,9 @@ def new_window(boss, window, payload):
|
||||
tabs = [boss.active_tab]
|
||||
tab = tabs[0]
|
||||
w = tab.new_special_window(w)
|
||||
if payload['keep_focus'] and old_window:
|
||||
if pg(payload, 'keep_focus') and old_window:
|
||||
boss.set_active_window(old_window)
|
||||
return None if payload['no_response'] else str(w.id)
|
||||
return None if pg(payload, 'no_response') else str(w.id)
|
||||
# }}}
|
||||
|
||||
|
||||
@@ -596,14 +689,18 @@ the command will exit with a success code.
|
||||
'''
|
||||
)
|
||||
def cmd_focus_window(global_opts, opts, args):
|
||||
'''
|
||||
match: The window to focus
|
||||
'''
|
||||
if opts.no_response:
|
||||
global_opts.no_command_response = True
|
||||
return {'match': opts.match, 'no_response': opts.no_response}
|
||||
|
||||
|
||||
def focus_window(boss, window, payload):
|
||||
pg = cmd_focus_window.payload_get
|
||||
windows = [window or boss.active_window]
|
||||
match = payload['match']
|
||||
match = pg(payload, 'match')
|
||||
if match:
|
||||
windows = tuple(boss.match_windows(match))
|
||||
if not windows:
|
||||
@@ -617,6 +714,59 @@ def focus_window(boss, window, payload):
|
||||
# }}}
|
||||
|
||||
|
||||
# scroll_window {{{
|
||||
@cmd(
|
||||
'Scroll the specified window',
|
||||
'Scroll the specified window, if no window is specified, scroll the window this command is run inside.'
|
||||
' SCROLL_AMOUNT can be either the keywords :code:`start` or :code:`end` or an'
|
||||
' argument of the form <number>[unit][+-]. For example, 30 will scroll down 30 lines and 2p- will'
|
||||
' scroll up 2 pages.',
|
||||
argspec='SCROLL_AMOUNT',
|
||||
options_spec=MATCH_WINDOW_OPTION
|
||||
)
|
||||
def cmd_scroll_window(global_opts, opts, args):
|
||||
'''
|
||||
amount+: The amount to scroll, a two item list with the first item being \
|
||||
either a number or the keywords, start and end. \
|
||||
And the second item being either 'p' for pages or 'l' for lines.
|
||||
match: The window to scroll
|
||||
'''
|
||||
amt = args[0]
|
||||
ans = {'match': opts.match}
|
||||
if amt in ('start', 'end'):
|
||||
ans['amount'] = amt, None
|
||||
else:
|
||||
pages = 'p' in amt
|
||||
amt = amt.replace('p', '')
|
||||
mult = -1 if amt.endswith('-') else 1
|
||||
amt = int(amt.replace('-', ''))
|
||||
ans['amount'] = [amt * mult, 'p' if pages else 'l']
|
||||
return ans
|
||||
|
||||
|
||||
def scroll_window(boss, window, payload):
|
||||
pg = cmd_scroll_window.payload_get
|
||||
windows = [window or boss.active_window]
|
||||
match = pg(payload, 'match')
|
||||
amt = pg(payload, 'amount')
|
||||
if match:
|
||||
windows = tuple(boss.match_windows(match))
|
||||
if not windows:
|
||||
raise MatchError(match)
|
||||
for window in windows:
|
||||
if window:
|
||||
if amt[0] in ('start', 'end'):
|
||||
getattr(window, {'start': 'scroll_home'}.get(amt[0], 'scroll_end'))()
|
||||
else:
|
||||
amt, unit = amt
|
||||
unit = 'page' if unit == 'p' else 'line'
|
||||
direction = 'up' if amt < 0 else 'down'
|
||||
func = getattr(window, 'scroll_{}_{}'.format(unit, direction))
|
||||
for i in range(abs(amt)):
|
||||
func()
|
||||
# }}}
|
||||
|
||||
|
||||
# focus_tab {{{
|
||||
@cmd(
|
||||
'Focus the specified tab',
|
||||
@@ -630,16 +780,19 @@ Don't wait for a response indicating the success of the action. Note that
|
||||
using this option means that you will not be notified of failures.
|
||||
''',
|
||||
argspec='',
|
||||
no_response=True,
|
||||
)
|
||||
def cmd_focus_tab(global_opts, opts, args):
|
||||
'''
|
||||
match: The tab to focus
|
||||
'''
|
||||
if opts.no_response:
|
||||
global_opts.no_command_response = True
|
||||
return {'match': opts.match}
|
||||
|
||||
|
||||
def focus_tab(boss, window, payload):
|
||||
match = payload['match']
|
||||
pg = cmd_focus_tab.payload_get
|
||||
match = pg(payload, 'match')
|
||||
tabs = tuple(boss.match_tabs(match))
|
||||
if not tabs:
|
||||
raise MatchError(match, 'tabs')
|
||||
@@ -673,22 +826,29 @@ If specified get text from the window this command is run in, rather than the ac
|
||||
argspec=''
|
||||
)
|
||||
def cmd_get_text(global_opts, opts, args):
|
||||
'''
|
||||
match: The tab to focus
|
||||
extent: One of :code:`screen`, :code:`all`, or :code:`selection`
|
||||
ansi: Boolean, if True send ANSI formatting codes
|
||||
self: Boolean, if True use window command was run in
|
||||
'''
|
||||
return {'match': opts.match, 'extent': opts.extent, 'ansi': opts.ansi, 'self': opts.self}
|
||||
|
||||
|
||||
def get_text(boss, window, payload):
|
||||
match = payload['match']
|
||||
pg = cmd_get_text.payload_get
|
||||
match = pg(payload, 'match')
|
||||
if match:
|
||||
windows = tuple(boss.match_windows(match))
|
||||
if not windows:
|
||||
raise MatchError(match)
|
||||
else:
|
||||
windows = [window if window and payload['self'] else boss.active_window]
|
||||
windows = [window if window and pg(payload, 'self') else boss.active_window]
|
||||
window = windows[0]
|
||||
if payload['extent'] == 'selection':
|
||||
if pg(payload, 'extent') == 'selection':
|
||||
ans = window.text_for_selection()
|
||||
else:
|
||||
ans = window.as_text(as_ansi=bool(payload['ansi']), add_history=payload['extent'] == 'all')
|
||||
ans = window.as_text(as_ansi=bool(pg(payload, 'ansi')), add_history=pg(payload, 'extent') == 'all')
|
||||
return ans
|
||||
# }}}
|
||||
|
||||
@@ -720,6 +880,15 @@ this option, any color arguments are ignored and --configured and --all are impl
|
||||
argspec='COLOR_OR_FILE ...'
|
||||
)
|
||||
def cmd_set_colors(global_opts, opts, args):
|
||||
'''
|
||||
colors+: An object mapping names to colors as 24-bit RGB integers
|
||||
cursor_text_color: A 24-bit clor for text under the cursor
|
||||
match_window: Window to change colors in
|
||||
match_tab: Tab to change colors in
|
||||
all: Boolean indicating change colors everywhere or not
|
||||
configured: Boolean indicating whether to change the configured colors. Must be True if reset is True
|
||||
reset: Boolean indicating colors should be reset to startup values
|
||||
'''
|
||||
from .rgb import color_as_int, Color
|
||||
colors, cursor_text_color = {}, False
|
||||
if not opts.reset:
|
||||
@@ -732,16 +901,17 @@ def cmd_set_colors(global_opts, opts, args):
|
||||
cursor_text_color = colors.pop('cursor_text_color', False)
|
||||
colors = {k: color_as_int(v) for k, v in colors.items() if isinstance(v, Color)}
|
||||
return {
|
||||
'title': ' '.join(args), 'match_window': opts.match, 'match_tab': opts.match_tab,
|
||||
'match_window': opts.match, 'match_tab': opts.match_tab,
|
||||
'all': opts.all or opts.reset, 'configured': opts.configured or opts.reset,
|
||||
'colors': colors, 'reset': opts.reset, 'cursor_text_color': cursor_text_color
|
||||
}
|
||||
|
||||
|
||||
def set_colors(boss, window, payload):
|
||||
pg = cmd_set_colors.payload_get
|
||||
from .rgb import color_as_int, Color
|
||||
windows = windows_for_payload(boss, window, payload)
|
||||
if payload['reset']:
|
||||
if pg(payload, 'reset'):
|
||||
payload['colors'] = {k: color_as_int(v) for k, v in boss.startup_colors.items()}
|
||||
payload['cursor_text_color'] = boss.startup_cursor_text_color
|
||||
profiles = tuple(w.screen.color_profile for w in windows)
|
||||
@@ -749,8 +919,8 @@ def set_colors(boss, window, payload):
|
||||
cursor_text_color = payload.get('cursor_text_color', False)
|
||||
if isinstance(cursor_text_color, (tuple, list, Color)):
|
||||
cursor_text_color = color_as_int(Color(*cursor_text_color))
|
||||
patch_color_profiles(payload['colors'], cursor_text_color, profiles, payload['configured'])
|
||||
boss.patch_colors(payload['colors'], cursor_text_color, payload['configured'])
|
||||
patch_color_profiles(payload['colors'], cursor_text_color, profiles, pg(payload, 'configured'))
|
||||
boss.patch_colors(payload['colors'], cursor_text_color, pg(payload, 'configured'))
|
||||
default_bg_changed = 'background' in payload['colors']
|
||||
for w in windows:
|
||||
if default_bg_changed:
|
||||
@@ -772,18 +942,23 @@ configured colors.
|
||||
''' + '\n\n' + MATCH_WINDOW_OPTION
|
||||
)
|
||||
def cmd_get_colors(global_opts, opts, args):
|
||||
'''
|
||||
match: The window to get the colors for
|
||||
configured: Boolean indicating whether to get configured or current colors
|
||||
'''
|
||||
return {'configured': opts.configured, 'match': opts.match}
|
||||
|
||||
|
||||
def get_colors(boss, window, payload):
|
||||
from .rgb import Color, color_as_sharp, color_from_int
|
||||
pg = cmd_get_colors.payload_get
|
||||
ans = {k: getattr(boss.opts, k) for k in boss.opts if isinstance(getattr(boss.opts, k), Color)}
|
||||
if not payload['configured']:
|
||||
if not pg(payload, 'configured'):
|
||||
windows = (window or boss.active_window,)
|
||||
if payload['match']:
|
||||
windows = tuple(boss.match_windows(payload['match']))
|
||||
if pg(payload, 'match'):
|
||||
windows = tuple(boss.match_windows(pg(payload, 'match')))
|
||||
if not windows:
|
||||
raise MatchError(payload['match'])
|
||||
raise MatchError(pg(payload, 'match'))
|
||||
ans.update({k: color_from_int(v) for k, v in windows[0].current_colors.items()})
|
||||
all_keys = natsort_ints(ans)
|
||||
maxlen = max(map(len, all_keys))
|
||||
@@ -808,24 +983,23 @@ cause colors to be changed in all windows.
|
||||
args_count=1
|
||||
)
|
||||
def cmd_set_background_opacity(global_opts, opts, args):
|
||||
'''
|
||||
opacity+: A number between 0.1 and 1
|
||||
match_window: Window to change opacity in
|
||||
match_tab: Tab to change opacity in
|
||||
all: Boolean indicating operate on all windows
|
||||
'''
|
||||
opacity = max(0.1, min(float(args[0]), 1.0))
|
||||
return {
|
||||
'opacity': opacity, 'match_window': opts.match,
|
||||
'all': opts.all,
|
||||
'all': opts.all, 'match_tab': opts.match_tab
|
||||
}
|
||||
|
||||
|
||||
def set_background_opacity(boss, window, payload):
|
||||
if not boss.opts.dynamic_background_opacity:
|
||||
raise OpacityError('You must turn on the dynamic_background_opacity option in kitty.conf to be able to set background opacity')
|
||||
if payload['all']:
|
||||
windows = tuple(boss.all_windows)
|
||||
else:
|
||||
windows = (window or boss.active_window,)
|
||||
if payload['match_window']:
|
||||
windows = tuple(boss.match_windows(payload['match_window']))
|
||||
if not windows:
|
||||
raise MatchError(payload['match_window'])
|
||||
windows = windows_for_payload(payload)
|
||||
for os_window_id in {w.os_window_id for w in windows}:
|
||||
boss._set_os_window_background_opacity(os_window_id, payload['opacity'])
|
||||
# }}}
|
||||
@@ -846,6 +1020,12 @@ cause ligatures to be changed in all windows.
|
||||
argspec='STRATEGY'
|
||||
)
|
||||
def cmd_disable_ligatures(global_opts, opts, args):
|
||||
'''
|
||||
strategy+: One of :code:`never`, :code:`always` or :code:`cursor`
|
||||
match_window: Window to change opacity in
|
||||
match_tab: Tab to change opacity in
|
||||
all: Boolean indicating operate on all windows
|
||||
'''
|
||||
strategy = args[0]
|
||||
if strategy not in ('never', 'always', 'cursor'):
|
||||
raise ValueError('{} is not a valid disable_ligatures strategy'.format('strategy'))
|
||||
@@ -872,6 +1052,11 @@ def disable_ligatures(boss, window, payload):
|
||||
argspec='kitten_name',
|
||||
)
|
||||
def cmd_kitten(global_opts, opts, args):
|
||||
'''
|
||||
kitten+: The name of the kitten to run
|
||||
args: Arguments to pass to the kitten as a list
|
||||
match: The window to run the kitten over
|
||||
'''
|
||||
if len(args) < 1:
|
||||
raise SystemExit('Must specify kitten name')
|
||||
return {'match': opts.match, 'args': list(args)[1:], 'kitten': args[0]}
|
||||
@@ -879,14 +1064,15 @@ def cmd_kitten(global_opts, opts, args):
|
||||
|
||||
def kitten(boss, window, payload):
|
||||
windows = [window or boss.active_window]
|
||||
match = payload['match']
|
||||
pg = cmd_kitten.payload_get
|
||||
match = pg(payload, 'match')
|
||||
if match:
|
||||
windows = tuple(boss.match_windows(match))
|
||||
if not windows:
|
||||
raise MatchError(match)
|
||||
for window in windows:
|
||||
if window:
|
||||
boss._run_kitten(payload['kitten'], args=tuple(payload['args']), window=window)
|
||||
boss._run_kitten(payload['kitten'], args=tuple(payload.get('args', ())), window=window)
|
||||
break
|
||||
# }}}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ find_app_name(void) {
|
||||
|
||||
for (i = 0; i < sizeof(name_keys) / sizeof(name_keys[0]); i++)
|
||||
{
|
||||
id name = [infoDictionary objectForKey:name_keys[i]];
|
||||
id name = infoDictionary[name_keys[i]];
|
||||
if (name &&
|
||||
[name isKindOfClass:[NSString class]] &&
|
||||
![name isEqualToString:@""])
|
||||
@@ -60,7 +60,7 @@ find_app_name(void) {
|
||||
|
||||
char** progname = _NSGetProgname();
|
||||
if (progname && *progname)
|
||||
return [NSString stringWithUTF8String:*progname];
|
||||
return @(*progname);
|
||||
|
||||
// Really shouldn't get here
|
||||
return @"kitty";
|
||||
@@ -132,7 +132,6 @@ set_notification_activated_callback(PyObject *self UNUSED, PyObject *callback) {
|
||||
notification_activated_callback = callback;
|
||||
Py_INCREF(callback);
|
||||
Py_RETURN_NONE;
|
||||
|
||||
}
|
||||
|
||||
@interface NotificationDelegate : NSObject <NSUserNotificationCenterDelegate>
|
||||
@@ -172,7 +171,7 @@ cocoa_send_notification(PyObject *self UNUSED, PyObject *args) {
|
||||
NSUserNotification *n = [NSUserNotification new];
|
||||
NSImage *img = nil;
|
||||
if (path_to_image) {
|
||||
NSString *p = [NSString stringWithUTF8String:path_to_image];
|
||||
NSString *p = @(path_to_image);
|
||||
NSURL *url = [NSURL fileURLWithPath:p];
|
||||
img = [[NSImage alloc] initWithContentsOfURL:url];
|
||||
[url release]; [p release];
|
||||
@@ -184,14 +183,14 @@ cocoa_send_notification(PyObject *self UNUSED, PyObject *args) {
|
||||
}
|
||||
#define SET(x) { \
|
||||
if (x) { \
|
||||
NSString *t = [NSString stringWithUTF8String:x]; \
|
||||
NSString *t = @(x); \
|
||||
n.x = t; \
|
||||
[t release]; \
|
||||
}}
|
||||
SET(title); SET(subtitle); SET(informativeText);
|
||||
#undef SET
|
||||
if (identifier) {
|
||||
n.userInfo = @{@"user_id": [NSString stringWithUTF8String:identifier]};
|
||||
n.userInfo = @{@"user_id": @(identifier)};
|
||||
}
|
||||
[center deliverNotification:n];
|
||||
Py_RETURN_NONE;
|
||||
@@ -233,6 +232,7 @@ cocoa_send_notification(PyObject *self UNUSED, PyObject *args) {
|
||||
void
|
||||
cocoa_create_global_menu(void) {
|
||||
@autoreleasepool {
|
||||
|
||||
NSString* app_name = find_app_name();
|
||||
NSMenu* bar = [[NSMenu alloc] init];
|
||||
GlobalMenuTarget *global_menu_target = [GlobalMenuTarget shared_instance];
|
||||
@@ -324,11 +324,12 @@ cocoa_create_global_menu(void) {
|
||||
|
||||
|
||||
[NSApp setServicesProvider:[[[ServiceProvider alloc] init] autorelease]];
|
||||
}
|
||||
|
||||
} // autoreleasepool
|
||||
}
|
||||
|
||||
void
|
||||
cocoa_update_title(PyObject *pytitle) {
|
||||
cocoa_update_menu_bar_title(PyObject *pytitle) {
|
||||
NSString *title = [[NSString alloc] initWithUTF8String:PyUnicode_AsUTF8(pytitle)];
|
||||
NSMenu *bar = [NSApp mainMenu];
|
||||
if (title_menu != NULL) {
|
||||
@@ -395,6 +396,7 @@ cocoa_get_workspace_ids(void *w, size_t *workspace_ids, size_t array_sz) {
|
||||
static PyObject*
|
||||
cocoa_get_lang(PyObject UNUSED *self) {
|
||||
@autoreleasepool {
|
||||
|
||||
NSString* locale = nil;
|
||||
NSString* lang_code = [[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode];
|
||||
NSString* country_code = [[NSLocale currentLocale] objectForKey:NSLocaleCountryCode];
|
||||
@@ -405,12 +407,14 @@ cocoa_get_lang(PyObject UNUSED *self) {
|
||||
}
|
||||
if (!locale) { Py_RETURN_NONE; }
|
||||
return Py_BuildValue("s", [locale UTF8String]);
|
||||
}
|
||||
|
||||
} // autoreleasepool
|
||||
}
|
||||
|
||||
double
|
||||
cocoa_cursor_blink_interval(void) {
|
||||
@autoreleasepool {
|
||||
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
double on_period_ms = [defaults doubleForKey:@"NSTextInsertionPointBlinkPeriodOn"];
|
||||
double off_period_ms = [defaults doubleForKey:@"NSTextInsertionPointBlinkPeriodOff"];
|
||||
@@ -422,19 +426,21 @@ cocoa_cursor_blink_interval(void) {
|
||||
ans = period_ms;
|
||||
}
|
||||
return ans > max_value ? 0.0 : ans;
|
||||
}
|
||||
|
||||
} // autoreleasepool
|
||||
}
|
||||
|
||||
void
|
||||
cocoa_set_hide_from_tasks(void) {
|
||||
[NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];
|
||||
cocoa_set_activation_policy(bool hide_from_tasks) {
|
||||
[NSApp setActivationPolicy:(hide_from_tasks ? NSApplicationActivationPolicyAccessory : NSApplicationActivationPolicyRegular)];
|
||||
}
|
||||
|
||||
void
|
||||
cocoa_set_titlebar_color(void *w, color_type titlebar_color)
|
||||
{
|
||||
@autoreleasepool {
|
||||
NSWindow *window = (NSWindow *)w;
|
||||
|
||||
NSWindow *window = (NSWindow*)w;
|
||||
|
||||
double red = ((titlebar_color >> 16) & 0xFF) / 255.0;
|
||||
double green = ((titlebar_color >> 8) & 0xFF) / 255.0;
|
||||
@@ -455,17 +461,20 @@ cocoa_set_titlebar_color(void *w, color_type titlebar_color)
|
||||
} else {
|
||||
[window setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameVibrantLight]];
|
||||
}
|
||||
}
|
||||
|
||||
} // autoreleasepool
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup() {
|
||||
@autoreleasepool {
|
||||
|
||||
if (dockMenu) [dockMenu release];
|
||||
dockMenu = nil;
|
||||
if (notification_activated_callback) Py_DECREF(notification_activated_callback);
|
||||
notification_activated_callback = NULL;
|
||||
}
|
||||
|
||||
} // autoreleasepool
|
||||
}
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
|
||||
@@ -272,7 +272,7 @@ set_configured_colors(ColorProfile *self, PyObject *args) {
|
||||
void
|
||||
copy_color_table_to_buffer(ColorProfile *self, color_type *buf, int offset, size_t stride) {
|
||||
size_t i;
|
||||
stride = MAX(1, stride);
|
||||
stride = MAX(1u, stride);
|
||||
for (i = 0, buf = buf + offset; i < sizeof(self->color_table)/sizeof(self->color_table[0]); i++, buf += stride) {
|
||||
*buf = self->color_table[i];
|
||||
}
|
||||
|
||||
@@ -12,6 +12,25 @@ from .cli import options_for_completion, parse_option_spec
|
||||
from .cmds import cmap
|
||||
from .shell import options_for_cmd
|
||||
|
||||
'''
|
||||
To add completion for a new shell, you need to:
|
||||
|
||||
1) Add an entry to completion scripts for your shell, this is
|
||||
a simple function that call's kitty's completion code and passes the
|
||||
results to the shell's completion system. This can be output by
|
||||
`kitty +complete setup shell_name` and its output goes into
|
||||
your shell's rc file.
|
||||
|
||||
2) Add an input_parser function, this takes the input from
|
||||
the shell for the text being completed and returns a list of words
|
||||
alongwith a boolean indicating if we are on a new word or not. This
|
||||
is passed to kitty's completion system.
|
||||
|
||||
3) An output_serializer function that is responsible for
|
||||
taking the results from kitty's completion system and converting
|
||||
them into something your shell will understand.
|
||||
'''
|
||||
|
||||
parsers, serializers = {}, {}
|
||||
|
||||
|
||||
@@ -131,7 +150,6 @@ def bash_output_serializer(ans):
|
||||
lines.append('COMPREPLY+=({})'.format(shlex.quote(word)))
|
||||
# debug('\n'.join(lines))
|
||||
return '\n'.join(lines)
|
||||
# }}}
|
||||
|
||||
|
||||
@output_serializer
|
||||
@@ -142,6 +160,7 @@ def fish_output_serializer(ans):
|
||||
lines.append(shlex.quote(word))
|
||||
# debug('\n'.join(lines))
|
||||
return '\n'.join(lines)
|
||||
# }}}
|
||||
|
||||
|
||||
def completions_for_first_word(ans, prefix, entry_points, namespaced_entry_points):
|
||||
|
||||
@@ -403,7 +403,8 @@ def handle_deprecated_hide_window_decorations_aliases(key, val, ans):
|
||||
handle_deprecated_hide_window_decorations_aliases.key = True
|
||||
log_error('The option {} is deprecated. Use hide_window_decorations instead.'.format(key))
|
||||
if to_bool(val):
|
||||
ans['hide_window_decorations'] = True
|
||||
if is_macos and key == 'macos_hide_titlebar' or (not is_macos and key == 'x11_hide_window_decorations'):
|
||||
ans['hide_window_decorations'] = True
|
||||
|
||||
|
||||
def expandvars(val, env):
|
||||
@@ -628,6 +629,4 @@ def load_config(*paths, overrides=None, accumulate_bad_lines=None):
|
||||
if opts.background_opacity < 1.0 and opts.macos_titlebar_color:
|
||||
log_error('Cannot use both macos_titlebar_color and background_opacity')
|
||||
opts.macos_titlebar_color = 0
|
||||
if (is_macos and getattr(opts, 'macos_hide_titlebar', False)) or (not is_macos and getattr(opts, 'x11_hide_window_decorations', False)):
|
||||
opts.hide_window_decorations = True
|
||||
return opts
|
||||
|
||||
@@ -456,6 +456,9 @@ o('rectangle_select_modifiers', 'ctrl+alt', option_type=to_modifiers, long_text=
|
||||
The modifiers to use rectangular selection (i.e. to select text in a
|
||||
rectangular block with the mouse)'''))
|
||||
|
||||
o('terminal_select_modifiers', 'shift', option_type=to_modifiers, long_text=_('''
|
||||
The modifiers to override mouse selection even when a terminal application has grabbed the mouse'''))
|
||||
|
||||
o('select_by_word_characters', ':@-./_~?&=%+#', long_text=_('''
|
||||
Characters considered part of a word when double clicking. In addition to these characters
|
||||
any character that is marked as an alpha-numeric character in the unicode
|
||||
@@ -469,6 +472,10 @@ o('focus_follows_mouse', False, long_text=_('''
|
||||
Set the active window to the window under the mouse when
|
||||
moving the mouse around'''))
|
||||
|
||||
o('pointer_shape_when_grabbed', 'arrow', option_type=choices('arrow', 'beam', 'hand'), long_text=('''
|
||||
The shape of the mouse pointer when the program running in the terminal grabs the mouse.
|
||||
'''))
|
||||
|
||||
# }}}
|
||||
|
||||
g('performance') # {{{
|
||||
@@ -478,7 +485,8 @@ Delay (in milliseconds) between screen updates. Decreasing it, increases
|
||||
frames-per-second (FPS) at the cost of more CPU usage. The default value
|
||||
yields ~100 FPS which is more than sufficient for most uses. Note that to
|
||||
actually achieve 100 FPS you have to either set :opt:`sync_to_monitor` to no
|
||||
or use a monitor with a high refresh rate.'''))
|
||||
or use a monitor with a high refresh rate. Also, to minimize latency
|
||||
when there is pending input to be processed, repaint_delay is ignored.'''))
|
||||
|
||||
o('input_delay', 3, option_type=positive_int, long_text=_('''
|
||||
Delay (in milliseconds) before input from the program running in the terminal
|
||||
@@ -1066,6 +1074,13 @@ Any programs running in that window will be allowed to control kitty.
|
||||
For example::
|
||||
|
||||
map ctrl+enter new_window @ some_program
|
||||
|
||||
You can open a new window next to the currently active window or as the first window,
|
||||
with::
|
||||
|
||||
map ctrl+n new_window !neighbor some_program
|
||||
map ctrl+f new_window !first some_program
|
||||
|
||||
'''))
|
||||
if is_macos:
|
||||
k('new_window', 'cmd+enter', 'new_window', _('New window'), add_to_docs=False)
|
||||
@@ -1194,7 +1209,7 @@ You can create shortcuts to clear/reset the terminal. For example::
|
||||
# Scroll the contents of the screen into the scrollback
|
||||
map kitty_mod+f12 clear_terminal scroll active
|
||||
|
||||
If you want to operate on all windows instead of just the current one, use :italic:`all` instead of :italic`active`.
|
||||
If you want to operate on all windows instead of just the current one, use :italic:`all` instead of :italic:`active`.
|
||||
|
||||
It is also possible to remap Ctrl+L to both scroll the current screen contents into the scrollback buffer
|
||||
and clear the screen, instead of just clearing the screen::
|
||||
|
||||
@@ -9,7 +9,7 @@ from collections import namedtuple
|
||||
from contextlib import suppress
|
||||
|
||||
appname = 'kitty'
|
||||
version = (0, 14, 2)
|
||||
version = (0, 14, 3)
|
||||
str_version = '.'.join(map(str, version))
|
||||
_plat = sys.platform.lower()
|
||||
is_macos = 'darwin' in _plat
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "state.h"
|
||||
#include "fonts.h"
|
||||
#include "unicode-data.h"
|
||||
#include <structmember.h>
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
@@ -134,7 +135,7 @@ font_descriptor_from_python(PyObject *src) {
|
||||
|
||||
#define SET(x, attr) \
|
||||
t = PyDict_GetItemString(src, #x); \
|
||||
if (t) attrs[(id)attr] = [NSString stringWithUTF8String:PyUnicode_AsUTF8(t)];
|
||||
if (t) attrs[(id)attr] = @(PyUnicode_AsUTF8(t));
|
||||
|
||||
SET(family, kCTFontFamilyNameAttribute);
|
||||
SET(style, kCTFontStyleNameAttribute);
|
||||
@@ -144,23 +145,75 @@ font_descriptor_from_python(PyObject *src) {
|
||||
return CTFontDescriptorCreateWithAttributes((CFDictionaryRef) attrs);
|
||||
}
|
||||
|
||||
static CTFontCollectionRef all_fonts_collection_data = NULL;
|
||||
|
||||
static CTFontCollectionRef
|
||||
all_fonts_collection() {
|
||||
if (all_fonts_collection_data == NULL) all_fonts_collection_data = CTFontCollectionCreateFromAvailableFonts(NULL);
|
||||
return all_fonts_collection_data;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
coretext_all_fonts(PyObject UNUSED *_self) {
|
||||
static CTFontCollectionRef collection = NULL;
|
||||
if (collection == NULL) collection = CTFontCollectionCreateFromAvailableFonts(NULL);
|
||||
NSArray *matches = (NSArray *) CTFontCollectionCreateMatchingFontDescriptors(collection);
|
||||
PyObject *ans = PyTuple_New([matches count]), *temp;
|
||||
CFArrayRef matches = CTFontCollectionCreateMatchingFontDescriptors(all_fonts_collection());
|
||||
const CFIndex count = CFArrayGetCount(matches);
|
||||
PyObject *ans = PyTuple_New(count), *temp;
|
||||
if (ans == NULL) return PyErr_NoMemory();
|
||||
for (unsigned int i = 0; i < [matches count]; i++) {
|
||||
temp = font_descriptor_to_python((CTFontDescriptorRef) matches[i]);
|
||||
for (CFIndex i = 0; i < count; i++) {
|
||||
temp = font_descriptor_to_python((CTFontDescriptorRef) CFArrayGetValueAtIndex(matches, i));
|
||||
if (temp == NULL) { Py_DECREF(ans); return NULL; }
|
||||
PyTuple_SET_ITEM(ans, i, temp); temp = NULL;
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
glyph_id_for_codepoint_ctfont(CTFontRef ct_font, char_type ch) {
|
||||
unichar chars[2] = {0};
|
||||
CGGlyph glyphs[2] = {0};
|
||||
int count = CFStringGetSurrogatePairForLongCharacter(ch, chars) ? 2 : 1;
|
||||
CTFontGetGlyphsForCharacters(ct_font, chars, glyphs, count);
|
||||
return glyphs[0];
|
||||
}
|
||||
|
||||
static inline bool
|
||||
is_last_resort_font(CTFontRef new_font) {
|
||||
CFStringRef name = CTFontCopyPostScriptName(new_font);
|
||||
CFComparisonResult cr = CFStringCompare(name, CFSTR("LastResort"), 0);
|
||||
CFRelease(name);
|
||||
return cr == kCFCompareEqualTo;
|
||||
}
|
||||
|
||||
static inline CTFontRef
|
||||
find_substitute_face(CFStringRef str, CTFontRef old_font) {
|
||||
manually_search_fallback_fonts(CTFontRef current_font, CPUCell *cell) {
|
||||
CFArrayRef fonts = CTFontCollectionCreateMatchingFontDescriptors(all_fonts_collection());
|
||||
CTFontRef ans = NULL;
|
||||
const CFIndex count = CFArrayGetCount(fonts);
|
||||
for (CFIndex i = 0; i < count; i++) {
|
||||
CTFontDescriptorRef descriptor = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fonts, i);
|
||||
CTFontRef new_font = CTFontCreateWithFontDescriptor(descriptor, CTFontGetSize(current_font), NULL);
|
||||
if (new_font) {
|
||||
if (!is_last_resort_font(new_font)) {
|
||||
char_type ch = cell->ch ? cell->ch : ' ';
|
||||
bool found = true;
|
||||
if (!glyph_id_for_codepoint_ctfont(new_font, ch)) found = false;
|
||||
for (unsigned i = 0; i < arraysz(cell->cc_idx) && cell->cc_idx[i] && found; i++) {
|
||||
ch = codepoint_for_mark(cell->cc_idx[i]);
|
||||
if (!glyph_id_for_codepoint_ctfont(new_font, ch)) found = false;
|
||||
}
|
||||
if (found) {
|
||||
ans = new_font;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CFRelease(new_font);
|
||||
}
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
static inline CTFontRef
|
||||
find_substitute_face(CFStringRef str, CTFontRef old_font, CPUCell *cpu_cell) {
|
||||
// CTFontCreateForString returns the original font when there are combining
|
||||
// diacritics in the font and the base character is in the original font,
|
||||
// so we have to check each character individually
|
||||
@@ -171,11 +224,13 @@ find_substitute_face(CFStringRef str, CTFontRef old_font) {
|
||||
else start++;
|
||||
if (new_font == NULL) { PyErr_SetString(PyExc_ValueError, "Failed to find fallback CTFont"); return NULL; }
|
||||
if (new_font == old_font) { CFRelease(new_font); continue; }
|
||||
CFStringRef name = CTFontCopyPostScriptName(new_font);
|
||||
CFComparisonResult cr = CFStringCompare(name, CFSTR("LastResort"), 0);
|
||||
CFRelease(name);
|
||||
if (cr == kCFCompareEqualTo) {
|
||||
if (is_last_resort_font(new_font)) {
|
||||
CFRelease(new_font);
|
||||
if (is_private_use(cpu_cell->ch)) {
|
||||
// CoreTexts fallback font mechanism does not work for private use characters
|
||||
new_font = manually_search_fallback_fonts(old_font, cpu_cell);
|
||||
if (new_font) return new_font;
|
||||
}
|
||||
PyErr_SetString(PyExc_ValueError, "Failed to find fallback CTFont other than the LastResort font");
|
||||
return NULL;
|
||||
}
|
||||
@@ -191,11 +246,11 @@ create_fallback_face(PyObject *base_face, CPUCell* cell, bool UNUSED bold, bool
|
||||
CTFontRef new_font;
|
||||
if (emoji_presentation) new_font = CTFontCreateWithName((CFStringRef)@"AppleColorEmoji", self->scaled_point_sz, NULL);
|
||||
else {
|
||||
char text[256] = {0};
|
||||
char text[64] = {0};
|
||||
cell_as_utf8_for_fallback(cell, text);
|
||||
CFStringRef str = CFStringCreateWithCString(NULL, text, kCFStringEncodingUTF8);
|
||||
if (str == NULL) return PyErr_NoMemory();
|
||||
new_font = find_substitute_face(str, self->ct_font);
|
||||
new_font = find_substitute_face(str, self->ct_font, cell);
|
||||
CFRelease(str);
|
||||
}
|
||||
if (new_font == NULL) return NULL;
|
||||
@@ -205,11 +260,7 @@ create_fallback_face(PyObject *base_face, CPUCell* cell, bool UNUSED bold, bool
|
||||
unsigned int
|
||||
glyph_id_for_codepoint(PyObject *s, char_type ch) {
|
||||
CTFace *self = (CTFace*)s;
|
||||
unichar chars[2] = {0};
|
||||
CGGlyph glyphs[2] = {0};
|
||||
int count = CFStringGetSurrogatePairForLongCharacter(ch, chars) ? 2 : 1;
|
||||
CTFontGetGlyphsForCharacters(self->ct_font, chars, glyphs, count);
|
||||
return glyphs[0];
|
||||
return glyph_id_for_codepoint_ctfont(self->ct_font, ch);
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -274,7 +325,7 @@ cell_metrics(PyObject *s, unsigned int* cell_width, unsigned int* cell_height, u
|
||||
if (w > width) width = w;
|
||||
}
|
||||
}
|
||||
*cell_width = MAX(1, width);
|
||||
*cell_width = MAX(1u, width);
|
||||
*underline_position = floor(self->ascent - self->underline_position + 0.5);
|
||||
*underline_thickness = (unsigned int)ceil(MAX(0.1, self->underline_thickness));
|
||||
*baseline = (unsigned int)self->ascent;
|
||||
@@ -296,7 +347,7 @@ cell_metrics(PyObject *s, unsigned int* cell_width, unsigned int* cell_height, u
|
||||
CTFrameGetLineOrigins(test_frame, CFRangeMake(1, 1), &origin2);
|
||||
CGFloat line_height = origin1.y - origin2.y;
|
||||
CFRelease(test_frame); CFRelease(path); CFRelease(framesetter);
|
||||
*cell_height = MAX(4, (unsigned int)ceilf(line_height));
|
||||
*cell_height = MAX(4u, (unsigned int)ceilf(line_height));
|
||||
#undef count
|
||||
}
|
||||
|
||||
@@ -336,6 +387,7 @@ static CGPoint positions[128];
|
||||
static void
|
||||
finalize(void) {
|
||||
free(render_buf);
|
||||
if (all_fonts_collection_data) CFRelease(all_fonts_collection_data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ START_ALLOW_CASE_RANGE
|
||||
case 3:
|
||||
self->italic = true; break;
|
||||
case 4:
|
||||
if (i < count) { self->decoration = MIN(3, params[i]); i++; }
|
||||
if (i < count) { self->decoration = MIN(3u, params[i]); i++; }
|
||||
else self->decoration = 1;
|
||||
break;
|
||||
case 7:
|
||||
@@ -161,7 +161,7 @@ apply_sgr_to_cells(GPUCell *first_cell, unsigned int cell_count, unsigned int *p
|
||||
case 3:
|
||||
SET(ITALIC_SHIFT);
|
||||
case 4:
|
||||
if (i < count) { uint8_t val = MIN(3, params[i]); i++; SETM(val, DECORATION_MASK, DECORATION_SHIFT); }
|
||||
if (i < count) { uint8_t val = MIN(3u, params[i]); i++; SETM(val, DECORATION_MASK, DECORATION_SHIFT); }
|
||||
else { SETM(1, DECORATION_MASK, DECORATION_SHIFT); }
|
||||
case 7:
|
||||
SET(REVERSE_SHIFT);
|
||||
|
||||
@@ -89,7 +89,9 @@ static inline double monotonic_(void) {
|
||||
}
|
||||
#endif
|
||||
|
||||
double monotonic() { return monotonic_(); }
|
||||
static double start_time = 0;
|
||||
|
||||
double monotonic() { return monotonic_() - start_time; }
|
||||
|
||||
static PyObject*
|
||||
redirect_std_streams(PyObject UNUSED *self, PyObject *args) {
|
||||
@@ -179,7 +181,7 @@ close_tty(PyObject *self UNUSED, PyObject *args) {
|
||||
TTY_ARGS
|
||||
tcsetattr(fd, TCSAFLUSH, termios_p); // deliberately ignore failure
|
||||
free(termios_p);
|
||||
close(fd);
|
||||
safe_close(fd);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
@@ -190,7 +192,7 @@ static PyMethodDef module_methods[] = {
|
||||
{"normal_tty", normal_tty, METH_VARARGS, ""},
|
||||
{"raw_tty", raw_tty, METH_VARARGS, ""},
|
||||
{"close_tty", close_tty, METH_VARARGS, ""},
|
||||
{"set_iutf8", (PyCFunction)pyset_iutf8, METH_VARARGS, ""},
|
||||
{"set_iutf8_fd", (PyCFunction)pyset_iutf8, METH_VARARGS, ""},
|
||||
{"thread_write", (PyCFunction)cm_thread_write, METH_VARARGS, ""},
|
||||
{"parse_bytes", (PyCFunction)parse_bytes, METH_VARARGS, ""},
|
||||
{"parse_bytes_dump", (PyCFunction)parse_bytes_dump, METH_VARARGS, ""},
|
||||
@@ -254,6 +256,7 @@ PyInit_fast_data_types(void) {
|
||||
#ifdef __APPLE__
|
||||
mach_timebase_info(&timebase);
|
||||
#endif
|
||||
start_time = monotonic_();
|
||||
|
||||
if (m != NULL) {
|
||||
if (!init_logging(m)) return NULL;
|
||||
|
||||
@@ -22,11 +22,18 @@
|
||||
#define EXPORTED __attribute__ ((visibility ("default")))
|
||||
#define LIKELY(x) __builtin_expect (!!(x), 1)
|
||||
#define UNLIKELY(x) __builtin_expect (!!(x), 0)
|
||||
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
|
||||
#define MIN(x, y) (((x) > (y)) ? (y) : (x))
|
||||
#define MAX(x, y) __extension__ ({ \
|
||||
__typeof__ (x) a = (x); __typeof__ (y) b = (y); \
|
||||
a > b ? a : b;})
|
||||
#define MIN(x, y) __extension__ ({ \
|
||||
__typeof__ (x) a = (x); __typeof__ (y) b = (y); \
|
||||
a < b ? a : b;})
|
||||
#define xstr(s) str(s)
|
||||
#define str(s) #s
|
||||
#define arraysz(x) (sizeof(x)/sizeof(x[0]))
|
||||
#define zero_at_i(array, idx) memset((array) + (idx), 0, sizeof((array)[0]))
|
||||
#define zero_at_ptr(p) memset((p), 0, sizeof((p)[0]))
|
||||
#define zero_at_ptr_count(p, count) memset((p), 0, (count) * sizeof((p)[0]))
|
||||
void log_error(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
|
||||
#define fatal(...) { log_error(__VA_ARGS__); exit(EXIT_FAILURE); }
|
||||
|
||||
@@ -200,7 +207,6 @@ typedef struct {
|
||||
uint8_t decoration;
|
||||
CursorShape shape;
|
||||
color_type fg, bg, decoration_fg;
|
||||
|
||||
} Cursor;
|
||||
|
||||
typedef struct {
|
||||
@@ -251,7 +257,7 @@ typedef struct {FONTS_DATA_HEAD} *FONTS_DATA_HANDLE;
|
||||
|
||||
#define ensure_space_for(base, array, type, num, capacity, initial_cap, zero_mem) \
|
||||
if ((base)->capacity < num) { \
|
||||
size_t _newcap = MAX(initial_cap, MAX(2 * (base)->capacity, num)); \
|
||||
size_t _newcap = MAX((size_t)initial_cap, MAX(2 * (base)->capacity, (size_t)num)); \
|
||||
(base)->array = realloc((base)->array, sizeof(type) * _newcap); \
|
||||
if ((base)->array == NULL) fatal("Out of memory while ensuring space for %zu elements in array of %s", (size_t)num, #type); \
|
||||
if (zero_mem) memset((base)->array + (base)->capacity, 0, sizeof(type) * (_newcap - (base)->capacity)); \
|
||||
@@ -298,11 +304,16 @@ void set_mouse_cursor(MouseShape);
|
||||
void enter_event(void);
|
||||
void mouse_event(int, int, int);
|
||||
void focus_in_event(void);
|
||||
void wakeup_io_loop(bool);
|
||||
void scroll_event(double, double, int);
|
||||
void fake_scroll(int, bool);
|
||||
void set_special_key_combo(int glfw_key, int mods, bool is_native);
|
||||
void on_key_input(int key, int scancode, int action, int mods, const char*, int);
|
||||
void request_window_attention(id_type, bool);
|
||||
#ifndef __APPLE__
|
||||
void play_canberra_sound(const char *which_sound, const char *event_id);
|
||||
#endif
|
||||
SPRITE_MAP_HANDLE alloc_sprite_map(unsigned int, unsigned int);
|
||||
SPRITE_MAP_HANDLE free_sprite_map(SPRITE_MAP_HANDLE);
|
||||
|
||||
static inline void safe_close(int fd) { while(close(fd) != 0 && errno == EINTR); }
|
||||
void log_event(const char *format, ...) __attribute__((format(printf, 1, 2)));
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "data-types.h"
|
||||
#include <dlfcn.h>
|
||||
#include <canberra.h>
|
||||
|
||||
#define FUNC(name, restype, ...) typedef restype (*name##_func)(__VA_ARGS__); static name##_func name = NULL
|
||||
#define LOAD_FUNC(handle, name) {\
|
||||
@@ -89,9 +90,25 @@ static PyMethodDef module_methods[] = {
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
static ca_context *canberra_ctx = NULL;
|
||||
|
||||
void
|
||||
play_canberra_sound(const char *which_sound, const char *event_id) {
|
||||
if (canberra_ctx == NULL) ca_context_create(&canberra_ctx);
|
||||
ca_context_play(
|
||||
canberra_ctx, 0,
|
||||
CA_PROP_EVENT_ID, which_sound,
|
||||
CA_PROP_EVENT_DESCRIPTION, event_id,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
static void
|
||||
finalize(void) {
|
||||
if (libsn_handle) dlclose(libsn_handle);
|
||||
libsn_handle = NULL;
|
||||
if (canberra_ctx) ca_context_destroy(canberra_ctx);
|
||||
canberra_ctx = NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
#include "unicode-data.h"
|
||||
|
||||
#define MISSING_GLYPH 4
|
||||
#define MAX_NUM_EXTRA_GLYPHS 8
|
||||
#define CELLS_IN_CANVAS ((MAX_NUM_EXTRA_GLYPHS + 1) * 3)
|
||||
#define MAX_NUM_EXTRA_GLYPHS_PUA 4
|
||||
#define MAX_NUM_EXTRA_GLYPHS 8u
|
||||
#define CELLS_IN_CANVAS ((MAX_NUM_EXTRA_GLYPHS + 1u) * 3u)
|
||||
#define MAX_NUM_EXTRA_GLYPHS_PUA 4u
|
||||
|
||||
typedef void (*send_sprite_to_gpu_func)(FONTS_DATA_HANDLE fg, unsigned int, unsigned int, unsigned int, pixel*);
|
||||
send_sprite_to_gpu_func current_send_sprite_to_gpu = NULL;
|
||||
@@ -163,7 +163,7 @@ font_group_for(double font_sz_in_pts, double logical_dpi_x, double logical_dpi_y
|
||||
}
|
||||
add_font_group();
|
||||
FontGroup *fg = font_groups + num_font_groups - 1;
|
||||
memset(fg, 0, sizeof(FontGroup));
|
||||
zero_at_ptr(fg);
|
||||
fg->font_sz_in_pts = font_sz_in_pts;
|
||||
fg->logical_dpi_x = logical_dpi_x;
|
||||
fg->logical_dpi_y = logical_dpi_y;
|
||||
@@ -196,7 +196,7 @@ sprite_map_set_error(int error) {
|
||||
void
|
||||
sprite_tracker_set_limits(size_t max_texture_size_, size_t max_array_len_) {
|
||||
max_texture_size = max_texture_size_;
|
||||
max_array_len = MIN(0xfff, max_array_len_);
|
||||
max_array_len = MIN(0xfffu, max_array_len_);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -207,7 +207,7 @@ do_increment(FontGroup *fg, int *error) {
|
||||
fg->sprite_tracker.ynum = MIN(MAX(fg->sprite_tracker.ynum, fg->sprite_tracker.y + 1), fg->sprite_tracker.max_y);
|
||||
if (fg->sprite_tracker.y >= fg->sprite_tracker.max_y) {
|
||||
fg->sprite_tracker.y = 0; fg->sprite_tracker.z++;
|
||||
if (fg->sprite_tracker.z >= MIN(UINT16_MAX, max_array_len)) *error = 2;
|
||||
if (fg->sprite_tracker.z >= MIN((size_t)UINT16_MAX, max_array_len)) *error = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -301,7 +301,7 @@ free_maps(Font *font) {
|
||||
|
||||
void
|
||||
clear_sprite_map(Font *font) {
|
||||
#define CLEAR(s) s->filled = false; s->rendered = false; s->colored = false; s->glyph = 0; memset(&s->extra_glyphs, 0, sizeof(ExtraGlyphs)); s->x = 0; s->y = 0; s->z = 0; s->ligature_index = 0;
|
||||
#define CLEAR(s) s->filled = false; s->rendered = false; s->colored = false; s->glyph = 0; zero_at_ptr(&s->extra_glyphs); s->x = 0; s->y = 0; s->z = 0; s->ligature_index = 0;
|
||||
SpritePosition *s;
|
||||
for (size_t i = 0; i < sizeof(font->sprite_map)/sizeof(font->sprite_map[0]); i++) {
|
||||
s = font->sprite_map + i;
|
||||
@@ -329,8 +329,8 @@ clear_special_glyph_cache(Font *font) {
|
||||
|
||||
static void
|
||||
sprite_tracker_set_layout(GPUSpriteTracker *sprite_tracker, unsigned int cell_width, unsigned int cell_height) {
|
||||
sprite_tracker->xnum = MIN(MAX(1, max_texture_size / cell_width), UINT16_MAX);
|
||||
sprite_tracker->max_y = MIN(MAX(1, max_texture_size / cell_height), UINT16_MAX);
|
||||
sprite_tracker->xnum = MIN(MAX(1u, max_texture_size / cell_width), (size_t)UINT16_MAX);
|
||||
sprite_tracker->max_y = MIN(MAX(1u, max_texture_size / cell_height), (size_t)UINT16_MAX);
|
||||
sprite_tracker->ynum = 1;
|
||||
sprite_tracker->x = 0; sprite_tracker->y = 0; sprite_tracker->z = 0;
|
||||
}
|
||||
@@ -586,7 +586,7 @@ render_alpha_mask(uint8_t *alpha_mask, pixel* dest, Region *src_rect, Region *de
|
||||
for(size_t sc = src_rect->left, dc = dest_rect->left; sc < src_rect->right && dc < dest_rect->right; sc++, dc++) {
|
||||
pixel val = d[dc];
|
||||
uint8_t alpha = s[sc];
|
||||
d[dc] = 0xffffff00 | MIN(0xff, alpha + (val & 0xff));
|
||||
d[dc] = 0xffffff00 | MIN(0xffu, alpha + (val & 0xff));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -650,11 +650,6 @@ extract_cell_from_canvas(FontGroup *fg, unsigned int i, unsigned int num_cells)
|
||||
return ans;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
is_private_use(char_type ch) {
|
||||
return (0xe000 <= ch && ch <= 0xf8ff) || (0xF0000 <= ch && ch <= 0xFFFFF) || (0x100000 <= ch && ch <= 0x10FFFF);
|
||||
}
|
||||
|
||||
static inline void
|
||||
render_group(FontGroup *fg, unsigned int num_cells, unsigned int num_glyphs, CPUCell *cpu_cells, GPUCell *gpu_cells, hb_glyph_info_t *info, hb_glyph_position_t *positions, Font *font, glyph_index glyph, ExtraGlyphs *extra_glyphs, bool center_glyph) {
|
||||
static SpritePosition* sprite_position[16];
|
||||
@@ -721,7 +716,7 @@ num_codepoints_in_cell(CPUCell *cell) {
|
||||
static inline void
|
||||
shape(CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, index_type num_cells, hb_font_t *font, bool disable_ligature) {
|
||||
if (group_state.groups_capacity <= 2 * num_cells) {
|
||||
group_state.groups_capacity = MAX(128, 2 * num_cells); // avoid unnecessary reallocs
|
||||
group_state.groups_capacity = MAX(128u, 2 * num_cells); // avoid unnecessary reallocs
|
||||
group_state.groups = realloc(group_state.groups, sizeof(Group) * group_state.groups_capacity);
|
||||
if (!group_state.groups) fatal("Out of memory");
|
||||
}
|
||||
@@ -733,7 +728,7 @@ shape(CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, index_type num_cells, hb
|
||||
group_state.current_cell_data.num_codepoints = num_codepoints_in_cell(first_cpu_cell);
|
||||
group_state.current_cell_data.codepoints_consumed = 0;
|
||||
group_state.current_cell_data.current_codepoint = first_cpu_cell->ch;
|
||||
memset(group_state.groups, 0, sizeof(Group) * group_state.groups_capacity);
|
||||
zero_at_ptr_count(group_state.groups, group_state.groups_capacity);
|
||||
group_state.group_idx = 0;
|
||||
group_state.glyph_idx = 0;
|
||||
group_state.cell_idx = 0;
|
||||
@@ -842,7 +837,7 @@ shape_run(CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, index_type num_cells
|
||||
uint32_t cluster, next_cluster;
|
||||
bool add_to_current_group;
|
||||
#define G(x) (group_state.x)
|
||||
#define MAX_GLYPHS_IN_GROUP (MAX_NUM_EXTRA_GLYPHS + 1)
|
||||
#define MAX_GLYPHS_IN_GROUP (MAX_NUM_EXTRA_GLYPHS + 1u)
|
||||
while (G(glyph_idx) < G(num_glyphs) && G(cell_idx) < G(num_cells)) {
|
||||
glyph_index glyph_id = G(info)[G(glyph_idx)].codepoint;
|
||||
cluster = G(info)[G(glyph_idx)].cluster;
|
||||
@@ -1077,7 +1072,7 @@ render_line(FONTS_DATA_HANDLE fg_, Line *line, index_type lnum, Cursor *cursor,
|
||||
if (is_private_use(cpu_cell->ch)
|
||||
&& cell_font_idx != BOX_FONT
|
||||
&& cell_font_idx != MISSING_FONT) {
|
||||
int desired_cells = 1;
|
||||
unsigned int desired_cells = 1;
|
||||
if (cell_font_idx > 0) {
|
||||
Font *font = (fg->fonts + cell_font_idx);
|
||||
glyph_index glyph_id = glyph_id_for_codepoint(font->face, cpu_cell->ch);
|
||||
@@ -1086,7 +1081,7 @@ render_line(FONTS_DATA_HANDLE fg_, Line *line, index_type lnum, Cursor *cursor,
|
||||
desired_cells = ceilf((float)width / fg->cell_width);
|
||||
}
|
||||
|
||||
int num_spaces = 0;
|
||||
unsigned int num_spaces = 0;
|
||||
while ((line->cpu_cells[i+num_spaces+1].ch == ' ')
|
||||
&& num_spaces < MAX_NUM_EXTRA_GLYPHS_PUA
|
||||
&& num_spaces < desired_cells
|
||||
|
||||
@@ -46,6 +46,6 @@ right_shift_canvas(pixel *canvas, size_t width, size_t height, size_t amt) {
|
||||
size_t r;
|
||||
for (r = 0, src = canvas; r < height; r++, src += width) {
|
||||
memmove(src + amt, src, sizeof(pixel) * (width - amt));
|
||||
memset(src, 0, sizeof(pixel) * amt);
|
||||
zero_at_ptr_count(src, amt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,11 +123,15 @@ get_height_for_char(Face *self, char ch) {
|
||||
static inline unsigned int
|
||||
calc_cell_height(Face *self, bool for_metrics) {
|
||||
unsigned int ans = font_units_to_pixels_y(self, self->height);
|
||||
unsigned int underscore_height = get_height_for_char(self, '_');
|
||||
if (for_metrics && global_state.debug_font_fallback && underscore_height > ans) {
|
||||
printf("Increasing cell height by %u pixels to work around buggy font that renders underscore outside the bounding box\n", underscore_height - ans);
|
||||
if (for_metrics) {
|
||||
unsigned int underscore_height = get_height_for_char(self, '_');
|
||||
if (underscore_height > ans) {
|
||||
if (global_state.debug_font_fallback) printf(
|
||||
"Increasing cell height by %u pixels to work around buggy font that renders underscore outside the bounding box\n", underscore_height - ans);
|
||||
return underscore_height;
|
||||
}
|
||||
}
|
||||
return MAX(ans, underscore_height);
|
||||
return ans;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
|
||||
4251
kitty/gl-wrapper.c
generated
4251
kitty/gl-wrapper.c
generated
File diff suppressed because it is too large
Load Diff
9550
kitty/gl-wrapper.h
generated
9550
kitty/gl-wrapper.h
generated
File diff suppressed because it is too large
Load Diff
366
kitty/gl.c
Normal file
366
kitty/gl.c
Normal file
@@ -0,0 +1,366 @@
|
||||
/*
|
||||
* gl.c
|
||||
* Copyright (C) 2019 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#include "gl.h"
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include "glfw-wrapper.h"
|
||||
#include "state.h"
|
||||
|
||||
// GL setup and error handling {{{
|
||||
static void
|
||||
check_for_gl_error(void UNUSED *ret, const char *name, GLADapiproc UNUSED funcptr, int UNUSED len_args, ...) {
|
||||
#define f(msg) fatal("OpenGL error: %s (calling function: %s)", msg, name); break;
|
||||
GLenum code = glad_glGetError();
|
||||
switch(code) {
|
||||
case GL_NO_ERROR: break;
|
||||
case GL_INVALID_ENUM:
|
||||
f("An enum value is invalid (GL_INVALID_ENUM)");
|
||||
case GL_INVALID_VALUE:
|
||||
f("An numeric value is invalid (GL_INVALID_VALUE)");
|
||||
case GL_INVALID_OPERATION:
|
||||
f("This operation is invalid (GL_INVALID_OPERATION)");
|
||||
case GL_INVALID_FRAMEBUFFER_OPERATION:
|
||||
f("The framebuffer object is not complete (GL_INVALID_FRAMEBUFFER_OPERATION)");
|
||||
case GL_OUT_OF_MEMORY:
|
||||
f("There is not enough memory left to execute the command. (GL_OUT_OF_MEMORY)");
|
||||
case GL_STACK_UNDERFLOW:
|
||||
f("An attempt has been made to perform an operation that would cause an internal stack to underflow. (GL_STACK_UNDERFLOW)");
|
||||
case GL_STACK_OVERFLOW:
|
||||
f("An attempt has been made to perform an operation that would cause an internal stack to overflow. (GL_STACK_OVERFLOW)");
|
||||
default:
|
||||
fatal("An unknown OpenGL error occurred with code: %d (calling function: %s)", code, name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gl_init() {
|
||||
static bool glad_loaded = false;
|
||||
if (!glad_loaded) {
|
||||
int gl_version = gladLoadGL(glfwGetProcAddress);
|
||||
if (!gl_version) {
|
||||
fatal("Loading the OpenGL library failed");
|
||||
}
|
||||
if (!global_state.debug_gl) {
|
||||
gladUninstallGLDebug();
|
||||
}
|
||||
gladSetGLPostCallback(check_for_gl_error);
|
||||
#define ARB_TEST(name) \
|
||||
if (!GLAD_GL_ARB_##name) { \
|
||||
fatal("The OpenGL driver on this system is missing the required extension: ARB_%s", #name); \
|
||||
}
|
||||
ARB_TEST(texture_storage);
|
||||
#undef ARB_TEST
|
||||
glad_loaded = true;
|
||||
int gl_major = GLAD_VERSION_MAJOR(gl_version);
|
||||
int gl_minor = GLAD_VERSION_MINOR(gl_version);
|
||||
if (global_state.debug_gl) printf("GL version string: '%s' Detected version: %d.%d\n", glGetString(GL_VERSION), gl_major, gl_minor);
|
||||
if (gl_major < OPENGL_REQUIRED_VERSION_MAJOR || (gl_major == OPENGL_REQUIRED_VERSION_MAJOR && gl_minor < OPENGL_REQUIRED_VERSION_MINOR)) {
|
||||
fatal("OpenGL version is %d.%d, version >= 3.3 required for kitty", gl_major, gl_minor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
update_surface_size(int w, int h, GLuint offscreen_texture_id) {
|
||||
glViewport(0, 0, w, h);
|
||||
if (offscreen_texture_id) {
|
||||
glBindTexture(GL_TEXTURE_2D, offscreen_texture_id);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
free_texture(GLuint *tex_id) {
|
||||
glDeleteTextures(1, tex_id);
|
||||
*tex_id = 0;
|
||||
}
|
||||
|
||||
|
||||
// }}}
|
||||
|
||||
// Programs {{{
|
||||
|
||||
static Program programs[64] = {{0}};
|
||||
|
||||
GLuint
|
||||
compile_shader(GLenum shader_type, const char *source) {
|
||||
GLuint shader_id = glCreateShader(shader_type);
|
||||
glShaderSource(shader_id, 1, (const GLchar **)&source, NULL);
|
||||
glCompileShader(shader_id);
|
||||
GLint ret = GL_FALSE;
|
||||
glGetShaderiv(shader_id, GL_COMPILE_STATUS, &ret);
|
||||
if (ret != GL_TRUE) {
|
||||
GLsizei len;
|
||||
static char glbuf[4096];
|
||||
glGetShaderInfoLog(shader_id, sizeof(glbuf), &len, glbuf);
|
||||
log_error("Failed to compile GLSL shader!\n%s", glbuf);
|
||||
glDeleteShader(shader_id);
|
||||
PyErr_SetString(PyExc_ValueError, "Failed to compile shader");
|
||||
return 0;
|
||||
}
|
||||
return shader_id;
|
||||
}
|
||||
|
||||
Program*
|
||||
program_ptr(int program) { return programs + (size_t)program; }
|
||||
|
||||
GLuint
|
||||
program_id(int program) { return programs[program].id; }
|
||||
|
||||
|
||||
void
|
||||
init_uniforms(int program) {
|
||||
Program *p = programs + program;
|
||||
glGetProgramiv(p->id, GL_ACTIVE_UNIFORMS, &(p->num_of_uniforms));
|
||||
for (GLint i = 0; i < p->num_of_uniforms; i++) {
|
||||
Uniform *u = p->uniforms + i;
|
||||
glGetActiveUniform(p->id, (GLuint)i, sizeof(u->name)/sizeof(u->name[0]), NULL, &(u->size), &(u->type), u->name);
|
||||
u->location = glGetUniformLocation(p->id, u->name);
|
||||
u->idx = i;
|
||||
}
|
||||
}
|
||||
|
||||
GLint
|
||||
get_uniform_information(int program, const char *name, GLenum information_type) {
|
||||
GLint q; GLuint t;
|
||||
static const char* names[] = {""};
|
||||
names[0] = name;
|
||||
GLuint pid = program_id(program);
|
||||
glGetUniformIndices(pid, 1, (void*)names, &t);
|
||||
glGetActiveUniformsiv(pid, 1, &t, information_type, &q);
|
||||
return q;
|
||||
}
|
||||
|
||||
GLint
|
||||
attrib_location(int program, const char *name) {
|
||||
GLint ans = glGetAttribLocation(programs[program].id, name);
|
||||
return ans;
|
||||
}
|
||||
|
||||
GLuint
|
||||
block_index(int program, const char *name) {
|
||||
GLuint ans = glGetUniformBlockIndex(programs[program].id, name);
|
||||
if (ans == GL_INVALID_INDEX) { fatal("Could not find block index"); }
|
||||
return ans;
|
||||
}
|
||||
|
||||
|
||||
GLint
|
||||
block_size(int program, GLuint block_index) {
|
||||
GLint ans;
|
||||
glGetActiveUniformBlockiv(programs[program].id, block_index, GL_UNIFORM_BLOCK_DATA_SIZE, &ans);
|
||||
return ans;
|
||||
}
|
||||
|
||||
void
|
||||
bind_program(int program) {
|
||||
glUseProgram(programs[program].id);
|
||||
}
|
||||
|
||||
void
|
||||
unbind_program(void) {
|
||||
glUseProgram(0);
|
||||
}
|
||||
// }}}
|
||||
|
||||
// Buffers {{{
|
||||
|
||||
typedef struct {
|
||||
GLuint id;
|
||||
GLsizeiptr size;
|
||||
GLenum usage;
|
||||
} Buffer;
|
||||
|
||||
|
||||
static Buffer buffers[MAX_CHILDREN * 6 + 4] = {{0}};
|
||||
|
||||
static ssize_t
|
||||
create_buffer(GLenum usage) {
|
||||
GLuint buffer_id;
|
||||
glGenBuffers(1, &buffer_id);
|
||||
for (size_t i = 0; i < sizeof(buffers)/sizeof(buffers[0]); i++) {
|
||||
if (buffers[i].id == 0) {
|
||||
buffers[i].id = buffer_id;
|
||||
buffers[i].size = 0;
|
||||
buffers[i].usage = usage;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
glDeleteBuffers(1, &buffer_id);
|
||||
fatal("Too many buffers");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
delete_buffer(ssize_t buf_idx) {
|
||||
glDeleteBuffers(1, &(buffers[buf_idx].id));
|
||||
buffers[buf_idx].id = 0;
|
||||
buffers[buf_idx].size = 0;
|
||||
}
|
||||
|
||||
static GLuint
|
||||
bind_buffer(ssize_t buf_idx) {
|
||||
glBindBuffer(buffers[buf_idx].usage, buffers[buf_idx].id);
|
||||
return buffers[buf_idx].id;
|
||||
}
|
||||
|
||||
static void
|
||||
unbind_buffer(ssize_t buf_idx) {
|
||||
glBindBuffer(buffers[buf_idx].usage, 0);
|
||||
}
|
||||
|
||||
static inline void
|
||||
alloc_buffer(ssize_t idx, GLsizeiptr size, GLenum usage) {
|
||||
Buffer *b = buffers + idx;
|
||||
if (b->size == size) return;
|
||||
b->size = size;
|
||||
glBufferData(b->usage, size, NULL, usage);
|
||||
}
|
||||
|
||||
static inline void*
|
||||
map_buffer(ssize_t idx, GLenum access) {
|
||||
void *ans = glMapBuffer(buffers[idx].usage, access);
|
||||
return ans;
|
||||
}
|
||||
|
||||
static inline void
|
||||
unmap_buffer(ssize_t idx) {
|
||||
glUnmapBuffer(buffers[idx].usage);
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
// Vertex Array Objects (VAO) {{{
|
||||
|
||||
typedef struct {
|
||||
GLuint id;
|
||||
size_t num_buffers;
|
||||
ssize_t buffers[10];
|
||||
} VAO;
|
||||
|
||||
static VAO vaos[4*MAX_CHILDREN + 10] = {{0}};
|
||||
|
||||
ssize_t
|
||||
create_vao(void) {
|
||||
GLuint vao_id;
|
||||
glGenVertexArrays(1, &vao_id);
|
||||
for (size_t i = 0; i < sizeof(vaos)/sizeof(vaos[0]); i++) {
|
||||
if (!vaos[i].id) {
|
||||
vaos[i].id = vao_id;
|
||||
vaos[i].num_buffers = 0;
|
||||
glBindVertexArray(vao_id);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
glDeleteVertexArrays(1, &vao_id);
|
||||
fatal("Too many VAOs");
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t
|
||||
add_buffer_to_vao(ssize_t vao_idx, GLenum usage) {
|
||||
VAO* vao = vaos + vao_idx;
|
||||
if (vao->num_buffers >= sizeof(vao->buffers) / sizeof(vao->buffers[0])) {
|
||||
fatal("Too many buffers in a single VAO");
|
||||
}
|
||||
ssize_t buf = create_buffer(usage);
|
||||
vao->buffers[vao->num_buffers++] = buf;
|
||||
return vao->num_buffers - 1;
|
||||
}
|
||||
|
||||
static void
|
||||
add_located_attribute_to_vao(ssize_t vao_idx, GLint aloc, GLint size, GLenum data_type, GLsizei stride, void *offset, GLuint divisor) {
|
||||
VAO *vao = vaos + vao_idx;
|
||||
if (!vao->num_buffers) fatal("You must create a buffer for this attribute first");
|
||||
ssize_t buf = vao->buffers[vao->num_buffers - 1];
|
||||
bind_buffer(buf);
|
||||
glEnableVertexAttribArray(aloc);
|
||||
switch(data_type) {
|
||||
case GL_BYTE:
|
||||
case GL_UNSIGNED_BYTE:
|
||||
case GL_SHORT:
|
||||
case GL_UNSIGNED_SHORT:
|
||||
case GL_INT:
|
||||
case GL_UNSIGNED_INT:
|
||||
glVertexAttribIPointer(aloc, size, data_type, stride, offset);
|
||||
break;
|
||||
default:
|
||||
glVertexAttribPointer(aloc, size, data_type, GL_FALSE, stride, offset);
|
||||
break;
|
||||
}
|
||||
if (divisor) {
|
||||
glVertexAttribDivisor(aloc, divisor);
|
||||
}
|
||||
unbind_buffer(buf);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
add_attribute_to_vao(int p, ssize_t vao_idx, const char *name, GLint size, GLenum data_type, GLsizei stride, void *offset, GLuint divisor) {
|
||||
GLint aloc = attrib_location(p, name);
|
||||
if (aloc == -1) fatal("No attribute named: %s found in this program", name);
|
||||
add_located_attribute_to_vao(vao_idx, aloc, size, data_type, stride, offset, divisor);
|
||||
}
|
||||
|
||||
void
|
||||
remove_vao(ssize_t vao_idx) {
|
||||
VAO *vao = vaos + vao_idx;
|
||||
while (vao->num_buffers) {
|
||||
vao->num_buffers--;
|
||||
delete_buffer(vao->buffers[vao->num_buffers]);
|
||||
}
|
||||
glDeleteVertexArrays(1, &(vao->id));
|
||||
vaos[vao_idx].id = 0;
|
||||
}
|
||||
|
||||
void
|
||||
bind_vertex_array(ssize_t vao_idx) {
|
||||
glBindVertexArray(vaos[vao_idx].id);
|
||||
}
|
||||
|
||||
void
|
||||
unbind_vertex_array(void) {
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
alloc_vao_buffer(ssize_t vao_idx, GLsizeiptr size, size_t bufnum, GLenum usage) {
|
||||
ssize_t buf_idx = vaos[vao_idx].buffers[bufnum];
|
||||
bind_buffer(buf_idx);
|
||||
alloc_buffer(buf_idx, size, usage);
|
||||
return buf_idx;
|
||||
}
|
||||
|
||||
void*
|
||||
map_vao_buffer(ssize_t vao_idx, size_t bufnum, GLenum access) {
|
||||
ssize_t buf_idx = vaos[vao_idx].buffers[bufnum];
|
||||
bind_buffer(buf_idx);
|
||||
return map_buffer(buf_idx, access);
|
||||
}
|
||||
|
||||
void*
|
||||
alloc_and_map_vao_buffer(ssize_t vao_idx, GLsizeiptr size, size_t bufnum, GLenum usage, GLenum access) {
|
||||
ssize_t buf_idx = alloc_vao_buffer(vao_idx, size, bufnum, usage);
|
||||
return map_buffer(buf_idx, access);
|
||||
}
|
||||
|
||||
void
|
||||
bind_vao_uniform_buffer(ssize_t vao_idx, size_t bufnum, GLuint block_index) {
|
||||
ssize_t buf_idx = vaos[vao_idx].buffers[bufnum];
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, block_index, buffers[buf_idx].id);
|
||||
}
|
||||
|
||||
void
|
||||
unmap_vao_buffer(ssize_t vao_idx, size_t bufnum) {
|
||||
ssize_t buf_idx = vaos[vao_idx].buffers[bufnum];
|
||||
unmap_buffer(buf_idx);
|
||||
unbind_buffer(buf_idx);
|
||||
}
|
||||
|
||||
// }}}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user