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: 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 -m flake8 --count .
|
||||||
- run: python3 setup.py build --debug --verbose
|
- 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 man
|
||||||
- run: make FAIL_WARN=-W html
|
- 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
|
- run: python3 setup.py linux-package --update-check-interval=0
|
||||||
|
|
||||||
lin-35:
|
lin-35:
|
||||||
@@ -26,7 +32,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run: /opt/py3.5/bin/python3 setup.py build --debug --verbose --sanitize
|
- 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:
|
lin-37:
|
||||||
docker:
|
docker:
|
||||||
@@ -38,7 +44,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run: /opt/py3.7/bin/python3 setup.py build --debug --verbose --sanitize
|
- 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:
|
lin-bundle:
|
||||||
docker:
|
docker:
|
||||||
@@ -49,8 +55,9 @@ jobs:
|
|||||||
- checkout
|
- checkout
|
||||||
- run: echo "export LD_LIBRARY_PATH=$SW/lib" >> $BASH_ENV
|
- run: echo "export LD_LIBRARY_PATH=$SW/lib" >> $BASH_ENV
|
||||||
- run: echo "export PKG_CONFIG_PATH=$SW/lib/pkgconfig" >> $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 setup.py build --debug --verbose
|
||||||
- run: $SW/bin/python3 test.py
|
- run: ./kitty/launcher/kitty +launch test.py
|
||||||
|
|
||||||
mac-bundle:
|
mac-bundle:
|
||||||
macos:
|
macos:
|
||||||
@@ -65,21 +72,23 @@ jobs:
|
|||||||
- run: curl https://download.calibre-ebook.com/travis/kitty/osx.tar.xz | tar xJ -C $SW
|
- 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: echo "export PATH=$SW/bin:$PATH" >> $BASH_ENV
|
||||||
- run: python3 setup.py build --debug --verbose
|
- run: python3 setup.py build --debug --verbose
|
||||||
- run: python3 test.py
|
- run: ./kitty/launcher/kitty +launch test.py
|
||||||
|
|
||||||
mac-brew:
|
mac-brew:
|
||||||
macos:
|
macos:
|
||||||
xcode: "10.1.0"
|
xcode: "10.2.0"
|
||||||
environment:
|
environment:
|
||||||
LC_ALL: en_US.UTF-8
|
LC_ALL: en_US.UTF-8
|
||||||
LANG: en_US.UTF-8
|
LANG: en_US.UTF-8
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run: brew bundle
|
- run: brew bundle
|
||||||
- run: python3 logo/make.py
|
|
||||||
- run: python3 setup.py build --debug --verbose
|
- run: python3 setup.py build --debug --verbose
|
||||||
- run: python3 test.py
|
- run: ./kitty/launcher/kitty +launch test.py
|
||||||
- run: python3 setup.py macos-bundle
|
- 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:
|
workflows:
|
||||||
@@ -90,5 +99,6 @@ workflows:
|
|||||||
- lin-sys
|
- lin-sys
|
||||||
- lin-35
|
- lin-35
|
||||||
- lin-37
|
- lin-37
|
||||||
|
- lin-package
|
||||||
- lin-bundle
|
- lin-bundle
|
||||||
- mac-brew
|
- 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
|
RUN apt-get install -y libreadline-dev zlib1g-dev libssl-dev libbz2-dev libsqlite3-dev libffi-dev
|
||||||
|
|
||||||
# kitty deps
|
# 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
|
# Needed to build kitty docs
|
||||||
RUN pip3 install sphinx
|
RUN pip3 install sphinx
|
||||||
|
|||||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -5,12 +5,11 @@ tags
|
|||||||
build
|
build
|
||||||
linux-package
|
linux-package
|
||||||
kitty.app
|
kitty.app
|
||||||
logo/*.iconset
|
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
|
link_commands.json
|
||||||
glad/out
|
glad/out
|
||||||
asan-launcher
|
kitty/launcher
|
||||||
asan-launcher.dSYM
|
*.dSYM
|
||||||
kitty-profile
|
|
||||||
dev
|
dev
|
||||||
__pycache__
|
__pycache__
|
||||||
glfw/wayland-*-client-protocol.[ch]
|
glfw/wayland-*-client-protocol.[ch]
|
||||||
|
|||||||
3
Brewfile
3
Brewfile
@@ -1,6 +1,5 @@
|
|||||||
brew 'pkg-config'
|
brew 'pkg-config'
|
||||||
brew 'imagemagick'
|
brew 'imagemagick'
|
||||||
brew 'optipng'
|
|
||||||
brew 'librsvg'
|
|
||||||
brew 'harfbuzz'
|
brew 'harfbuzz'
|
||||||
brew 'python'
|
brew 'python'
|
||||||
|
brew 'sphinx-doc'
|
||||||
|
|||||||
7
Makefile
7
Makefile
@@ -28,12 +28,7 @@ asan:
|
|||||||
profile:
|
profile:
|
||||||
python3 setup.py build $(VVAL) --profile
|
python3 setup.py build $(VVAL) --profile
|
||||||
|
|
||||||
logo/kitty.iconset/icon_256x256.png: logo/kitty.svg logo/make.py
|
app:
|
||||||
logo/make.py
|
|
||||||
|
|
||||||
rendered_logo: logo/kitty.iconset/icon_256x256.png
|
|
||||||
|
|
||||||
app: rendered_logo
|
|
||||||
python3 setup.py kitty.app $(VVAL)
|
python3 setup.py kitty.app $(VVAL)
|
||||||
|
|
||||||
man:
|
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
|
* libpng
|
||||||
* freetype (not needed on macOS)
|
* freetype (not needed on macOS)
|
||||||
* fontconfig (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)
|
* 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``)
|
* pygments (optional, need for syntax highlighting in ``kitty +kitten diff``)
|
||||||
|
|
||||||
@@ -28,7 +29,7 @@ Build-time dependencies:
|
|||||||
* gcc or clang
|
* gcc or clang
|
||||||
* pkg-config
|
* pkg-config
|
||||||
* For building on Linux in addition to the above dependencies you might also need to install the ``-dev`` packages for:
|
* 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.
|
if they are not already installed by your distro.
|
||||||
|
|
||||||
Install and run from source
|
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::
|
You can run |kitty|, as::
|
||||||
|
|
||||||
python3 .
|
./kitty/launcher/kitty
|
||||||
|
|
||||||
If that works, you can create a script to launch |kitty|:
|
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
|
||||||
.. 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
|
|
||||||
just ``kitty``.
|
just ``kitty``.
|
||||||
|
|
||||||
|
|
||||||
Building kitty.app on macOS from source
|
Building kitty.app on macOS from source
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
|
|
||||||
Install `imagemagick`, `optipng` and `librsvg` using `brew` or similar (needed
|
Run::
|
||||||
for the logo generation step). And run::
|
|
||||||
|
|
||||||
make app
|
make app
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,61 @@ Changelog
|
|||||||
|kitty| is a feature full, cross-platform, *fast*, GPU based terminal emulator.
|
|kitty| is a feature full, cross-platform, *fast*, GPU based terminal emulator.
|
||||||
To update |kitty|, :doc:`follow the instructions <binary>`.
|
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]
|
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 {{{
|
# config file docs {{{
|
||||||
|
|
||||||
class ConfLexer(RegexLexer):
|
class ConfLexer(RegexLexer):
|
||||||
@@ -483,9 +525,12 @@ def process_shortcut_link(env, refnode, has_explicit_title, title, target):
|
|||||||
conf_name, slug = 'kitty', conf_name
|
conf_name, slug = 'kitty', conf_name
|
||||||
full_name = conf_name + '.' + slug
|
full_name = conf_name + '.' + slug
|
||||||
try:
|
try:
|
||||||
target, title = shortcut_slugs[full_name]
|
target, stitle = shortcut_slugs[full_name]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.warning('Unknown shortcut: {}'.format(target), location=refnode)
|
logger.warning('Unknown shortcut: {}'.format(target), location=refnode)
|
||||||
|
else:
|
||||||
|
if not has_explicit_title:
|
||||||
|
title = stitle
|
||||||
return title, target
|
return title, target
|
||||||
|
|
||||||
|
|
||||||
@@ -537,6 +582,7 @@ def setup(app):
|
|||||||
from kittens.runner import all_kitten_names
|
from kittens.runner import all_kitten_names
|
||||||
all_kitten_names = all_kitten_names()
|
all_kitten_names = all_kitten_names()
|
||||||
write_cli_docs(all_kitten_names)
|
write_cli_docs(all_kitten_names)
|
||||||
|
write_remote_control_protocol_docs()
|
||||||
write_conf_docs(app, all_kitten_names)
|
write_conf_docs(app, all_kitten_names)
|
||||||
app.add_lexer('session', SessionLexer())
|
app.add_lexer('session', SessionLexer())
|
||||||
app.add_role('link', link_role)
|
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:
|
A list of pre-made color themes for kitty is available at:
|
||||||
`kitty-themes <https://github.com/dexpota/kitty-themes>`_
|
`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?
|
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
|
manager/desktop environment. For ways to do it with kitty (or indeed any
|
||||||
terminal) in different environments,
|
terminal) in different environments,
|
||||||
see `here <https://github.com/kovidgoyal/kitty/issues/45>`_.
|
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.
|
columns.
|
||||||
* Selecting text automatically copies it to the primary clipboard (on
|
* Selecting text automatically copies it to the primary clipboard (on
|
||||||
platforms with a primary clipboard).
|
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
|
Font control
|
||||||
@@ -448,6 +450,14 @@ Add the following to your :file:`~/.bashrc`
|
|||||||
|
|
||||||
source <(kitty + complete setup bash)
|
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
|
zsh
|
||||||
~~~~~~~~~
|
~~~~~~~~~
|
||||||
@@ -486,3 +496,4 @@ See :doc:`changelog`.
|
|||||||
|
|
||||||
*
|
*
|
||||||
kittens/*
|
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
|
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.
|
of some `tearing <https://en.wikipedia.org/wiki/Screen_tearing>`_ while scrolling.
|
||||||
|
|
||||||
You can generate detailed per-function performance data using
|
You can generate detailed per-function performance data using `gperftools
|
||||||
`gperftools <https://github.com/gperftools/gperftools>`_. Build |kitty| with
|
<https://github.com/gperftools/gperftools>`_. Build |kitty| with `make
|
||||||
`make profile` which will create an executable called `kitty-profile`. Run
|
profile`. Run kitty and perform the task you want to analyse, for example,
|
||||||
that and perform the task you want to analyse, for example, scrolling a large
|
scrolling a large file with `less`. After you quit, function call statistics
|
||||||
file with `less`. After you quit, function call statistics will be printed to
|
will be printed to `stdout` and you can use tools like *kcachegrind* for more
|
||||||
`stdout` and you can use tools like *kcachegrind* for more detailed analysis.
|
detailed analysis.
|
||||||
|
|
||||||
Here are some CPU usage numbers for the task of scrolling a file continuously
|
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
|
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
|
therefore can control |kitty|. It can, however, be useful to block programs
|
||||||
running on other computers (for example, over ssh) or as other users.
|
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
|
.. include:: generated/cli-kitty-at.rst
|
||||||
|
|||||||
@@ -8,9 +8,11 @@ import shlex
|
|||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
cmdline = (
|
cmdline = (
|
||||||
'glad --profile core --out-path {dest} --api gl=3.3 --generator {generator} --spec gl'
|
'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'
|
' --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')
|
clean('out')
|
||||||
|
|
||||||
subprocess.check_call(
|
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():
|
def export():
|
||||||
c = open('out/src/glad.c', 'rb').read().decode('utf-8')
|
with open('out/include/glad/gl.h', 'r', encoding='utf-8') as source:
|
||||||
functions = []
|
data = source.read()
|
||||||
|
data = strip_trailing_whitespace(data)
|
||||||
|
|
||||||
def sub(m):
|
with open('../kitty/gl-wrapper.h', 'w', encoding='utf-8') as dest:
|
||||||
functions.append(m.group(2))
|
dest.write(data)
|
||||||
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))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
89
glfw/backend_utils.c
vendored
89
glfw/backend_utils.c
vendored
@@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
@@ -220,24 +222,90 @@ dispatchTimers(EventLoopData *eld) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
drain_wakeup_fd(int fd, int events, void* data) {
|
drain_wakeup_fd(int fd, EventLoopData* eld) {
|
||||||
static char drain_buf[64];
|
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
|
void
|
||||||
initPollData(EventLoopData *eld, int wakeup_fd, int display_fd) {
|
check_for_wakeup_events(EventLoopData *eld) {
|
||||||
addWatch(eld, "display", display_fd, POLLIN, 1, NULL, NULL);
|
#ifdef HAS_EVENT_FD
|
||||||
addWatch(eld, "wakeup", wakeup_fd, POLLIN, 1, drain_wakeup_fd, NULL);
|
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
|
int
|
||||||
pollForEvents(EventLoopData *eld, double timeout) {
|
pollForEvents(EventLoopData *eld, double timeout) {
|
||||||
int read_ok = 0;
|
int read_ok = 0;
|
||||||
timeout = prepareForPoll(eld, timeout);
|
timeout = prepareForPoll(eld, timeout);
|
||||||
|
EVDBG("pollForEvents final timeout: %.3f", timeout);
|
||||||
int result;
|
int result;
|
||||||
double end_time = monotonic() + timeout;
|
double end_time = monotonic() + timeout;
|
||||||
|
eld->wakeup_fd_ready = false;
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
if (timeout >= 0) {
|
if (timeout >= 0) {
|
||||||
@@ -270,17 +338,6 @@ pollForEvents(EventLoopData *eld, double timeout) {
|
|||||||
return read_ok;
|
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
|
// Splits and translates a text/uri-list into separate file paths
|
||||||
// NOTE: This function destroys the provided string
|
// 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 <unistd.h>
|
||||||
#include <stdbool.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 unsigned long long id_type;
|
||||||
typedef void(*watch_callback_func)(int, int, void*);
|
typedef void(*watch_callback_func)(int, int, void*);
|
||||||
typedef void(*timer_callback_func)(id_type, void*);
|
typedef void(*timer_callback_func)(id_type, void*);
|
||||||
@@ -56,13 +66,19 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
struct pollfd fds[32];
|
struct pollfd fds[32];
|
||||||
|
#ifdef HAS_EVENT_FD
|
||||||
|
int wakeupFd;
|
||||||
|
#else
|
||||||
int wakeupFds[2];
|
int wakeupFds[2];
|
||||||
|
#endif
|
||||||
|
bool wakeup_data_read, wakeup_fd_ready;
|
||||||
nfds_t watches_count, timers_count;
|
nfds_t watches_count, timers_count;
|
||||||
Watch watches[32];
|
Watch watches[32];
|
||||||
Timer timers[128];
|
Timer timers[128];
|
||||||
} EventLoopData;
|
} 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);
|
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 removeWatch(EventLoopData *eld, id_type watch_id);
|
||||||
void toggleWatch(EventLoopData *eld, id_type watch_id, int enabled);
|
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 pollWithTimeout(struct pollfd *fds, nfds_t nfds, double timeout);
|
||||||
int pollForEvents(EventLoopData *eld, double timeout);
|
int pollForEvents(EventLoopData *eld, double timeout);
|
||||||
unsigned dispatchTimers(EventLoopData *eld);
|
unsigned dispatchTimers(EventLoopData *eld);
|
||||||
void closeFds(int *fds, size_t count);
|
void finalizePollData(EventLoopData *eld);
|
||||||
void initPollData(EventLoopData *eld, int wakeup_fd, int display_fd);
|
bool initPollData(EventLoopData *eld, int display_fd);
|
||||||
char** parseUriList(char* text, int* count);
|
char** parseUriList(char* text, int* count);
|
||||||
|
void wakeupEventLoop(EventLoopData *eld);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 macOS - www.glfw.org
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -23,9 +23,12 @@
|
|||||||
// distribution.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// It is fine to use C99 in this file because it will not be built with VS
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include <sys/param.h> // For MAXPATHLEN
|
#include <sys/param.h> // For MAXPATHLEN
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
// Change to our application bundle's resources directory, if present
|
// Change to our application bundle's resources directory, if present
|
||||||
//
|
//
|
||||||
@@ -247,13 +250,13 @@ static bool initializeTIS(void)
|
|||||||
CFStringRef* kPropertyUnicodeKeyLayoutData =
|
CFStringRef* kPropertyUnicodeKeyLayoutData =
|
||||||
CFBundleGetDataPointerForName(_glfw.ns.tis.bundle,
|
CFBundleGetDataPointerForName(_glfw.ns.tis.bundle,
|
||||||
CFSTR("kTISPropertyUnicodeKeyLayoutData"));
|
CFSTR("kTISPropertyUnicodeKeyLayoutData"));
|
||||||
_glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource =
|
*(void **)&_glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource =
|
||||||
CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
|
CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
|
||||||
CFSTR("TISCopyCurrentKeyboardLayoutInputSource"));
|
CFSTR("TISCopyCurrentKeyboardLayoutInputSource"));
|
||||||
_glfw.ns.tis.GetInputSourceProperty =
|
*(void **)&_glfw.ns.tis.GetInputSourceProperty =
|
||||||
CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
|
CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
|
||||||
CFSTR("TISGetInputSourceProperty"));
|
CFSTR("TISGetInputSourceProperty"));
|
||||||
_glfw.ns.tis.GetKbdType =
|
*(void **)&_glfw.ns.tis.GetKbdType =
|
||||||
CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
|
CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
|
||||||
CFSTR("LMGetKbdType"));
|
CFSTR("LMGetKbdType"));
|
||||||
|
|
||||||
@@ -280,14 +283,16 @@ static bool initializeTIS(void)
|
|||||||
|
|
||||||
- (void)selectedKeyboardInputSourceChanged:(NSObject* )object
|
- (void)selectedKeyboardInputSourceChanged:(NSObject* )object
|
||||||
{
|
{
|
||||||
|
(void)object;
|
||||||
updateUnicodeDataNS();
|
updateUnicodeDataNS();
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)doNothing:(id)object
|
- (void)doNothing:(id)object
|
||||||
{
|
{
|
||||||
|
(void)object;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end // GLFWHelper
|
@end // GLFWHelper
|
||||||
|
|
||||||
@interface GLFWApplication : NSApplication
|
@interface GLFWApplication : NSApplication
|
||||||
- (void)tick_callback;
|
- (void)tick_callback;
|
||||||
@@ -307,6 +312,7 @@ static bool initializeTIS(void)
|
|||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
////// GLFW platform API //////
|
////// GLFW platform API //////
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
@@ -332,6 +338,7 @@ is_cmd_period(NSEvent *event, NSEventModifierFlags modifierFlags) {
|
|||||||
int _glfwPlatformInit(void)
|
int _glfwPlatformInit(void)
|
||||||
{
|
{
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
|
|
||||||
_glfw.ns.helper = [[GLFWHelper alloc] init];
|
_glfw.ns.helper = [[GLFWHelper alloc] init];
|
||||||
|
|
||||||
[NSThread detachNewThreadSelector:@selector(doNothing:)
|
[NSThread detachNewThreadSelector:@selector(doNothing:)
|
||||||
@@ -374,6 +381,7 @@ int _glfwPlatformInit(void)
|
|||||||
_glfw.ns.keyDownMonitor =
|
_glfw.ns.keyDownMonitor =
|
||||||
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyDown
|
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyDown
|
||||||
handler:keydown_block];
|
handler:keydown_block];
|
||||||
|
|
||||||
if (_glfw.hints.init.ns.chdir)
|
if (_glfw.hints.init.ns.chdir)
|
||||||
changeToResourcesDirectory();
|
changeToResourcesDirectory();
|
||||||
|
|
||||||
@@ -394,24 +402,20 @@ int _glfwPlatformInit(void)
|
|||||||
if (!initializeTIS())
|
if (!initializeTIS())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_glfw.ns.displayLinks.lock = [NSLock new];
|
|
||||||
_glfwInitTimerNS();
|
_glfwInitTimerNS();
|
||||||
_glfwInitJoysticksNS();
|
_glfwInitJoysticksNS();
|
||||||
|
|
||||||
_glfwPollMonitorsNS();
|
_glfwPollMonitorsNS();
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
} // autoreleasepool
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformTerminate(void)
|
void _glfwPlatformTerminate(void)
|
||||||
{
|
{
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
|
|
||||||
if (_glfw.ns.displayLinks.lock) {
|
_glfwClearDisplayLinks();
|
||||||
_glfwClearDisplayLinks();
|
|
||||||
[_glfw.ns.displayLinks.lock release];
|
|
||||||
_glfw.ns.displayLinks.lock = nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_glfw.ns.inputSource)
|
if (_glfw.ns.inputSource)
|
||||||
{
|
{
|
||||||
@@ -444,6 +448,7 @@ void _glfwPlatformTerminate(void)
|
|||||||
[_glfw.ns.helper release];
|
[_glfw.ns.helper release];
|
||||||
_glfw.ns.helper = nil;
|
_glfw.ns.helper = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_glfw.ns.keyUpMonitor)
|
if (_glfw.ns.keyUpMonitor)
|
||||||
[NSEvent removeMonitor:_glfw.ns.keyUpMonitor];
|
[NSEvent removeMonitor:_glfw.ns.keyUpMonitor];
|
||||||
if (_glfw.ns.keyDownMonitor)
|
if (_glfw.ns.keyDownMonitor)
|
||||||
@@ -453,7 +458,8 @@ void _glfwPlatformTerminate(void)
|
|||||||
|
|
||||||
_glfwTerminateNSGL();
|
_glfwTerminateNSGL();
|
||||||
_glfwTerminateJoysticksNS();
|
_glfwTerminateJoysticksNS();
|
||||||
}
|
|
||||||
|
} // autoreleasepool
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* _glfwPlatformGetVersionString(void)
|
const char* _glfwPlatformGetVersionString(void)
|
||||||
@@ -468,32 +474,56 @@ const char* _glfwPlatformGetVersionString(void)
|
|||||||
static GLFWtickcallback tick_callback = NULL;
|
static GLFWtickcallback tick_callback = NULL;
|
||||||
static void* tick_callback_data = NULL;
|
static void* tick_callback_data = NULL;
|
||||||
static bool tick_callback_requested = false;
|
static bool tick_callback_requested = false;
|
||||||
|
static pthread_t main_thread;
|
||||||
|
static NSLock *tick_lock = NULL;
|
||||||
|
|
||||||
|
|
||||||
void _glfwDispatchTickCallback() {
|
void _glfwDispatchTickCallback() {
|
||||||
if (tick_callback) {
|
if (tick_lock && tick_callback) {
|
||||||
tick_callback_requested = false;
|
[tick_lock lock];
|
||||||
tick_callback(tick_callback_data);
|
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) {
|
if (!tick_callback_requested) {
|
||||||
tick_callback_requested = true;
|
tick_callback_requested = true;
|
||||||
[NSApp performSelectorOnMainThread:@selector(tick_callback) withObject:nil waitUntilDone:NO];
|
[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) {
|
void _glfwPlatformStopMainLoop(void) {
|
||||||
tick_callback = NULL;
|
|
||||||
[NSApp stop:nil];
|
[NSApp stop:nil];
|
||||||
_glfwPlatformPostEmptyEvent();
|
_glfwCocoaPostEmptyEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformRunMainLoop(GLFWtickcallback callback, void* data) {
|
void _glfwPlatformRunMainLoop(GLFWtickcallback callback, void* data) {
|
||||||
|
main_thread = pthread_self();
|
||||||
tick_callback = callback;
|
tick_callback = callback;
|
||||||
tick_callback_data = data;
|
tick_callback_data = data;
|
||||||
|
tick_lock = [NSLock new];
|
||||||
[NSApp run];
|
[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
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 Cocoa - www.glfw.org
|
// 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>
|
// Copyright (c) 2012 Torsten Walluhn <tw@mad-cad.net>
|
||||||
//
|
//
|
||||||
// This software is provided 'as-is', without any express or implied
|
// This software is provided 'as-is', without any express or implied
|
||||||
@@ -24,6 +24,8 @@
|
|||||||
// distribution.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// It is fine to use C99 in this file because it will not be built with VS
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
@@ -75,7 +77,7 @@ static long getElementValue(_GLFWjoystick* js, _GLFWjoyelementNS* element)
|
|||||||
//
|
//
|
||||||
static CFComparisonResult compareElements(const void* fp,
|
static CFComparisonResult compareElements(const void* fp,
|
||||||
const void* sp,
|
const void* sp,
|
||||||
void* user)
|
void* user UNUSED)
|
||||||
{
|
{
|
||||||
const _GLFWjoyelementNS* fe = fp;
|
const _GLFWjoyelementNS* fe = fp;
|
||||||
const _GLFWjoyelementNS* se = sp;
|
const _GLFWjoyelementNS* se = sp;
|
||||||
@@ -117,9 +119,9 @@ static void closeJoystick(_GLFWjoystick* js)
|
|||||||
|
|
||||||
// Callback for user-initiated joystick addition
|
// Callback for user-initiated joystick addition
|
||||||
//
|
//
|
||||||
static void matchCallback(void* context,
|
static void matchCallback(void* context UNUSED,
|
||||||
IOReturn result,
|
IOReturn result UNUSED,
|
||||||
void* sender,
|
void* sender UNUSED,
|
||||||
IOHIDDeviceRef device)
|
IOHIDDeviceRef device)
|
||||||
{
|
{
|
||||||
int jid;
|
int jid;
|
||||||
@@ -270,9 +272,9 @@ static void matchCallback(void* context,
|
|||||||
|
|
||||||
// Callback for user-initiated joystick removal
|
// Callback for user-initiated joystick removal
|
||||||
//
|
//
|
||||||
static void removeCallback(void* context,
|
static void removeCallback(void* context UNUSED,
|
||||||
IOReturn result,
|
IOReturn result UNUSED,
|
||||||
void* sender,
|
void* sender UNUSED,
|
||||||
IOHIDDeviceRef device)
|
IOHIDDeviceRef device)
|
||||||
{
|
{
|
||||||
int jid;
|
int jid;
|
||||||
@@ -316,7 +318,7 @@ void _glfwInitJoysticksNS(void)
|
|||||||
return;
|
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;
|
const long page = kHIDPage_GenericDesktop;
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// GLFW 3.3 macOS - www.glfw.org
|
// GLFW 3.3 macOS - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -24,6 +24,8 @@
|
|||||||
// distribution.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// It is fine to use C99 in this file because it will not be built with VS
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
@@ -215,7 +217,7 @@ static void endFadeReservation(CGDisplayFadeReservationToken token)
|
|||||||
|
|
||||||
// Finds and caches the NSScreen corresponding to the specified monitor
|
// Finds and caches the NSScreen corresponding to the specified monitor
|
||||||
//
|
//
|
||||||
bool refreshMonitorScreen(_GLFWmonitor* monitor)
|
static bool refreshMonitorScreen(_GLFWmonitor* monitor)
|
||||||
{
|
{
|
||||||
if (monitor->ns.screen)
|
if (monitor->ns.screen)
|
||||||
return true;
|
return true;
|
||||||
@@ -243,49 +245,30 @@ bool refreshMonitorScreen(_GLFWmonitor* monitor)
|
|||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void _glfwClearDisplayLinks() {
|
void _glfwClearDisplayLinks() {
|
||||||
[_glfw.ns.displayLinks.lock lock];
|
|
||||||
for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) {
|
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) {
|
if (_glfw.ns.displayLinks.entries[i].displayLink) {
|
||||||
|
CVDisplayLinkStop(_glfw.ns.displayLinks.entries[i].displayLink);
|
||||||
CVDisplayLinkRelease(_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].displayLink = nil;
|
||||||
|
_glfw.ns.displayLinks.entries[i].lastRenderFrameRequestedAt = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_glfw.ns.displayLinks.count = 0;
|
_glfw.ns.displayLinks.count = 0;
|
||||||
[_glfw.ns.displayLinks.lock unlock];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static CVReturn displayLinkCallback(
|
static CVReturn displayLinkCallback(
|
||||||
CVDisplayLinkRef displayLink,
|
CVDisplayLinkRef displayLink UNUSED,
|
||||||
const CVTimeStamp* now, const CVTimeStamp* outputTime,
|
const CVTimeStamp* now UNUSED, const CVTimeStamp* outputTime UNUSED,
|
||||||
CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* userInfo)
|
CVOptionFlags flagsIn UNUSED, CVOptionFlags* flagsOut UNUSED, void* userInfo)
|
||||||
{
|
{
|
||||||
CGDirectDisplayID displayID = (CGDirectDisplayID)userInfo;
|
CGDirectDisplayID displayID = (CGDirectDisplayID)userInfo;
|
||||||
[_glfw.ns.displayLinks.lock lock];
|
NSNumber *arg = [NSNumber numberWithUnsignedInt:displayID];
|
||||||
bool notify = false;
|
[NSApp performSelectorOnMainThread:@selector(render_frame_received:) withObject:arg waitUntilDone:NO];
|
||||||
for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) {
|
[arg release];
|
||||||
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];
|
|
||||||
}
|
|
||||||
return kCVReturnSuccess;
|
return kCVReturnSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void createDisplayLink(CGDirectDisplayID displayID) {
|
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;
|
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++) {
|
for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) {
|
||||||
if (_glfw.ns.displayLinks.entries[i].displayID == displayID) return;
|
if (_glfw.ns.displayLinks.entries[i].displayID == displayID) return;
|
||||||
@@ -295,26 +278,24 @@ static inline void createDisplayLink(CGDirectDisplayID displayID) {
|
|||||||
entry->displayID = displayID;
|
entry->displayID = displayID;
|
||||||
CVDisplayLinkCreateWithCGDisplay(displayID, &entry->displayLink);
|
CVDisplayLinkCreateWithCGDisplay(displayID, &entry->displayLink);
|
||||||
CVDisplayLinkSetOutputCallback(entry->displayLink, &displayLinkCallback, (void*)(uintptr_t)displayID);
|
CVDisplayLinkSetOutputCallback(entry->displayLink, &displayLinkCallback, (void*)(uintptr_t)displayID);
|
||||||
[_glfw.ns.displayLinks.lock unlock];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Poll for changes in the set of connected monitors
|
// Poll for changes in the set of connected monitors
|
||||||
//
|
//
|
||||||
void _glfwPollMonitorsNS(void)
|
void _glfwPollMonitorsNS(void)
|
||||||
{
|
{
|
||||||
uint32_t i, j, displayCount, disconnectedCount;
|
uint32_t displayCount;
|
||||||
CGDirectDisplayID* displays;
|
|
||||||
_GLFWmonitor** disconnected = NULL;
|
|
||||||
|
|
||||||
CGGetOnlineDisplayList(0, NULL, &displayCount);
|
CGGetOnlineDisplayList(0, NULL, &displayCount);
|
||||||
displays = calloc(displayCount, sizeof(CGDirectDisplayID));
|
CGDirectDisplayID* displays = calloc(displayCount, sizeof(CGDirectDisplayID));
|
||||||
CGGetOnlineDisplayList(displayCount, displays, &displayCount);
|
CGGetOnlineDisplayList(displayCount, displays, &displayCount);
|
||||||
_glfwClearDisplayLinks();
|
_glfwClearDisplayLinks();
|
||||||
|
|
||||||
for (i = 0; i < _glfw.monitorCount; i++)
|
for (int i = 0; i < _glfw.monitorCount; i++)
|
||||||
_glfw.monitors[i]->ns.screen = nil;
|
_glfw.monitors[i]->ns.screen = nil;
|
||||||
|
|
||||||
disconnectedCount = _glfw.monitorCount;
|
_GLFWmonitor** disconnected = NULL;
|
||||||
|
uint32_t disconnectedCount = _glfw.monitorCount;
|
||||||
if (disconnectedCount)
|
if (disconnectedCount)
|
||||||
{
|
{
|
||||||
disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*));
|
disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*));
|
||||||
@@ -323,19 +304,18 @@ void _glfwPollMonitorsNS(void)
|
|||||||
_glfw.monitorCount * sizeof(_GLFWmonitor*));
|
_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]))
|
if (CGDisplayIsAsleep(displays[i]))
|
||||||
continue;
|
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)
|
if (disconnected[j] && disconnected[j]->ns.unitNumber == unitNumber)
|
||||||
{
|
{
|
||||||
disconnected[j] = NULL;
|
disconnected[j] = NULL;
|
||||||
@@ -348,7 +328,7 @@ void _glfwPollMonitorsNS(void)
|
|||||||
if (!name)
|
if (!name)
|
||||||
name = _glfw_strdup("Unknown");
|
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.displayID = displays[i];
|
||||||
monitor->ns.unitNumber = unitNumber;
|
monitor->ns.unitNumber = unitNumber;
|
||||||
createDisplayLink(monitor->ns.displayID);
|
createDisplayLink(monitor->ns.displayID);
|
||||||
@@ -358,7 +338,7 @@ void _glfwPollMonitorsNS(void)
|
|||||||
_glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST);
|
_glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < disconnectedCount; i++)
|
for (uint32_t i = 0; i < disconnectedCount; i++)
|
||||||
{
|
{
|
||||||
if (disconnected[i])
|
if (disconnected[i])
|
||||||
_glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0);
|
_glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0);
|
||||||
@@ -373,24 +353,20 @@ void _glfwPollMonitorsNS(void)
|
|||||||
//
|
//
|
||||||
void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired)
|
void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired)
|
||||||
{
|
{
|
||||||
CFArrayRef modes;
|
|
||||||
CFIndex count, i;
|
|
||||||
CVDisplayLinkRef link;
|
|
||||||
CGDisplayModeRef native = NULL;
|
|
||||||
GLFWvidmode current;
|
GLFWvidmode current;
|
||||||
const GLFWvidmode* best;
|
const GLFWvidmode* best = _glfwChooseVideoMode(monitor, desired);
|
||||||
|
|
||||||
best = _glfwChooseVideoMode(monitor, desired);
|
|
||||||
_glfwPlatformGetVideoMode(monitor, ¤t);
|
_glfwPlatformGetVideoMode(monitor, ¤t);
|
||||||
if (_glfwCompareVideoModes(¤t, best) == 0)
|
if (_glfwCompareVideoModes(¤t, best) == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
CVDisplayLinkRef link;
|
||||||
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
|
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
|
||||||
|
|
||||||
modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
|
CFArrayRef modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
|
||||||
count = CFArrayGetCount(modes);
|
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);
|
CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i);
|
||||||
if (!modeIsGood(dm))
|
if (!modeIsGood(dm))
|
||||||
@@ -439,7 +415,7 @@ void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor)
|
|||||||
////// GLFW platform API //////
|
////// 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);
|
*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))
|
if (!refreshMonitorScreen(monitor))
|
||||||
return;
|
return;
|
||||||
@@ -488,20 +466,16 @@ void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos
|
|||||||
|
|
||||||
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
|
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
|
||||||
{
|
{
|
||||||
CFArrayRef modes;
|
|
||||||
CFIndex found, i, j;
|
|
||||||
GLFWvidmode* result;
|
|
||||||
CVDisplayLinkRef link;
|
|
||||||
|
|
||||||
*count = 0;
|
*count = 0;
|
||||||
|
|
||||||
|
CVDisplayLinkRef link;
|
||||||
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
|
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
|
||||||
|
|
||||||
modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
|
CFArrayRef modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
|
||||||
found = CFArrayGetCount(modes);
|
const CFIndex found = CFArrayGetCount(modes);
|
||||||
result = calloc(found, sizeof(GLFWvidmode));
|
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);
|
CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i);
|
||||||
if (!modeIsGood(dm))
|
if (!modeIsGood(dm))
|
||||||
@@ -509,7 +483,7 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
|
|||||||
|
|
||||||
const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link);
|
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)
|
if (_glfwCompareVideoModes(result + j, &mode) == 0)
|
||||||
break;
|
break;
|
||||||
@@ -530,21 +504,20 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
|
|||||||
|
|
||||||
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode *mode)
|
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode *mode)
|
||||||
{
|
{
|
||||||
CGDisplayModeRef displayMode;
|
|
||||||
CVDisplayLinkRef link;
|
CVDisplayLinkRef link;
|
||||||
|
|
||||||
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
|
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
|
||||||
|
|
||||||
displayMode = CGDisplayCopyDisplayMode(monitor->ns.displayID);
|
CGDisplayModeRef native = CGDisplayCopyDisplayMode(monitor->ns.displayID);
|
||||||
*mode = vidmodeFromCGDisplayMode(displayMode, link);
|
*mode = vidmodeFromCGDisplayMode(native, link);
|
||||||
CGDisplayModeRelease(displayMode);
|
CGDisplayModeRelease(native);
|
||||||
|
|
||||||
CVDisplayLinkRelease(link);
|
CVDisplayLinkRelease(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
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));
|
CGGammaValue* values = calloc(size * 3, sizeof(CGGammaValue));
|
||||||
|
|
||||||
CGGetDisplayTransferByTable(monitor->ns.displayID,
|
CGGetDisplayTransferByTable(monitor->ns.displayID,
|
||||||
@@ -556,7 +529,7 @@ bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
|||||||
|
|
||||||
_glfwAllocGammaArrays(ramp, size);
|
_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->red[i] = (unsigned short) (values[i] * 65535);
|
||||||
ramp->green[i] = (unsigned short) (values[i + size] * 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)
|
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
CGGammaValue* values = calloc(ramp->size * 3, sizeof(CGGammaValue));
|
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->red[i] / 65535.f;
|
||||||
values[i + ramp->size] = ramp->green[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
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -116,8 +116,8 @@ typedef struct _GLFWwindowNS
|
|||||||
id view;
|
id view;
|
||||||
id layer;
|
id layer;
|
||||||
|
|
||||||
bool maximized;
|
bool maximized;
|
||||||
bool retina;
|
bool retina;
|
||||||
|
|
||||||
// Cached window properties to filter out duplicate events
|
// Cached window properties to filter out duplicate events
|
||||||
int width, height;
|
int width, height;
|
||||||
@@ -144,8 +144,7 @@ typedef struct _GLFWDisplayLinkNS
|
|||||||
{
|
{
|
||||||
CVDisplayLinkRef displayLink;
|
CVDisplayLinkRef displayLink;
|
||||||
CGDirectDisplayID displayID;
|
CGDirectDisplayID displayID;
|
||||||
bool displayLinkStarted;
|
double lastRenderFrameRequestedAt;
|
||||||
bool renderFrameRequested;
|
|
||||||
} _GLFWDisplayLinkNS;
|
} _GLFWDisplayLinkNS;
|
||||||
|
|
||||||
// Cocoa-specific global data
|
// Cocoa-specific global data
|
||||||
@@ -154,7 +153,7 @@ typedef struct _GLFWlibraryNS
|
|||||||
{
|
{
|
||||||
CGEventSourceRef eventSource;
|
CGEventSourceRef eventSource;
|
||||||
id delegate;
|
id delegate;
|
||||||
bool cursorHidden;
|
bool cursorHidden;
|
||||||
TISInputSourceRef inputSource;
|
TISInputSourceRef inputSource;
|
||||||
IOHIDManagerRef hidManager;
|
IOHIDManagerRef hidManager;
|
||||||
id unicodeData;
|
id unicodeData;
|
||||||
@@ -184,7 +183,6 @@ typedef struct _GLFWlibraryNS
|
|||||||
struct {
|
struct {
|
||||||
_GLFWDisplayLinkNS entries[256];
|
_GLFWDisplayLinkNS entries[256];
|
||||||
size_t count;
|
size_t count;
|
||||||
id lock;
|
|
||||||
} displayLinks;
|
} displayLinks;
|
||||||
|
|
||||||
} _GLFWlibraryNS;
|
} _GLFWlibraryNS;
|
||||||
@@ -222,9 +220,12 @@ void _glfwInitTimerNS(void);
|
|||||||
void _glfwPollMonitorsNS(void);
|
void _glfwPollMonitorsNS(void);
|
||||||
void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired);
|
void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired);
|
||||||
void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor);
|
void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor);
|
||||||
|
|
||||||
float _glfwTransformYNS(float y);
|
float _glfwTransformYNS(float y);
|
||||||
|
|
||||||
void _glfwClearDisplayLinks(void);
|
void _glfwClearDisplayLinks(void);
|
||||||
void _glfwRestartDisplayLinks(void);
|
void _glfwRestartDisplayLinks(void);
|
||||||
void _glfwCocoaPostEmptyEvent(short subtype, long data1, bool at_start);
|
|
||||||
void _glfwDispatchTickCallback(void);
|
void _glfwDispatchTickCallback(void);
|
||||||
void _glfwDispatchRenderFrame(CGDirectDisplayID);
|
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.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// It is fine to use C99 in this file because it will not be built with VS
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 macOS - www.glfw.org
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -23,6 +23,8 @@
|
|||||||
// distribution.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// It is fine to use C99 in this file because it will not be built with VS
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
@@ -57,11 +59,23 @@ static NSUInteger getStyleMask(_GLFWwindow* window)
|
|||||||
CGDirectDisplayID displayIDForWindow(_GLFWwindow *w) {
|
CGDirectDisplayID displayIDForWindow(_GLFWwindow *w) {
|
||||||
NSWindow *nw = w->ns.object;
|
NSWindow *nw = w->ns.object;
|
||||||
NSDictionary *dict = [nw.screen deviceDescription];
|
NSDictionary *dict = [nw.screen deviceDescription];
|
||||||
NSNumber *displayIDns = [dict objectForKey:@"NSScreenNumber"];
|
NSNumber *displayIDns = dict[@"NSScreenNumber"];
|
||||||
if (displayIDns) return [displayIDns unsignedIntValue];
|
if (displayIDns) return [displayIDns unsignedIntValue];
|
||||||
return (CGDirectDisplayID)-1;
|
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
|
static inline void
|
||||||
requestRenderFrame(_GLFWwindow *w, GLFWcocoarenderframefun callback) {
|
requestRenderFrame(_GLFWwindow *w, GLFWcocoarenderframefun callback) {
|
||||||
@@ -73,19 +87,22 @@ requestRenderFrame(_GLFWwindow *w, GLFWcocoarenderframefun callback) {
|
|||||||
w->ns.renderFrameCallback = callback;
|
w->ns.renderFrameCallback = callback;
|
||||||
w->ns.renderFrameRequested = true;
|
w->ns.renderFrameRequested = true;
|
||||||
CGDirectDisplayID displayID = displayIDForWindow(w);
|
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++) {
|
for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) {
|
||||||
_GLFWDisplayLinkNS *dl = &_glfw.ns.displayLinks.entries[i];
|
_GLFWDisplayLinkNS *dl = &_glfw.ns.displayLinks.entries[i];
|
||||||
if (dl->displayID == displayID) {
|
if (dl->displayID == displayID) {
|
||||||
dl->renderFrameRequested = true;
|
dl->lastRenderFrameRequestedAt = now;
|
||||||
if (!dl->displayLinkStarted) {
|
if (!CVDisplayLinkIsRunning(dl->displayLink)) CVDisplayLinkStart(dl->displayLink);
|
||||||
CVDisplayLinkStart(dl->displayLink);
|
} else if (dl->displayLink && dl->lastRenderFrameRequestedAt && now - dl->lastRenderFrameRequestedAt >= DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL) {
|
||||||
dl->displayLinkStarted = true;
|
CVDisplayLinkStop(dl->displayLink);
|
||||||
}
|
dl->lastRenderFrameRequestedAt = 0;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[_glfw.ns.displayLinks.lock unlock];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -108,7 +125,7 @@ static bool cursorInContentArea(_GLFWwindow* window)
|
|||||||
|
|
||||||
// Hides the cursor if not already hidden
|
// Hides the cursor if not already hidden
|
||||||
//
|
//
|
||||||
static void hideCursor(_GLFWwindow* window)
|
static void hideCursor(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
if (!_glfw.ns.cursorHidden)
|
if (!_glfw.ns.cursorHidden)
|
||||||
{
|
{
|
||||||
@@ -119,7 +136,7 @@ static void hideCursor(_GLFWwindow* window)
|
|||||||
|
|
||||||
// Shows the cursor if not already shown
|
// Shows the cursor if not already shown
|
||||||
//
|
//
|
||||||
static void showCursor(_GLFWwindow* window)
|
static void showCursor(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
if (_glfw.ns.cursorHidden)
|
if (_glfw.ns.cursorHidden)
|
||||||
{
|
{
|
||||||
@@ -333,9 +350,8 @@ static int translateKey(unsigned int key, bool apply_keymap)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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) {
|
if (flags & kCGDisplayBeginConfigurationFlag) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -374,9 +390,7 @@ static NSUInteger translateKeyToModifierFlag(int key)
|
|||||||
static const NSRange kEmptyRange = { NSNotFound, 0 };
|
static const NSRange kEmptyRange = { NSNotFound, 0 };
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
// Delegate for window related notifications {{{
|
||||||
// Delegate for window related notifications
|
|
||||||
//------------------------------------------------------------------------
|
|
||||||
|
|
||||||
@interface GLFWWindowDelegate : NSObject
|
@interface GLFWWindowDelegate : NSObject
|
||||||
{
|
{
|
||||||
@@ -400,12 +414,14 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
|||||||
|
|
||||||
- (BOOL)windowShouldClose:(id)sender
|
- (BOOL)windowShouldClose:(id)sender
|
||||||
{
|
{
|
||||||
|
(void)sender;
|
||||||
_glfwInputWindowCloseRequest(window);
|
_glfwInputWindowCloseRequest(window);
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)windowDidResize:(NSNotification *)notification
|
- (void)windowDidResize:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
|
(void)notification;
|
||||||
if (window->context.client != GLFW_NO_API)
|
if (window->context.client != GLFW_NO_API)
|
||||||
[window->context.nsgl.object update];
|
[window->context.nsgl.object update];
|
||||||
|
|
||||||
@@ -441,6 +457,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
|||||||
|
|
||||||
- (void)windowDidMove:(NSNotification *)notification
|
- (void)windowDidMove:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
|
(void)notification;
|
||||||
if (window->context.client != GLFW_NO_API)
|
if (window->context.client != GLFW_NO_API)
|
||||||
[window->context.nsgl.object update];
|
[window->context.nsgl.object update];
|
||||||
|
|
||||||
@@ -454,11 +471,13 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
|||||||
|
|
||||||
- (void)windowDidChangeOcclusionState:(NSNotification *)notification
|
- (void)windowDidChangeOcclusionState:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
|
(void)notification;
|
||||||
_glfwInputWindowOcclusion(window, !([window->ns.object occlusionState] & NSWindowOcclusionStateVisible));
|
_glfwInputWindowOcclusion(window, !([window->ns.object occlusionState] & NSWindowOcclusionStateVisible));
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)windowDidMiniaturize:(NSNotification *)notification
|
- (void)windowDidMiniaturize:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
|
(void)notification;
|
||||||
if (window->monitor)
|
if (window->monitor)
|
||||||
releaseMonitor(window);
|
releaseMonitor(window);
|
||||||
|
|
||||||
@@ -467,6 +486,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
|||||||
|
|
||||||
- (void)windowDidDeminiaturize:(NSNotification *)notification
|
- (void)windowDidDeminiaturize:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
|
(void)notification;
|
||||||
if (window->monitor)
|
if (window->monitor)
|
||||||
acquireMonitor(window);
|
acquireMonitor(window);
|
||||||
|
|
||||||
@@ -475,6 +495,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
|||||||
|
|
||||||
- (void)windowDidBecomeKey:(NSNotification *)notification
|
- (void)windowDidBecomeKey:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
|
(void)notification;
|
||||||
if (_glfw.ns.disabledCursorWindow == window)
|
if (_glfw.ns.disabledCursorWindow == window)
|
||||||
_glfwCenterCursorInContentArea(window);
|
_glfwCenterCursorInContentArea(window);
|
||||||
|
|
||||||
@@ -491,6 +512,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
|||||||
|
|
||||||
- (void)windowDidResignKey:(NSNotification *)notification
|
- (void)windowDidResignKey:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
|
(void)notification;
|
||||||
if (window->monitor && window->autoIconify)
|
if (window->monitor && window->autoIconify)
|
||||||
_glfwPlatformIconifyWindow(window);
|
_glfwPlatformIconifyWindow(window);
|
||||||
showCursor(window);
|
showCursor(window);
|
||||||
@@ -500,6 +522,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
|||||||
|
|
||||||
- (void)windowDidChangeScreen:(NSNotification *)notification
|
- (void)windowDidChangeScreen:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
|
(void)notification;
|
||||||
if (window->ns.renderFrameRequested && window->ns.renderFrameCallback) {
|
if (window->ns.renderFrameRequested && window->ns.renderFrameCallback) {
|
||||||
// Ensure that if the window changed its monitor, CVDisplayLink
|
// Ensure that if the window changed its monitor, CVDisplayLink
|
||||||
// is running for the new monitor
|
// 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
|
@interface GLFWApplicationDelegate : NSObject
|
||||||
@end
|
@end
|
||||||
@@ -522,6 +542,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
|||||||
|
|
||||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
|
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
|
||||||
{
|
{
|
||||||
|
(void)sender;
|
||||||
_GLFWwindow* window;
|
_GLFWwindow* window;
|
||||||
|
|
||||||
for (window = _glfw.windowListHead; window; window = window->next)
|
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
|
- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag
|
||||||
{
|
{
|
||||||
|
(void)sender;
|
||||||
if (!handle_reopen_callback) return YES;
|
if (!handle_reopen_callback) return YES;
|
||||||
if (handle_reopen_callback(flag)) return YES;
|
if (handle_reopen_callback(flag)) return YES;
|
||||||
return NO;
|
return NO;
|
||||||
@@ -541,6 +563,7 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
|||||||
|
|
||||||
- (void)applicationDidChangeScreenParameters:(NSNotification *) notification
|
- (void)applicationDidChangeScreenParameters:(NSNotification *) notification
|
||||||
{
|
{
|
||||||
|
(void)notification;
|
||||||
_GLFWwindow* window;
|
_GLFWwindow* window;
|
||||||
|
|
||||||
for (window = _glfw.windowListHead; window; window = window->next)
|
for (window = _glfw.windowListHead; window; window = window->next)
|
||||||
@@ -554,19 +577,22 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
|||||||
|
|
||||||
- (void)applicationDidFinishLaunching:(NSNotification *)notification
|
- (void)applicationDidFinishLaunching:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
|
(void)notification;
|
||||||
[NSApp stop:nil];
|
[NSApp stop:nil];
|
||||||
|
|
||||||
CGDisplayRegisterReconfigurationCallback(display_reconfigured, NULL);
|
CGDisplayRegisterReconfigurationCallback(display_reconfigured, NULL);
|
||||||
_glfwPlatformPostEmptyEvent();
|
_glfwCocoaPostEmptyEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)applicationWillTerminate:(NSNotification *)aNotification
|
- (void)applicationWillTerminate:(NSNotification *)aNotification
|
||||||
{
|
{
|
||||||
|
(void)aNotification;
|
||||||
CGDisplayRemoveReconfigurationCallback(display_reconfigured, NULL);
|
CGDisplayRemoveReconfigurationCallback(display_reconfigured, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)applicationDidHide:(NSNotification *)notification
|
- (void)applicationDidHide:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
|
(void)notification;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < _glfw.monitorCount; i++)
|
for (i = 0; i < _glfw.monitorCount; i++)
|
||||||
@@ -574,11 +600,9 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// Content view class for the GLFW window {{{
|
||||||
//------------------------------------------------------------------------
|
|
||||||
// Content view class for the GLFW window
|
|
||||||
//------------------------------------------------------------------------
|
|
||||||
|
|
||||||
@interface GLFWContentView : NSView <NSTextInputClient>
|
@interface GLFWContentView : NSView <NSTextInputClient>
|
||||||
{
|
{
|
||||||
@@ -588,6 +612,7 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
|||||||
NSRect markedRect;
|
NSRect markedRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) removeGLFWWindow;
|
||||||
- (instancetype)initWithGlfwWindow:(_GLFWwindow *)initWindow;
|
- (instancetype)initWithGlfwWindow:(_GLFWwindow *)initWindow;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -618,13 +643,18 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
|||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) removeGLFWWindow
|
||||||
|
{
|
||||||
|
window = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
- (_GLFWwindow*)glfwWindow {
|
- (_GLFWwindow*)glfwWindow {
|
||||||
return window;
|
return window;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)isOpaque
|
- (BOOL)isOpaque
|
||||||
{
|
{
|
||||||
return [window->ns.object isOpaque];
|
return window && [window->ns.object isOpaque];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)canBecomeKeyView
|
- (BOOL)canBecomeKeyView
|
||||||
@@ -639,11 +669,13 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
|||||||
|
|
||||||
- (void) viewWillStartLiveResize
|
- (void) viewWillStartLiveResize
|
||||||
{
|
{
|
||||||
|
if (!window) return;
|
||||||
_glfwInputLiveResize(window, true);
|
_glfwInputLiveResize(window, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewDidEndLiveResize
|
- (void)viewDidEndLiveResize
|
||||||
{
|
{
|
||||||
|
if (!window) return;
|
||||||
_glfwInputLiveResize(window, false);
|
_glfwInputLiveResize(window, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -654,6 +686,7 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
|||||||
|
|
||||||
- (void)updateLayer
|
- (void)updateLayer
|
||||||
{
|
{
|
||||||
|
if (!window) return;
|
||||||
if (window->context.client != GLFW_NO_API) {
|
if (window->context.client != GLFW_NO_API) {
|
||||||
@try {
|
@try {
|
||||||
[window->context.nsgl.object update];
|
[window->context.nsgl.object update];
|
||||||
@@ -669,16 +702,19 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
|||||||
|
|
||||||
- (void)cursorUpdate:(NSEvent *)event
|
- (void)cursorUpdate:(NSEvent *)event
|
||||||
{
|
{
|
||||||
updateCursorImage(window);
|
(void)event;
|
||||||
|
if (window) updateCursorImage(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)acceptsFirstMouse:(NSEvent *)event
|
- (BOOL)acceptsFirstMouse:(NSEvent *)event
|
||||||
{
|
{
|
||||||
|
(void)event;
|
||||||
return NO; // changed by Kovid, to follow cocoa platform conventions
|
return NO; // changed by Kovid, to follow cocoa platform conventions
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mouseDown:(NSEvent *)event
|
- (void)mouseDown:(NSEvent *)event
|
||||||
{
|
{
|
||||||
|
if (!window) return;
|
||||||
_glfwInputMouseClick(window,
|
_glfwInputMouseClick(window,
|
||||||
GLFW_MOUSE_BUTTON_LEFT,
|
GLFW_MOUSE_BUTTON_LEFT,
|
||||||
GLFW_PRESS,
|
GLFW_PRESS,
|
||||||
@@ -692,6 +728,7 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
|||||||
|
|
||||||
- (void)mouseUp:(NSEvent *)event
|
- (void)mouseUp:(NSEvent *)event
|
||||||
{
|
{
|
||||||
|
if (!window) return;
|
||||||
_glfwInputMouseClick(window,
|
_glfwInputMouseClick(window,
|
||||||
GLFW_MOUSE_BUTTON_LEFT,
|
GLFW_MOUSE_BUTTON_LEFT,
|
||||||
GLFW_RELEASE,
|
GLFW_RELEASE,
|
||||||
@@ -700,6 +737,7 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
|||||||
|
|
||||||
- (void)mouseMoved:(NSEvent *)event
|
- (void)mouseMoved:(NSEvent *)event
|
||||||
{
|
{
|
||||||
|
if (!window) return;
|
||||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||||
{
|
{
|
||||||
const double dx = [event deltaX] - window->ns.cursorWarpDeltaX;
|
const double dx = [event deltaX] - window->ns.cursorWarpDeltaX;
|
||||||
@@ -724,6 +762,7 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
|||||||
|
|
||||||
- (void)rightMouseDown:(NSEvent *)event
|
- (void)rightMouseDown:(NSEvent *)event
|
||||||
{
|
{
|
||||||
|
if (!window) return;
|
||||||
_glfwInputMouseClick(window,
|
_glfwInputMouseClick(window,
|
||||||
GLFW_MOUSE_BUTTON_RIGHT,
|
GLFW_MOUSE_BUTTON_RIGHT,
|
||||||
GLFW_PRESS,
|
GLFW_PRESS,
|
||||||
@@ -737,6 +776,7 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
|||||||
|
|
||||||
- (void)rightMouseUp:(NSEvent *)event
|
- (void)rightMouseUp:(NSEvent *)event
|
||||||
{
|
{
|
||||||
|
if (!window) return;
|
||||||
_glfwInputMouseClick(window,
|
_glfwInputMouseClick(window,
|
||||||
GLFW_MOUSE_BUTTON_RIGHT,
|
GLFW_MOUSE_BUTTON_RIGHT,
|
||||||
GLFW_RELEASE,
|
GLFW_RELEASE,
|
||||||
@@ -745,6 +785,7 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
|||||||
|
|
||||||
- (void)otherMouseDown:(NSEvent *)event
|
- (void)otherMouseDown:(NSEvent *)event
|
||||||
{
|
{
|
||||||
|
if (!window) return;
|
||||||
_glfwInputMouseClick(window,
|
_glfwInputMouseClick(window,
|
||||||
(int) [event buttonNumber],
|
(int) [event buttonNumber],
|
||||||
GLFW_PRESS,
|
GLFW_PRESS,
|
||||||
@@ -758,6 +799,7 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
|||||||
|
|
||||||
- (void)otherMouseUp:(NSEvent *)event
|
- (void)otherMouseUp:(NSEvent *)event
|
||||||
{
|
{
|
||||||
|
if (!window) return;
|
||||||
_glfwInputMouseClick(window,
|
_glfwInputMouseClick(window,
|
||||||
(int) [event buttonNumber],
|
(int) [event buttonNumber],
|
||||||
GLFW_RELEASE,
|
GLFW_RELEASE,
|
||||||
@@ -766,16 +808,21 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
|||||||
|
|
||||||
- (void)mouseExited:(NSEvent *)event
|
- (void)mouseExited:(NSEvent *)event
|
||||||
{
|
{
|
||||||
|
(void)event;
|
||||||
|
if (!window) return;
|
||||||
_glfwInputCursorEnter(window, false);
|
_glfwInputCursorEnter(window, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mouseEntered:(NSEvent *)event
|
- (void)mouseEntered:(NSEvent *)event
|
||||||
{
|
{
|
||||||
|
(void)event;
|
||||||
|
if (!window) return;
|
||||||
_glfwInputCursorEnter(window, true);
|
_glfwInputCursorEnter(window, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewDidChangeBackingProperties
|
- (void)viewDidChangeBackingProperties
|
||||||
{
|
{
|
||||||
|
if (!window) return;
|
||||||
const NSRect contentRect = [window->ns.view frame];
|
const NSRect contentRect = [window->ns.view frame];
|
||||||
const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect];
|
const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect];
|
||||||
|
|
||||||
@@ -803,6 +850,8 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
|||||||
|
|
||||||
- (void)drawRect:(NSRect)rect
|
- (void)drawRect:(NSRect)rect
|
||||||
{
|
{
|
||||||
|
(void)rect;
|
||||||
|
if (!window) return;
|
||||||
_glfwInputWindowDamage(window);
|
_glfwInputWindowDamage(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -975,10 +1024,9 @@ is_ascii_control_char(char x) {
|
|||||||
|
|
||||||
- (void)scrollWheel:(NSEvent *)event
|
- (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;
|
int flags = [event hasPreciseScrollingDeltas] ? 1 : 0;
|
||||||
if (flags) {
|
if (flags) {
|
||||||
float xscale = 1, yscale = 1;
|
float xscale = 1, yscale = 1;
|
||||||
@@ -1010,8 +1058,9 @@ is_ascii_control_char(char x) {
|
|||||||
|
|
||||||
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
|
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
|
||||||
{
|
{
|
||||||
|
(void)sender;
|
||||||
// HACK: We don't know what to say here because we don't know what the
|
// 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;
|
return NSDragOperationGeneric;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1021,19 +1070,19 @@ is_ascii_control_char(char x) {
|
|||||||
// NOTE: The returned location uses base 0,1 not 0,0
|
// NOTE: The returned location uses base 0,1 not 0,0
|
||||||
const NSPoint pos = [sender draggingLocation];
|
const NSPoint pos = [sender draggingLocation];
|
||||||
_glfwInputCursorPos(window, pos.x, contentRect.size.height - pos.y);
|
_glfwInputCursorPos(window, pos.x, contentRect.size.height - pos.y);
|
||||||
|
|
||||||
NSPasteboard* pasteboard = [sender draggingPasteboard];
|
NSPasteboard* pasteboard = [sender draggingPasteboard];
|
||||||
NSDictionary* options = @{NSPasteboardURLReadingFileURLsOnlyKey:@YES};
|
NSDictionary* options = @{NSPasteboardURLReadingFileURLsOnlyKey:@YES};
|
||||||
NSArray* urls = [pasteboard readObjectsForClasses:@[[NSURL class]]
|
NSArray* urls = [pasteboard readObjectsForClasses:@[[NSURL class]]
|
||||||
options:options];
|
options:options];
|
||||||
if (!urls) return NO;
|
if (!urls) return NO;
|
||||||
const NSUInteger count = [urls count];
|
const NSUInteger count = [urls count];
|
||||||
|
|
||||||
if (count)
|
if (count)
|
||||||
{
|
{
|
||||||
char** paths = calloc(count, sizeof(char*));
|
char** paths = calloc(count, sizeof(char*));
|
||||||
|
|
||||||
for (NSUInteger i = 0; i < count; i++)
|
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);
|
_glfwInputDrop(window, (int) count, (const char**) paths);
|
||||||
|
|
||||||
@@ -1067,6 +1116,7 @@ is_ascii_control_char(char x) {
|
|||||||
selectedRange:(NSRange)selectedRange
|
selectedRange:(NSRange)selectedRange
|
||||||
replacementRange:(NSRange)replacementRange
|
replacementRange:(NSRange)replacementRange
|
||||||
{
|
{
|
||||||
|
(void)selectedRange; (void)replacementRange;
|
||||||
[markedText release];
|
[markedText release];
|
||||||
if ([string isKindOfClass:[NSAttributedString class]])
|
if ([string isKindOfClass:[NSAttributedString class]])
|
||||||
markedText = [[NSMutableAttributedString alloc] initWithAttributedString:string];
|
markedText = [[NSMutableAttributedString alloc] initWithAttributedString:string];
|
||||||
@@ -1089,6 +1139,7 @@ void _glfwPlatformUpdateIMEState(_GLFWwindow *w, int which, int a, int b, int c,
|
|||||||
cellWidth:(CGFloat)cellWidth
|
cellWidth:(CGFloat)cellWidth
|
||||||
cellHeight:(CGFloat)cellHeight
|
cellHeight:(CGFloat)cellHeight
|
||||||
{
|
{
|
||||||
|
(void) which;
|
||||||
left /= window->ns.xscale;
|
left /= window->ns.xscale;
|
||||||
top /= window->ns.yscale;
|
top /= window->ns.yscale;
|
||||||
cellWidth /= window->ns.xscale;
|
cellWidth /= window->ns.xscale;
|
||||||
@@ -1109,22 +1160,26 @@ void _glfwPlatformUpdateIMEState(_GLFWwindow *w, int which, int a, int b, int c,
|
|||||||
- (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)range
|
- (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)range
|
||||||
actualRange:(NSRangePointer)actualRange
|
actualRange:(NSRangePointer)actualRange
|
||||||
{
|
{
|
||||||
|
(void)range; (void)actualRange;
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSUInteger)characterIndexForPoint:(NSPoint)point
|
- (NSUInteger)characterIndexForPoint:(NSPoint)point
|
||||||
{
|
{
|
||||||
|
(void)point;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSRect)firstRectForCharacterRange:(NSRange)range
|
- (NSRect)firstRectForCharacterRange:(NSRange)range
|
||||||
actualRange:(NSRangePointer)actualRange
|
actualRange:(NSRangePointer)actualRange
|
||||||
{
|
{
|
||||||
|
(void)range; (void)actualRange;
|
||||||
return markedRect;
|
return markedRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)insertText:(id)string replacementRange:(NSRange)replacementRange
|
- (void)insertText:(id)string replacementRange:(NSRange)replacementRange
|
||||||
{
|
{
|
||||||
|
(void)replacementRange;
|
||||||
NSString* characters;
|
NSString* characters;
|
||||||
if ([string isKindOfClass:[NSAttributedString class]])
|
if ([string isKindOfClass:[NSAttributedString class]])
|
||||||
characters = [string string];
|
characters = [string string];
|
||||||
@@ -1138,20 +1193,44 @@ void _glfwPlatformUpdateIMEState(_GLFWwindow *w, int which, int a, int b, int c,
|
|||||||
|
|
||||||
- (void)doCommandBySelector:(SEL)selector
|
- (void)doCommandBySelector:(SEL)selector
|
||||||
{
|
{
|
||||||
|
(void)selector;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// GLFW Window class {{{
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
@interface GLFWWindow : NSWindow {
|
||||||
// GLFW window class
|
_GLFWwindow* glfw_window;
|
||||||
//------------------------------------------------------------------------
|
}
|
||||||
|
|
||||||
@interface GLFWWindow : NSWindow {}
|
- (instancetype)initWithGlfwWindow:(NSRect)contentRect
|
||||||
|
styleMask:(NSWindowStyleMask)style
|
||||||
|
backing:(NSBackingStoreType)backingStoreType
|
||||||
|
initWindow:(_GLFWwindow *)initWindow;
|
||||||
|
|
||||||
|
- (void) removeGLFWWindow;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation GLFWWindow
|
@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
|
- (BOOL)canBecomeKeyWindow
|
||||||
{
|
{
|
||||||
// Required for NSWindowStyleMaskBorderless windows
|
// 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
|
- (void)toggleFullScreen:(nullable id)sender
|
||||||
{
|
{
|
||||||
GLFWContentView *view = [self contentView];
|
if (glfw_window && glfw_window->ns.toggleFullscreenCallback && glfw_window->ns.toggleFullscreenCallback((GLFWwindow*)glfw_window) == 1)
|
||||||
if (view)
|
|
||||||
{
|
|
||||||
_GLFWwindow *window = [view glfwWindow];
|
|
||||||
if (window && window->ns.toggleFullscreenCallback && window->ns.toggleFullscreenCallback((GLFWwindow*)window) == 1)
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
[super toggleFullScreen:sender];
|
[super toggleFullScreen:sender];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
// }}}
|
||||||
|
|
||||||
// Set up the menu bar (manually)
|
// Set up the menu bar (manually)
|
||||||
// This is nasty, nasty stuff -- calls to undocumented semi-private APIs that
|
// 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++)
|
for (i = 0; i < sizeof(nameKeys) / sizeof(nameKeys[0]); i++)
|
||||||
{
|
{
|
||||||
id name = [bundleInfo objectForKey:nameKeys[i]];
|
id name = bundleInfo[nameKeys[i]];
|
||||||
if (name &&
|
if (name &&
|
||||||
[name isKindOfClass:[NSString class]] &&
|
[name isKindOfClass:[NSString class]] &&
|
||||||
![name isEqualToString:@""])
|
![name isEqualToString:@""])
|
||||||
@@ -1213,7 +1287,7 @@ static void createMenuBar(void)
|
|||||||
{
|
{
|
||||||
char** progname = _NSGetProgname();
|
char** progname = _NSGetProgname();
|
||||||
if (progname && *progname)
|
if (progname && *progname)
|
||||||
appName = [NSString stringWithUTF8String:*progname];
|
appName = @(*progname);
|
||||||
else
|
else
|
||||||
appName = @"GLFW Application";
|
appName = @"GLFW Application";
|
||||||
}
|
}
|
||||||
@@ -1357,10 +1431,11 @@ static bool createNativeWindow(_GLFWwindow* window,
|
|||||||
contentRect = NSMakeRect(0, 0, wndconfig->width, wndconfig->height);
|
contentRect = NSMakeRect(0, 0, wndconfig->width, wndconfig->height);
|
||||||
|
|
||||||
window->ns.object = [[GLFWWindow alloc]
|
window->ns.object = [[GLFWWindow alloc]
|
||||||
initWithContentRect:contentRect
|
initWithGlfwWindow:contentRect
|
||||||
styleMask:getStyleMask(window)
|
styleMask:getStyleMask(window)
|
||||||
backing:NSBackingStoreBuffered
|
backing:NSBackingStoreBuffered
|
||||||
defer:NO];
|
initWindow:window
|
||||||
|
];
|
||||||
|
|
||||||
if (window->ns.object == nil)
|
if (window->ns.object == nil)
|
||||||
{
|
{
|
||||||
@@ -1372,7 +1447,7 @@ static bool createNativeWindow(_GLFWwindow* window,
|
|||||||
[window->ns.object setLevel:NSMainMenuWindowLevel + 1];
|
[window->ns.object setLevel:NSMainMenuWindowLevel + 1];
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
[window->ns.object center];
|
[(NSWindow*)window->ns.object center];
|
||||||
_glfw.ns.cascadePoint =
|
_glfw.ns.cascadePoint =
|
||||||
NSPointToCGPoint([window->ns.object cascadeTopLeftFromPoint:
|
NSPointToCGPoint([window->ns.object cascadeTopLeftFromPoint:
|
||||||
NSPointFromCGPoint(_glfw.ns.cascadePoint)]);
|
NSPointFromCGPoint(_glfw.ns.cascadePoint)]);
|
||||||
@@ -1393,10 +1468,9 @@ static bool createNativeWindow(_GLFWwindow* window,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (strlen(wndconfig->ns.frameName))
|
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.view = [[GLFWContentView alloc] initWithGlfwWindow:window];
|
||||||
|
|
||||||
window->ns.retina = wndconfig->ns.retina;
|
window->ns.retina = wndconfig->ns.retina;
|
||||||
|
|
||||||
if (fbconfig->transparent)
|
if (fbconfig->transparent)
|
||||||
@@ -1408,7 +1482,7 @@ static bool createNativeWindow(_GLFWwindow* window,
|
|||||||
|
|
||||||
[window->ns.object setContentView:window->ns.view];
|
[window->ns.object setContentView:window->ns.view];
|
||||||
[window->ns.object makeFirstResponder: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 setDelegate:window->ns.delegate];
|
||||||
[window->ns.object setAcceptsMouseMovedEvents:YES];
|
[window->ns.object setAcceptsMouseMovedEvents:YES];
|
||||||
[window->ns.object setRestorable:NO];
|
[window->ns.object setRestorable:NO];
|
||||||
@@ -1488,24 +1562,26 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
|
|||||||
[window->ns.delegate release];
|
[window->ns.delegate release];
|
||||||
window->ns.delegate = nil;
|
window->ns.delegate = nil;
|
||||||
|
|
||||||
|
[window->ns.view removeGLFWWindow];
|
||||||
[window->ns.view release];
|
[window->ns.view release];
|
||||||
window->ns.view = nil;
|
window->ns.view = nil;
|
||||||
|
|
||||||
|
[window->ns.object removeGLFWWindow];
|
||||||
[window->ns.object close];
|
[window->ns.object close];
|
||||||
window->ns.object = nil;
|
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];
|
[window->ns.object setTitle:string];
|
||||||
// HACK: Set the miniwindow title explicitly as setTitle: doesn't update it
|
// HACK: Set the miniwindow title explicitly as setTitle: doesn't update it
|
||||||
// if the window lacks NSWindowStyleMaskTitled
|
// if the window lacks NSWindowStyleMaskTitled
|
||||||
[window->ns.object setMiniwindowTitle:string];
|
[window->ns.object setMiniwindowTitle:string];
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
|
void _glfwPlatformSetWindowIcon(_GLFWwindow* window UNUSED,
|
||||||
int count, const GLFWimage* images)
|
int count UNUSED, const GLFWimage* images UNUSED)
|
||||||
{
|
{
|
||||||
// Regular windows do not have icons
|
// Regular windows do not have icons
|
||||||
}
|
}
|
||||||
@@ -1615,7 +1691,7 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
|
|||||||
*yscale = (float) (pixels.size.height / points.size.height);
|
*yscale = (float) (pixels.size.height / points.size.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window)
|
double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
return [NSEvent doubleClickInterval];
|
return [NSEvent doubleClickInterval];
|
||||||
}
|
}
|
||||||
@@ -1649,12 +1725,12 @@ void _glfwPlatformHideWindow(_GLFWwindow* window)
|
|||||||
[window->ns.object orderOut:nil];
|
[window->ns.object orderOut:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window)
|
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
[NSApp requestUserAttention:NSInformationalRequest];
|
[NSApp requestUserAttention:NSInformationalRequest];
|
||||||
}
|
}
|
||||||
|
|
||||||
int _glfwPlatformWindowBell(_GLFWwindow* window)
|
int _glfwPlatformWindowBell(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
NSBeep();
|
NSBeep();
|
||||||
return true;
|
return true;
|
||||||
@@ -1663,11 +1739,10 @@ int _glfwPlatformWindowBell(_GLFWwindow* window)
|
|||||||
void _glfwPlatformFocusWindow(_GLFWwindow* window)
|
void _glfwPlatformFocusWindow(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
// Make us the active application
|
// Make us the active application
|
||||||
// HACK: This has been moved here from initializeAppKit to prevent
|
// HACK: This is here to prevent applications using only hidden windows from
|
||||||
// applications using only hidden windows from being activated, but
|
// being activated, but should probably not be done every time any
|
||||||
// should probably not be done every time any window is shown
|
// window is shown
|
||||||
[NSApp activateIgnoringOtherApps:YES];
|
[NSApp activateIgnoringOtherApps:YES];
|
||||||
|
|
||||||
[window->ns.object makeKeyAndOrderFront:nil];
|
[window->ns.object makeKeyAndOrderFront:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1675,7 +1750,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
|
|||||||
_GLFWmonitor* monitor,
|
_GLFWmonitor* monitor,
|
||||||
int xpos, int ypos,
|
int xpos, int ypos,
|
||||||
int width, int height,
|
int width, int height,
|
||||||
int refreshRate)
|
int refreshRate UNUSED)
|
||||||
{
|
{
|
||||||
if (window->monitor == monitor)
|
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
|
// HACK: Changing the style mask can cause the first responder to be cleared
|
||||||
[window->ns.object makeFirstResponder:window->ns.view];
|
[window->ns.object makeFirstResponder:window->ns.view];
|
||||||
|
|
||||||
if (monitor)
|
if (window->monitor)
|
||||||
{
|
{
|
||||||
[window->ns.object setLevel:NSMainMenuWindowLevel + 1];
|
[window->ns.object setLevel:NSMainMenuWindowLevel + 1];
|
||||||
[window->ns.object setHasShadow:NO];
|
[window->ns.object setHasShadow:NO];
|
||||||
@@ -1800,12 +1875,12 @@ int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
|
|||||||
return ![window->ns.object isOpaque] && ![window->ns.view isOpaque];
|
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)];
|
[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 setStyleMask:getStyleMask(window)];
|
||||||
[window->ns.object makeFirstResponder:window->ns.view];
|
[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)
|
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
|
||||||
{
|
{
|
||||||
const NSRect contentRect = [window->ns.view frame];
|
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))
|
if (_glfwPlatformWindowFocused(window))
|
||||||
updateCursorMode(window);
|
updateCursorMode(window);
|
||||||
@@ -1974,6 +2028,7 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
|||||||
|
|
||||||
cursor->ns.object = [[NSCursor alloc] initWithImage:native
|
cursor->ns.object = [[NSCursor alloc] initWithImage:native
|
||||||
hotSpot:NSMakePoint(xhot, yhot)];
|
hotSpot:NSMakePoint(xhot, yhot)];
|
||||||
|
|
||||||
[native release];
|
[native release];
|
||||||
if (cursor->ns.object == nil)
|
if (cursor->ns.object == nil)
|
||||||
return false;
|
return false;
|
||||||
@@ -2018,7 +2073,7 @@ void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
|
|||||||
[(NSCursor*) cursor->ns.object release];
|
[(NSCursor*) cursor->ns.object release];
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor UNUSED)
|
||||||
{
|
{
|
||||||
if (cursorInContentArea(window))
|
if (cursorInContentArea(window))
|
||||||
updateCursorImage(window);
|
updateCursorImage(window);
|
||||||
@@ -2051,8 +2106,7 @@ void _glfwPlatformSetClipboardString(const char* string)
|
|||||||
{
|
{
|
||||||
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
|
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
|
||||||
[pasteboard declareTypes:@[NSPasteboardTypeString] owner:nil];
|
[pasteboard declareTypes:@[NSPasteboardTypeString] owner:nil];
|
||||||
[pasteboard setString:[NSString stringWithUTF8String:string]
|
[pasteboard setString:@(string) forType:NSPasteboardTypeString];
|
||||||
forType:NSPasteboardTypeString];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* _glfwPlatformGetClipboardString(void)
|
const char* _glfwPlatformGetClipboardString(void)
|
||||||
@@ -2089,9 +2143,9 @@ void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)
|
|||||||
extensions[1] = "VK_MVK_macos_surface";
|
extensions[1] = "VK_MVK_macos_surface";
|
||||||
}
|
}
|
||||||
|
|
||||||
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
|
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance UNUSED,
|
||||||
VkPhysicalDevice device,
|
VkPhysicalDevice device UNUSED,
|
||||||
uint32_t queuefamily)
|
uint32_t queuefamily UNUSED)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -2136,6 +2190,7 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
|
|||||||
|
|
||||||
if (window->ns.retina)
|
if (window->ns.retina)
|
||||||
[window->ns.layer setContentsScale:[window->ns.object backingScaleFactor]];
|
[window->ns.layer setContentsScale:[window->ns.object backingScaleFactor]];
|
||||||
|
|
||||||
[window->ns.view setLayer:window->ns.layer];
|
[window->ns.view setLayer:window->ns.layer];
|
||||||
[window->ns.view setWantsLayer:YES];
|
[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)
|
if (glfw_mods & GLFW_MOD_CAPS_LOCK)
|
||||||
*cocoa_mods |= NSEventModifierFlagCapsLock;
|
*cocoa_mods |= NSEventModifierFlagCapsLock;
|
||||||
|
|
||||||
|
START_ALLOW_CASE_RANGE
|
||||||
switch(glfw_key) {
|
switch(glfw_key) {
|
||||||
#define K(ch, name) case GLFW_KEY_##name: *cocoa_key = ch; break;
|
#define K(ch, name) case GLFW_KEY_##name: *cocoa_key = ch; break;
|
||||||
K('a', A);
|
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)(0x4E|NSEventModifierFlagNumericPad), KP_SUBTRACT);
|
||||||
K((unichar)(0x51|NSEventModifierFlagNumericPad), KP_EQUAL);
|
K((unichar)(0x51|NSEventModifierFlagNumericPad), KP_EQUAL);
|
||||||
#undef K
|
#undef K
|
||||||
|
END_ALLOW_CASE_RANGE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
////// GLFW internal API //////
|
////// GLFW internal API //////
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
@@ -2300,3 +2358,16 @@ float _glfwTransformYNS(float y)
|
|||||||
{
|
{
|
||||||
return CGDisplayBounds(CGMainDisplayID()).size.height - y - 1;
|
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.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// Please use C89 style variable declarations in this file because VS 2010
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#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
|
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;
|
DBusWatch *watch = (DBusWatch*)data;
|
||||||
unsigned int flags = 0;
|
unsigned int flags = 0;
|
||||||
if (events & POLLERR) flags |= DBUS_WATCH_ERROR;
|
if (events & POLLERR) flags |= DBUS_WATCH_ERROR;
|
||||||
@@ -84,19 +84,19 @@ add_dbus_watch(DBusWatch *watch, void *data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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);
|
id_type *idp = dbus_watch_get_data(watch);
|
||||||
if (idp) removeWatch(dbus_data->eld, *idp);
|
if (idp) removeWatch(dbus_data->eld, *idp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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);
|
id_type *idp = dbus_watch_get_data(watch);
|
||||||
if (idp) toggleWatch(dbus_data->eld, *idp, dbus_watch_get_enabled(watch));
|
if (idp) toggleWatch(dbus_data->eld, *idp, dbus_watch_get_enabled(watch));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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) {
|
if (data) {
|
||||||
DBusTimeout *t = (DBusTimeout*)data;
|
DBusTimeout *t = (DBusTimeout*)data;
|
||||||
dbus_timeout_handle(t);
|
dbus_timeout_handle(t);
|
||||||
@@ -123,13 +123,13 @@ add_dbus_timeout(DBusTimeout *timeout, void *data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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);
|
id_type *idp = dbus_timeout_get_data(timeout);
|
||||||
if (idp) removeTimer(dbus_data->eld, *idp);
|
if (idp) removeTimer(dbus_data->eld, *idp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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);
|
id_type *idp = dbus_timeout_get_data(timeout);
|
||||||
if (idp) toggleTimer(dbus_data->eld, *idp, dbus_timeout_get_enabled(timeout));
|
if (idp) toggleTimer(dbus_data->eld, *idp, dbus_timeout_get_enabled(timeout));
|
||||||
}
|
}
|
||||||
@@ -178,7 +178,7 @@ glfw_dbus_session_bus_dispatch() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
glfw_dbus_terminate(_GLFWDBUSData *dbus) {
|
glfw_dbus_terminate(_GLFWDBUSData *dbus UNUSED) {
|
||||||
if (dbus_data) {
|
if (dbus_data) {
|
||||||
dbus_data->eld = NULL;
|
dbus_data->eld = NULL;
|
||||||
dbus_data = 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
|
// GLFW 3.3 EGL - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -24,6 +24,8 @@
|
|||||||
// distribution.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// Please use C89 style variable declarations in this file because VS 2010
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
@@ -253,8 +255,8 @@ static GLFWglproc getProcAddressEGL(const char* procname)
|
|||||||
|
|
||||||
if (window->context.egl.client)
|
if (window->context.egl.client)
|
||||||
{
|
{
|
||||||
GLFWglproc proc = (GLFWglproc) _glfw_dlsym(window->context.egl.client,
|
GLFWglproc proc = NULL;
|
||||||
procname);
|
glfw_dlsym(proc, window->context.egl.client, procname);
|
||||||
if (proc)
|
if (proc)
|
||||||
return proc;
|
return proc;
|
||||||
}
|
}
|
||||||
@@ -335,38 +337,22 @@ bool _glfwInitEGL(void)
|
|||||||
|
|
||||||
_glfw.egl.prefix = (strncmp(sonames[i], "lib", 3) == 0);
|
_glfw.egl.prefix = (strncmp(sonames[i], "lib", 3) == 0);
|
||||||
|
|
||||||
_glfw.egl.GetConfigAttrib = (PFN_eglGetConfigAttrib)
|
glfw_dlsym(_glfw.egl.GetConfigAttrib, _glfw.egl.handle, "eglGetConfigAttrib");
|
||||||
_glfw_dlsym(_glfw.egl.handle, "eglGetConfigAttrib");
|
glfw_dlsym(_glfw.egl.GetConfigs, _glfw.egl.handle, "eglGetConfigs");
|
||||||
_glfw.egl.GetConfigs = (PFN_eglGetConfigs)
|
glfw_dlsym(_glfw.egl.GetDisplay, _glfw.egl.handle, "eglGetDisplay");
|
||||||
_glfw_dlsym(_glfw.egl.handle, "eglGetConfigs");
|
glfw_dlsym(_glfw.egl.GetError, _glfw.egl.handle, "eglGetError");
|
||||||
_glfw.egl.GetDisplay = (PFN_eglGetDisplay)
|
glfw_dlsym(_glfw.egl.Initialize, _glfw.egl.handle, "eglInitialize");
|
||||||
_glfw_dlsym(_glfw.egl.handle, "eglGetDisplay");
|
glfw_dlsym(_glfw.egl.Terminate, _glfw.egl.handle, "eglTerminate");
|
||||||
_glfw.egl.GetError = (PFN_eglGetError)
|
glfw_dlsym(_glfw.egl.BindAPI, _glfw.egl.handle, "eglBindAPI");
|
||||||
_glfw_dlsym(_glfw.egl.handle, "eglGetError");
|
glfw_dlsym(_glfw.egl.CreateContext, _glfw.egl.handle, "eglCreateContext");
|
||||||
_glfw.egl.Initialize = (PFN_eglInitialize)
|
glfw_dlsym(_glfw.egl.DestroySurface, _glfw.egl.handle, "eglDestroySurface");
|
||||||
_glfw_dlsym(_glfw.egl.handle, "eglInitialize");
|
glfw_dlsym(_glfw.egl.DestroyContext, _glfw.egl.handle, "eglDestroyContext");
|
||||||
_glfw.egl.Terminate = (PFN_eglTerminate)
|
glfw_dlsym(_glfw.egl.CreateWindowSurface, _glfw.egl.handle, "eglCreateWindowSurface");
|
||||||
_glfw_dlsym(_glfw.egl.handle, "eglTerminate");
|
glfw_dlsym(_glfw.egl.MakeCurrent, _glfw.egl.handle, "eglMakeCurrent");
|
||||||
_glfw.egl.BindAPI = (PFN_eglBindAPI)
|
glfw_dlsym(_glfw.egl.SwapBuffers, _glfw.egl.handle, "eglSwapBuffers");
|
||||||
_glfw_dlsym(_glfw.egl.handle, "eglBindAPI");
|
glfw_dlsym(_glfw.egl.SwapInterval, _glfw.egl.handle, "eglSwapInterval");
|
||||||
_glfw.egl.CreateContext = (PFN_eglCreateContext)
|
glfw_dlsym(_glfw.egl.QueryString, _glfw.egl.handle, "eglQueryString");
|
||||||
_glfw_dlsym(_glfw.egl.handle, "eglCreateContext");
|
glfw_dlsym(_glfw.egl.GetProcAddress, _glfw.egl.handle, "eglGetProcAddress");
|
||||||
_glfw.egl.DestroySurface = (PFN_eglDestroySurface)
|
|
||||||
_glfw_dlsym(_glfw.egl.handle, "eglDestroySurface");
|
|
||||||
_glfw.egl.DestroyContext = (PFN_eglDestroyContext)
|
|
||||||
_glfw_dlsym(_glfw.egl.handle, "eglDestroyContext");
|
|
||||||
_glfw.egl.CreateWindowSurface = (PFN_eglCreateWindowSurface)
|
|
||||||
_glfw_dlsym(_glfw.egl.handle, "eglCreateWindowSurface");
|
|
||||||
_glfw.egl.MakeCurrent = (PFN_eglMakeCurrent)
|
|
||||||
_glfw_dlsym(_glfw.egl.handle, "eglMakeCurrent");
|
|
||||||
_glfw.egl.SwapBuffers = (PFN_eglSwapBuffers)
|
|
||||||
_glfw_dlsym(_glfw.egl.handle, "eglSwapBuffers");
|
|
||||||
_glfw.egl.SwapInterval = (PFN_eglSwapInterval)
|
|
||||||
_glfw_dlsym(_glfw.egl.handle, "eglSwapInterval");
|
|
||||||
_glfw.egl.QueryString = (PFN_eglQueryString)
|
|
||||||
_glfw_dlsym(_glfw.egl.handle, "eglQueryString");
|
|
||||||
_glfw.egl.GetProcAddress = (PFN_eglGetProcAddress)
|
|
||||||
_glfw_dlsym(_glfw.egl.handle, "eglGetProcAddress");
|
|
||||||
|
|
||||||
if (!_glfw.egl.GetConfigAttrib ||
|
if (!_glfw.egl.GetConfigAttrib ||
|
||||||
!_glfw.egl.GetConfigs ||
|
!_glfw.egl.GetConfigs ||
|
||||||
@@ -446,7 +432,7 @@ void _glfwTerminateEGL(void)
|
|||||||
|
|
||||||
#define setAttrib(a, v) \
|
#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++] = a; \
|
||||||
attribs[index++] = v; \
|
attribs[index++] = v; \
|
||||||
}
|
}
|
||||||
@@ -714,7 +700,7 @@ bool _glfwCreateContextEGL(_GLFWwindow* window,
|
|||||||
// Returns the Visual and depth of the chosen EGLConfig
|
// Returns the Visual and depth of the chosen EGLConfig
|
||||||
//
|
//
|
||||||
#if defined(_GLFW_X11)
|
#if defined(_GLFW_X11)
|
||||||
bool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig,
|
bool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig UNUSED,
|
||||||
const _GLFWctxconfig* ctxconfig,
|
const _GLFWctxconfig* ctxconfig,
|
||||||
const _GLFWfbconfig* fbconfig,
|
const _GLFWfbconfig* fbconfig,
|
||||||
Visual** visual, int* depth)
|
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
|
// GLFW 3.3 EGL - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -173,13 +173,13 @@ typedef struct _GLFWlibraryEGL
|
|||||||
{
|
{
|
||||||
EGLDisplay display;
|
EGLDisplay display;
|
||||||
EGLint major, minor;
|
EGLint major, minor;
|
||||||
bool prefix;
|
bool prefix;
|
||||||
|
|
||||||
bool KHR_create_context;
|
bool KHR_create_context;
|
||||||
bool KHR_create_context_no_error;
|
bool KHR_create_context_no_error;
|
||||||
bool KHR_gl_colorspace;
|
bool KHR_gl_colorspace;
|
||||||
bool KHR_get_all_proc_addresses;
|
bool KHR_get_all_proc_addresses;
|
||||||
bool KHR_context_flush_control;
|
bool KHR_context_flush_control;
|
||||||
|
|
||||||
void* handle;
|
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'):
|
def init_env(env, pkg_config, at_least_version, test_compile, module='x11'):
|
||||||
ans = env.copy()
|
ans = env.copy()
|
||||||
ans.cflags = [
|
|
||||||
x for x in ans.cflags
|
|
||||||
if x not in '-Wpedantic -Wextra -pedantic-errors'.split()
|
|
||||||
]
|
|
||||||
if not is_macos:
|
if not is_macos:
|
||||||
ans.cflags.append('-pthread')
|
ans.cflags.append('-pthread')
|
||||||
ans.ldpaths.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
|
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:
|
for protocol in env.wayland_protocols:
|
||||||
src = os.path.join(env.wayland_packagedir, protocol)
|
src = os.path.join(env.wayland_packagedir, protocol)
|
||||||
if not os.path.exists(src):
|
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)
|
dest = os.path.join(dest_dir, dest)
|
||||||
if newer(dest, src):
|
if newer(dest, src):
|
||||||
q = 'client-header' if ext == 'h' else env.wayland_scanner_code
|
q = 'client-header' if ext == 'h' else env.wayland_scanner_code
|
||||||
run_tool([env.wayland_scanner, q, src, dest],
|
items.append(Command(
|
||||||
desc='Generating {} ...'.format(emphasis(os.path.basename(dest))))
|
'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:
|
class Arg:
|
||||||
|
|||||||
43
glfw/glfw3.h
vendored
43
glfw/glfw3.h
vendored
@@ -3,7 +3,7 @@
|
|||||||
* A library for OpenGL, window and input
|
* A library for OpenGL, window and input
|
||||||
*------------------------------------------------------------------------
|
*------------------------------------------------------------------------
|
||||||
* Copyright (c) 2002-2006 Marcus Geelnard
|
* 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
|
* This software is provided 'as-is', without any express or implied
|
||||||
* warranty. In no event will the authors be held liable for any damages
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -905,62 +905,62 @@ extern "C" {
|
|||||||
#define GLFW_CLIENT_API 0x00022001
|
#define GLFW_CLIENT_API 0x00022001
|
||||||
/*! @brief Context client API major version hint and attribute.
|
/*! @brief Context client API major version hint and attribute.
|
||||||
*
|
*
|
||||||
* Context client API major version [hint](@ref GLFW_CLIENT_API_hint) and
|
* Context client API major version [hint](@ref GLFW_CONTEXT_VERSION_MAJOR_hint)
|
||||||
* [attribute](@ref GLFW_CLIENT_API_attrib).
|
* and [attribute](@ref GLFW_CONTEXT_VERSION_MAJOR_attrib).
|
||||||
*/
|
*/
|
||||||
#define GLFW_CONTEXT_VERSION_MAJOR 0x00022002
|
#define GLFW_CONTEXT_VERSION_MAJOR 0x00022002
|
||||||
/*! @brief Context client API minor version hint and attribute.
|
/*! @brief Context client API minor version hint and attribute.
|
||||||
*
|
*
|
||||||
* Context client API minor version [hint](@ref GLFW_CLIENT_API_hint) and
|
* Context client API minor version [hint](@ref GLFW_CONTEXT_VERSION_MINOR_hint)
|
||||||
* [attribute](@ref GLFW_CLIENT_API_attrib).
|
* and [attribute](@ref GLFW_CONTEXT_VERSION_MINOR_attrib).
|
||||||
*/
|
*/
|
||||||
#define GLFW_CONTEXT_VERSION_MINOR 0x00022003
|
#define GLFW_CONTEXT_VERSION_MINOR 0x00022003
|
||||||
/*! @brief Context client API revision number hint and attribute.
|
/*! @brief Context client API revision number hint and attribute.
|
||||||
*
|
*
|
||||||
* Context client API revision number [hint](@ref GLFW_CLIENT_API_hint) and
|
* Context client API revision number
|
||||||
* [attribute](@ref GLFW_CLIENT_API_attrib).
|
* [attribute](@ref GLFW_CONTEXT_REVISION_attrib).
|
||||||
*/
|
*/
|
||||||
#define GLFW_CONTEXT_REVISION 0x00022004
|
#define GLFW_CONTEXT_REVISION 0x00022004
|
||||||
/*! @brief Context robustness hint and attribute.
|
/*! @brief Context robustness hint and attribute.
|
||||||
*
|
*
|
||||||
* Context client API revision number [hint](@ref GLFW_CLIENT_API_hint) and
|
* Context client API revision number [hint](@ref GLFW_CONTEXT_ROBUSTNESS_hint)
|
||||||
* [attribute](@ref GLFW_CLIENT_API_attrib).
|
* and [attribute](@ref GLFW_CONTEXT_ROBUSTNESS_attrib).
|
||||||
*/
|
*/
|
||||||
#define GLFW_CONTEXT_ROBUSTNESS 0x00022005
|
#define GLFW_CONTEXT_ROBUSTNESS 0x00022005
|
||||||
/*! @brief OpenGL forward-compatibility hint and attribute.
|
/*! @brief OpenGL forward-compatibility hint and attribute.
|
||||||
*
|
*
|
||||||
* OpenGL forward-compatibility [hint](@ref GLFW_CLIENT_API_hint) and
|
* OpenGL forward-compatibility [hint](@ref GLFW_OPENGL_FORWARD_COMPAT_hint)
|
||||||
* [attribute](@ref GLFW_CLIENT_API_attrib).
|
* and [attribute](@ref GLFW_OPENGL_FORWARD_COMPAT_attrib).
|
||||||
*/
|
*/
|
||||||
#define GLFW_OPENGL_FORWARD_COMPAT 0x00022006
|
#define GLFW_OPENGL_FORWARD_COMPAT 0x00022006
|
||||||
/*! @brief OpenGL debug context hint and attribute.
|
/*! @brief OpenGL debug context hint and attribute.
|
||||||
*
|
*
|
||||||
* OpenGL debug context [hint](@ref GLFW_CLIENT_API_hint) and
|
* OpenGL debug context [hint](@ref GLFW_OPENGL_DEBUG_CONTEXT_hint) and
|
||||||
* [attribute](@ref GLFW_CLIENT_API_attrib).
|
* [attribute](@ref GLFW_OPENGL_DEBUG_CONTEXT_attrib).
|
||||||
*/
|
*/
|
||||||
#define GLFW_OPENGL_DEBUG_CONTEXT 0x00022007
|
#define GLFW_OPENGL_DEBUG_CONTEXT 0x00022007
|
||||||
/*! @brief OpenGL profile hint and attribute.
|
/*! @brief OpenGL profile hint and attribute.
|
||||||
*
|
*
|
||||||
* OpenGL profile [hint](@ref GLFW_CLIENT_API_hint) and
|
* OpenGL profile [hint](@ref GLFW_OPENGL_PROFILE_hint) and
|
||||||
* [attribute](@ref GLFW_CLIENT_API_attrib).
|
* [attribute](@ref GLFW_OPENGL_PROFILE_attrib).
|
||||||
*/
|
*/
|
||||||
#define GLFW_OPENGL_PROFILE 0x00022008
|
#define GLFW_OPENGL_PROFILE 0x00022008
|
||||||
/*! @brief Context flush-on-release hint and attribute.
|
/*! @brief Context flush-on-release hint and attribute.
|
||||||
*
|
*
|
||||||
* Context flush-on-release [hint](@ref GLFW_CLIENT_API_hint) and
|
* Context flush-on-release [hint](@ref GLFW_CONTEXT_RELEASE_BEHAVIOR_hint) and
|
||||||
* [attribute](@ref GLFW_CLIENT_API_attrib).
|
* [attribute](@ref GLFW_CONTEXT_RELEASE_BEHAVIOR_attrib).
|
||||||
*/
|
*/
|
||||||
#define GLFW_CONTEXT_RELEASE_BEHAVIOR 0x00022009
|
#define GLFW_CONTEXT_RELEASE_BEHAVIOR 0x00022009
|
||||||
/*! @brief Context error suppression hint and attribute.
|
/*! @brief Context error suppression hint and attribute.
|
||||||
*
|
*
|
||||||
* Context error suppression [hint](@ref GLFW_CLIENT_API_hint) and
|
* Context error suppression [hint](@ref GLFW_CONTEXT_NO_ERROR_hint) and
|
||||||
* [attribute](@ref GLFW_CLIENT_API_attrib).
|
* [attribute](@ref GLFW_CONTEXT_NO_ERROR_attrib).
|
||||||
*/
|
*/
|
||||||
#define GLFW_CONTEXT_NO_ERROR 0x0002200A
|
#define GLFW_CONTEXT_NO_ERROR 0x0002200A
|
||||||
/*! @brief Context creation API hint and attribute.
|
/*! @brief Context creation API hint and attribute.
|
||||||
*
|
*
|
||||||
* Context creation API [hint](@ref GLFW_CLIENT_API_hint) and
|
* Context creation API [hint](@ref GLFW_CONTEXT_CREATION_API_hint) and
|
||||||
* [attribute](@ref GLFW_CLIENT_API_attrib).
|
* [attribute](@ref GLFW_CONTEXT_CREATION_API_attrib).
|
||||||
*/
|
*/
|
||||||
#define GLFW_CONTEXT_CREATION_API 0x0002200B
|
#define GLFW_CONTEXT_CREATION_API 0x0002200B
|
||||||
/*! @brief Window content area scaling window
|
/*! @brief Window content area scaling window
|
||||||
@@ -1628,7 +1628,6 @@ typedef struct GLFWgamepadstate
|
|||||||
GLFWAPI int glfwInit(void);
|
GLFWAPI int glfwInit(void);
|
||||||
GLFWAPI void glfwRunMainLoop(GLFWtickcallback callback, void *callback_data);
|
GLFWAPI void glfwRunMainLoop(GLFWtickcallback callback, void *callback_data);
|
||||||
GLFWAPI void glfwStopMainLoop(void);
|
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 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 glfwUpdateTimer(unsigned long long timer_id, double interval, bool enabled);
|
||||||
GLFWAPI void glfwRemoveTimer(unsigned long long);
|
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
|
// GLFW 3.3 GLX - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -24,6 +24,8 @@
|
|||||||
// distribution.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// It is fine to use C99 in this file because it will not be built with VS
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
@@ -142,7 +144,7 @@ static bool chooseGLXFBConfig(const _GLFWfbconfig* desired,
|
|||||||
|
|
||||||
// Create the OpenGL context using legacy API
|
// Create the OpenGL context using legacy API
|
||||||
//
|
//
|
||||||
static GLXContext createLegacyContextGLX(_GLFWwindow* window,
|
static GLXContext createLegacyContextGLX(_GLFWwindow* window UNUSED,
|
||||||
GLXFBConfig fbconfig,
|
GLXFBConfig fbconfig,
|
||||||
GLXContext share)
|
GLXContext share)
|
||||||
{
|
{
|
||||||
@@ -222,8 +224,11 @@ static GLFWglproc getProcAddressGLX(const char* procname)
|
|||||||
return _glfw.glx.GetProcAddress((const GLubyte*) procname);
|
return _glfw.glx.GetProcAddress((const GLubyte*) procname);
|
||||||
else if (_glfw.glx.GetProcAddressARB)
|
else if (_glfw.glx.GetProcAddressARB)
|
||||||
return _glfw.glx.GetProcAddressARB((const GLubyte*) procname);
|
return _glfw.glx.GetProcAddressARB((const GLubyte*) procname);
|
||||||
else
|
else {
|
||||||
return _glfw_dlsym(_glfw.glx.handle, procname);
|
GLFWglproc ans = NULL;
|
||||||
|
glfw_dlsym(ans, _glfw.glx.handle, procname);
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void destroyContextGLX(_GLFWwindow* window)
|
static void destroyContextGLX(_GLFWwindow* window)
|
||||||
@@ -280,36 +285,21 @@ bool _glfwInitGLX(void)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_glfw.glx.GetFBConfigs =
|
glfw_dlsym(_glfw.glx.GetFBConfigs, _glfw.glx.handle, "glXGetFBConfigs");
|
||||||
_glfw_dlsym(_glfw.glx.handle, "glXGetFBConfigs");
|
glfw_dlsym(_glfw.glx.GetFBConfigAttrib, _glfw.glx.handle, "glXGetFBConfigAttrib");
|
||||||
_glfw.glx.GetFBConfigAttrib =
|
glfw_dlsym(_glfw.glx.GetClientString, _glfw.glx.handle, "glXGetClientString");
|
||||||
_glfw_dlsym(_glfw.glx.handle, "glXGetFBConfigAttrib");
|
glfw_dlsym(_glfw.glx.QueryExtension, _glfw.glx.handle, "glXQueryExtension");
|
||||||
_glfw.glx.GetClientString =
|
glfw_dlsym(_glfw.glx.QueryVersion, _glfw.glx.handle, "glXQueryVersion");
|
||||||
_glfw_dlsym(_glfw.glx.handle, "glXGetClientString");
|
glfw_dlsym(_glfw.glx.DestroyContext, _glfw.glx.handle, "glXDestroyContext");
|
||||||
_glfw.glx.QueryExtension =
|
glfw_dlsym(_glfw.glx.MakeCurrent, _glfw.glx.handle, "glXMakeCurrent");
|
||||||
_glfw_dlsym(_glfw.glx.handle, "glXQueryExtension");
|
glfw_dlsym(_glfw.glx.SwapBuffers, _glfw.glx.handle, "glXSwapBuffers");
|
||||||
_glfw.glx.QueryVersion =
|
glfw_dlsym(_glfw.glx.QueryExtensionsString, _glfw.glx.handle, "glXQueryExtensionsString");
|
||||||
_glfw_dlsym(_glfw.glx.handle, "glXQueryVersion");
|
glfw_dlsym(_glfw.glx.CreateNewContext, _glfw.glx.handle, "glXCreateNewContext");
|
||||||
_glfw.glx.DestroyContext =
|
glfw_dlsym(_glfw.glx.CreateWindow, _glfw.glx.handle, "glXCreateWindow");
|
||||||
_glfw_dlsym(_glfw.glx.handle, "glXDestroyContext");
|
glfw_dlsym(_glfw.glx.DestroyWindow, _glfw.glx.handle, "glXDestroyWindow");
|
||||||
_glfw.glx.MakeCurrent =
|
glfw_dlsym(_glfw.glx.GetProcAddress, _glfw.glx.handle, "glXGetProcAddress");
|
||||||
_glfw_dlsym(_glfw.glx.handle, "glXMakeCurrent");
|
glfw_dlsym(_glfw.glx.GetProcAddressARB, _glfw.glx.handle, "glXGetProcAddressARB");
|
||||||
_glfw.glx.SwapBuffers =
|
glfw_dlsym(_glfw.glx.GetVisualFromFBConfig, _glfw.glx.handle, "glXGetVisualFromFBConfig");
|
||||||
_glfw_dlsym(_glfw.glx.handle, "glXSwapBuffers");
|
|
||||||
_glfw.glx.QueryExtensionsString =
|
|
||||||
_glfw_dlsym(_glfw.glx.handle, "glXQueryExtensionsString");
|
|
||||||
_glfw.glx.CreateNewContext =
|
|
||||||
_glfw_dlsym(_glfw.glx.handle, "glXCreateNewContext");
|
|
||||||
_glfw.glx.CreateWindow =
|
|
||||||
_glfw_dlsym(_glfw.glx.handle, "glXCreateWindow");
|
|
||||||
_glfw.glx.DestroyWindow =
|
|
||||||
_glfw_dlsym(_glfw.glx.handle, "glXDestroyWindow");
|
|
||||||
_glfw.glx.GetProcAddress =
|
|
||||||
_glfw_dlsym(_glfw.glx.handle, "glXGetProcAddress");
|
|
||||||
_glfw.glx.GetProcAddressARB =
|
|
||||||
_glfw_dlsym(_glfw.glx.handle, "glXGetProcAddressARB");
|
|
||||||
_glfw.glx.GetVisualFromFBConfig =
|
|
||||||
_glfw_dlsym(_glfw.glx.handle, "glXGetVisualFromFBConfig");
|
|
||||||
|
|
||||||
if (!_glfw.glx.GetFBConfigs ||
|
if (!_glfw.glx.GetFBConfigs ||
|
||||||
!_glfw.glx.GetFBConfigAttrib ||
|
!_glfw.glx.GetFBConfigAttrib ||
|
||||||
@@ -433,7 +423,7 @@ void _glfwTerminateGLX(void)
|
|||||||
|
|
||||||
#define setAttrib(a, v) \
|
#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++] = a; \
|
||||||
attribs[index++] = v; \
|
attribs[index++] = v; \
|
||||||
}
|
}
|
||||||
@@ -631,8 +621,8 @@ bool _glfwCreateContextGLX(_GLFWwindow* window,
|
|||||||
|
|
||||||
// Returns the Visual and depth of the chosen GLXFBConfig
|
// Returns the Visual and depth of the chosen GLXFBConfig
|
||||||
//
|
//
|
||||||
bool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig,
|
bool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig UNUSED,
|
||||||
const _GLFWctxconfig* ctxconfig,
|
const _GLFWctxconfig* ctxconfig UNUSED,
|
||||||
const _GLFWfbconfig* fbconfig,
|
const _GLFWfbconfig* fbconfig,
|
||||||
Visual** visual, int* depth)
|
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
|
// GLFW 3.3 GLX - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// 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 glXCreateWindow _glfw.glx.CreateWindow
|
||||||
#define glXDestroyWindow _glfw.glx.DestroyWindow
|
#define glXDestroyWindow _glfw.glx.DestroyWindow
|
||||||
|
|
||||||
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextGLX glx
|
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextGLX glx;
|
||||||
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryGLX glx
|
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryGLX glx;
|
||||||
|
|
||||||
|
|
||||||
// GLX-specific per-context data
|
// GLX-specific per-context data
|
||||||
@@ -178,4 +178,3 @@ bool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig,
|
|||||||
const _GLFWctxconfig* ctxconfig,
|
const _GLFWctxconfig* ctxconfig,
|
||||||
const _GLFWfbconfig* fbconfig,
|
const _GLFWfbconfig* fbconfig,
|
||||||
Visual** visual, int* depth);
|
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
|
static inline size_t
|
||||||
MIN(size_t a, size_t b) {
|
GLFW_MIN(size_t a, size_t b) {
|
||||||
return a < b ? a : b;
|
return a < b ? a : b;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +117,7 @@ send_text(const char *text, int state) {
|
|||||||
// Connection handling {{{
|
// Connection handling {{{
|
||||||
|
|
||||||
static DBusHandlerResult
|
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
|
// To monitor signals from IBUS, use
|
||||||
// dbus-monitor --address `ibus address` "type='signal',interface='org.freedesktop.IBus.InputContext'"
|
// dbus-monitor --address `ibus address` "type='signal',interface='org.freedesktop.IBus.InputContext'"
|
||||||
_GLFWIBUSData *ibus = (_GLFWIBUSData*)user_data;
|
_GLFWIBUSData *ibus = (_GLFWIBUSData*)user_data;
|
||||||
@@ -151,7 +151,7 @@ get_ibus_address_file_name(void) {
|
|||||||
addr = getenv("IBUS_ADDRESS");
|
addr = getenv("IBUS_ADDRESS");
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
if (addr && addr[0]) {
|
if (addr && addr[0]) {
|
||||||
memcpy(ans, addr, MIN(strlen(addr), sizeof(ans)));
|
memcpy(ans, addr, GLFW_MIN(strlen(addr), sizeof(ans)));
|
||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
8
glfw/init.c
vendored
8
glfw/init.c
vendored
@@ -2,7 +2,7 @@
|
|||||||
// GLFW 3.3 - www.glfw.org
|
// GLFW 3.3 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -24,6 +24,8 @@
|
|||||||
// distribution.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// Please use C89 style variable declarations in this file because VS 2010
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "mappings.h"
|
#include "mappings.h"
|
||||||
@@ -342,10 +344,6 @@ GLFWAPI void glfwRunMainLoop(GLFWtickcallback callback, void *data)
|
|||||||
_glfwPlatformRunMainLoop(callback, data);
|
_glfwPlatformRunMainLoop(callback, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLFWAPI void glfwRequestTickCallback(void) {
|
|
||||||
_glfwPlatformRequestTickCallback();
|
|
||||||
}
|
|
||||||
|
|
||||||
GLFWAPI void glfwStopMainLoop(void) {
|
GLFWAPI void glfwStopMainLoop(void) {
|
||||||
_GLFW_REQUIRE_INIT();
|
_GLFW_REQUIRE_INIT();
|
||||||
_glfwPlatformStopMainLoop();
|
_glfwPlatformStopMainLoop();
|
||||||
|
|||||||
26
glfw/input.c
vendored
26
glfw/input.c
vendored
@@ -2,7 +2,7 @@
|
|||||||
// GLFW 3.3 - www.glfw.org
|
// GLFW 3.3 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -24,6 +24,8 @@
|
|||||||
// distribution.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// Please use C89 style variable declarations in this file because VS 2010
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
@@ -254,7 +256,7 @@ static bool parseMapping(_GLFWmapping* mapping, const char* string)
|
|||||||
////// GLFW event API //////
|
////// 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)
|
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->present = true;
|
||||||
js->name = _glfw_strdup(name);
|
js->name = _glfw_strdup(name);
|
||||||
js->axes = calloc(axisCount, sizeof(float));
|
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->hats = calloc(hatCount, 1);
|
||||||
js->axisCount = axisCount;
|
js->axisCount = axisCount;
|
||||||
js->buttonCount = buttonCount;
|
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)
|
void _glfwCenterCursorInContentArea(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
int width, height;
|
int width, height;
|
||||||
|
|
||||||
_glfwPlatformGetWindowSize(window, &width, &height);
|
_glfwPlatformGetWindowSize(window, &width, &height);
|
||||||
_glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0);
|
_glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
////// GLFW public API //////
|
////// GLFW public API //////
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
@@ -672,7 +676,9 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
|
|||||||
window->stickyMouseButtons = value;
|
window->stickyMouseButtons = value;
|
||||||
}
|
}
|
||||||
else if (mode == GLFW_LOCK_KEY_MODS)
|
else if (mode == GLFW_LOCK_KEY_MODS)
|
||||||
|
{
|
||||||
window->lockKeyMods = value ? true : false;
|
window->lockKeyMods = value ? true : false;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
_glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
|
_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;
|
const unsigned int bit = e->index & 0xf;
|
||||||
if (js->hats[hat] & bit)
|
if (js->hats[hat] & bit)
|
||||||
state->axes[i] = 1.f;
|
state->axes[i] = 1.f;
|
||||||
|
else
|
||||||
|
state->axes[i] = -1.f;
|
||||||
}
|
}
|
||||||
else if (e->type == _GLFW_JOYSTICK_BUTTON)
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string)
|
GLFWAPI void glfwSetClipboardString(GLFWwindow* handle UNUSED, const char* string)
|
||||||
{
|
{
|
||||||
assert(string != NULL);
|
assert(string != NULL);
|
||||||
|
|
||||||
@@ -1375,14 +1383,14 @@ GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string)
|
|||||||
_glfwPlatformSetClipboardString(string);
|
_glfwPlatformSetClipboardString(string);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle)
|
GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle UNUSED)
|
||||||
{
|
{
|
||||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
return _glfwPlatformGetClipboardString();
|
return _glfwPlatformGetClipboardString();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_GLFW_X11) || defined(_GLFW_WAYLAND)
|
#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);
|
assert(string != NULL);
|
||||||
|
|
||||||
@@ -1390,7 +1398,7 @@ GLFWAPI void glfwSetPrimarySelectionString(GLFWwindow* handle, const char* strin
|
|||||||
_glfwPlatformSetPrimarySelectionString(string);
|
_glfwPlatformSetPrimarySelectionString(string);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLFWAPI const char* glfwGetPrimarySelectionString(GLFWwindow* handle)
|
GLFWAPI const char* glfwGetPrimarySelectionString(GLFWwindow* handle UNUSED)
|
||||||
{
|
{
|
||||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
return _glfwPlatformGetPrimarySelectionString();
|
return _glfwPlatformGetPrimarySelectionString();
|
||||||
|
|||||||
121
glfw/internal.h
vendored
121
glfw/internal.h
vendored
@@ -2,7 +2,7 @@
|
|||||||
// GLFW 3.3 - www.glfw.org
|
// GLFW 3.3 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// 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
|
// Swaps the provided pointers
|
||||||
#define _GLFW_SWAP_POINTERS(x, y) \
|
#define _GLFW_SWAP_POINTERS(x, y) \
|
||||||
{ \
|
do{ \
|
||||||
void* t; \
|
__typeof__(x) t; \
|
||||||
t = x; \
|
t = x; \
|
||||||
x = y; \
|
x = y; \
|
||||||
y = t; \
|
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
|
// Per-thread error structure
|
||||||
//
|
//
|
||||||
@@ -247,12 +267,12 @@ struct _GLFWerror
|
|||||||
//
|
//
|
||||||
struct _GLFWinitconfig
|
struct _GLFWinitconfig
|
||||||
{
|
{
|
||||||
bool hatButtons;
|
bool hatButtons;
|
||||||
bool debugKeyboard;
|
bool debugKeyboard;
|
||||||
bool enableJoysticks;
|
bool enableJoysticks;
|
||||||
struct {
|
struct {
|
||||||
bool menubar;
|
bool menubar;
|
||||||
bool chdir;
|
bool chdir;
|
||||||
} ns;
|
} ns;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -267,18 +287,18 @@ struct _GLFWwndconfig
|
|||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
const char* title;
|
const char* title;
|
||||||
bool resizable;
|
bool resizable;
|
||||||
bool visible;
|
bool visible;
|
||||||
bool decorated;
|
bool decorated;
|
||||||
bool focused;
|
bool focused;
|
||||||
bool autoIconify;
|
bool autoIconify;
|
||||||
bool floating;
|
bool floating;
|
||||||
bool maximized;
|
bool maximized;
|
||||||
bool centerCursor;
|
bool centerCursor;
|
||||||
bool focusOnShow;
|
bool focusOnShow;
|
||||||
bool scaleToMonitor;
|
bool scaleToMonitor;
|
||||||
struct {
|
struct {
|
||||||
bool retina;
|
bool retina;
|
||||||
char frameName[256];
|
char frameName[256];
|
||||||
} ns;
|
} ns;
|
||||||
struct {
|
struct {
|
||||||
@@ -302,15 +322,15 @@ struct _GLFWctxconfig
|
|||||||
int source;
|
int source;
|
||||||
int major;
|
int major;
|
||||||
int minor;
|
int minor;
|
||||||
bool forward;
|
bool forward;
|
||||||
bool debug;
|
bool debug;
|
||||||
bool noerror;
|
bool noerror;
|
||||||
int profile;
|
int profile;
|
||||||
int robustness;
|
int robustness;
|
||||||
int release;
|
int release;
|
||||||
_GLFWwindow* share;
|
_GLFWwindow* share;
|
||||||
struct {
|
struct {
|
||||||
bool offline;
|
bool offline;
|
||||||
} nsgl;
|
} nsgl;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -335,11 +355,11 @@ struct _GLFWfbconfig
|
|||||||
int accumBlueBits;
|
int accumBlueBits;
|
||||||
int accumAlphaBits;
|
int accumAlphaBits;
|
||||||
int auxBuffers;
|
int auxBuffers;
|
||||||
bool stereo;
|
bool stereo;
|
||||||
int samples;
|
int samples;
|
||||||
bool sRGB;
|
bool sRGB;
|
||||||
bool doublebuffer;
|
bool doublebuffer;
|
||||||
bool transparent;
|
bool transparent;
|
||||||
uintptr_t handle;
|
uintptr_t handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -350,7 +370,7 @@ struct _GLFWcontext
|
|||||||
int client;
|
int client;
|
||||||
int source;
|
int source;
|
||||||
int major, minor, revision;
|
int major, minor, revision;
|
||||||
bool forward, debug, noerror;
|
bool forward, debug, noerror;
|
||||||
int profile;
|
int profile;
|
||||||
int robustness;
|
int robustness;
|
||||||
int release;
|
int release;
|
||||||
@@ -367,7 +387,7 @@ struct _GLFWcontext
|
|||||||
_GLFWdestroycontextfun destroy;
|
_GLFWdestroycontextfun destroy;
|
||||||
|
|
||||||
// This is defined in the context API's context.h
|
// 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
|
// This is defined in egl_context.h
|
||||||
_GLFW_EGL_CONTEXT_STATE;
|
_GLFW_EGL_CONTEXT_STATE;
|
||||||
// This is defined in osmesa_context.h
|
// This is defined in osmesa_context.h
|
||||||
@@ -381,12 +401,12 @@ struct _GLFWwindow
|
|||||||
struct _GLFWwindow* next;
|
struct _GLFWwindow* next;
|
||||||
|
|
||||||
// Window settings and state
|
// Window settings and state
|
||||||
bool resizable;
|
bool resizable;
|
||||||
bool decorated;
|
bool decorated;
|
||||||
bool autoIconify;
|
bool autoIconify;
|
||||||
bool floating;
|
bool floating;
|
||||||
bool focusOnShow;
|
bool focusOnShow;
|
||||||
bool shouldClose;
|
bool shouldClose;
|
||||||
void* userPointer;
|
void* userPointer;
|
||||||
GLFWid id;
|
GLFWid id;
|
||||||
GLFWvidmode videoMode;
|
GLFWvidmode videoMode;
|
||||||
@@ -397,9 +417,9 @@ struct _GLFWwindow
|
|||||||
int maxwidth, maxheight;
|
int maxwidth, maxheight;
|
||||||
int numer, denom;
|
int numer, denom;
|
||||||
|
|
||||||
bool stickyKeys;
|
bool stickyKeys;
|
||||||
bool stickyMouseButtons;
|
bool stickyMouseButtons;
|
||||||
bool lockKeyMods;
|
bool lockKeyMods;
|
||||||
int cursorMode;
|
int cursorMode;
|
||||||
char mouseButtons[GLFW_MOUSE_BUTTON_LAST + 1];
|
char mouseButtons[GLFW_MOUSE_BUTTON_LAST + 1];
|
||||||
char keys[GLFW_KEY_LAST + 1];
|
char keys[GLFW_KEY_LAST + 1];
|
||||||
@@ -490,7 +510,7 @@ struct _GLFWmapping
|
|||||||
//
|
//
|
||||||
struct _GLFWjoystick
|
struct _GLFWjoystick
|
||||||
{
|
{
|
||||||
bool present;
|
bool present;
|
||||||
float* axes;
|
float* axes;
|
||||||
int axisCount;
|
int axisCount;
|
||||||
unsigned char* buttons;
|
unsigned char* buttons;
|
||||||
@@ -526,7 +546,7 @@ struct _GLFWmutex
|
|||||||
//
|
//
|
||||||
struct _GLFWlibrary
|
struct _GLFWlibrary
|
||||||
{
|
{
|
||||||
bool initialized;
|
bool initialized;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
_GLFWinitconfig init;
|
_GLFWinitconfig init;
|
||||||
@@ -559,23 +579,23 @@ struct _GLFWlibrary
|
|||||||
} timer;
|
} timer;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool available;
|
bool available;
|
||||||
void* handle;
|
void* handle;
|
||||||
char* extensions[2];
|
char* extensions[2];
|
||||||
#if !defined(_GLFW_VULKAN_STATIC)
|
#if !defined(_GLFW_VULKAN_STATIC)
|
||||||
PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties;
|
PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties;
|
||||||
PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
|
PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
|
||||||
#endif
|
#endif
|
||||||
bool KHR_surface;
|
bool KHR_surface;
|
||||||
#if defined(_GLFW_WIN32)
|
#if defined(_GLFW_WIN32)
|
||||||
bool KHR_win32_surface;
|
bool KHR_win32_surface;
|
||||||
#elif defined(_GLFW_COCOA)
|
#elif defined(_GLFW_COCOA)
|
||||||
bool MVK_macos_surface;
|
bool MVK_macos_surface;
|
||||||
#elif defined(_GLFW_X11)
|
#elif defined(_GLFW_X11)
|
||||||
bool KHR_xlib_surface;
|
bool KHR_xlib_surface;
|
||||||
bool KHR_xcb_surface;
|
bool KHR_xcb_surface;
|
||||||
#elif defined(_GLFW_WAYLAND)
|
#elif defined(_GLFW_WAYLAND)
|
||||||
bool KHR_wayland_surface;
|
bool KHR_wayland_surface;
|
||||||
#endif
|
#endif
|
||||||
} vk;
|
} vk;
|
||||||
|
|
||||||
@@ -587,9 +607,9 @@ struct _GLFWlibrary
|
|||||||
// This is defined in the window API's platform.h
|
// This is defined in the window API's platform.h
|
||||||
_GLFW_PLATFORM_LIBRARY_WINDOW_STATE;
|
_GLFW_PLATFORM_LIBRARY_WINDOW_STATE;
|
||||||
// This is defined in the context API's context.h
|
// 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
|
// 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
|
// This is defined in egl_context.h
|
||||||
_GLFW_EGL_LIBRARY_CONTEXT_STATE;
|
_GLFW_EGL_LIBRARY_CONTEXT_STATE;
|
||||||
// This is defined in osmesa_context.h
|
// This is defined in osmesa_context.h
|
||||||
@@ -802,7 +822,6 @@ const char* _glfwGetVulkanResultString(VkResult result);
|
|||||||
_GLFWwindow* _glfwFocusedWindow(void);
|
_GLFWwindow* _glfwFocusedWindow(void);
|
||||||
_GLFWwindow* _glfwWindowForId(GLFWid id);
|
_GLFWwindow* _glfwWindowForId(GLFWid id);
|
||||||
void _glfwPlatformRunMainLoop(GLFWtickcallback, void*);
|
void _glfwPlatformRunMainLoop(GLFWtickcallback, void*);
|
||||||
void _glfwPlatformRequestTickCallback(void);
|
|
||||||
void _glfwPlatformStopMainLoop(void);
|
void _glfwPlatformStopMainLoop(void);
|
||||||
unsigned long long _glfwPlatformAddTimer(double interval, bool repeats, GLFWuserdatafun callback, void *callback_data, GLFWuserdatafun free_callback);
|
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);
|
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
|
// GLFW 3.3 Linux - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -24,6 +24,8 @@
|
|||||||
// distribution.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// It is fine to use C99 in this file because it will not be built with VS
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
@@ -104,9 +106,7 @@ static void handleAbsEvent(_GLFWjoystick* js, int code, int value)
|
|||||||
//
|
//
|
||||||
static void pollAbsState(_GLFWjoystick* js)
|
static void pollAbsState(_GLFWjoystick* js)
|
||||||
{
|
{
|
||||||
int code;
|
for (int code = 0; code < ABS_CNT; code++)
|
||||||
|
|
||||||
for (code = 0; code < ABS_CNT; code++)
|
|
||||||
{
|
{
|
||||||
if (js->linjs.absMap[code] < 0)
|
if (js->linjs.absMap[code] < 0)
|
||||||
continue;
|
continue;
|
||||||
@@ -126,18 +126,7 @@ static void pollAbsState(_GLFWjoystick* js)
|
|||||||
//
|
//
|
||||||
static bool openJoystickDevice(const char* path)
|
static bool openJoystickDevice(const char* path)
|
||||||
{
|
{
|
||||||
int jid, code;
|
for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
|
||||||
char name[256] = "";
|
|
||||||
char guid[33] = "";
|
|
||||||
char evBits[(EV_CNT + 7) / 8] = {0};
|
|
||||||
char keyBits[(KEY_CNT + 7) / 8] = {0};
|
|
||||||
char absBits[(ABS_CNT + 7) / 8] = {0};
|
|
||||||
int axisCount = 0, buttonCount = 0, hatCount = 0;
|
|
||||||
struct input_id id;
|
|
||||||
_GLFWjoystickLinux linjs = {0};
|
|
||||||
_GLFWjoystick* js = NULL;
|
|
||||||
|
|
||||||
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
|
|
||||||
{
|
{
|
||||||
if (!_glfw.joysticks[jid].present)
|
if (!_glfw.joysticks[jid].present)
|
||||||
continue;
|
continue;
|
||||||
@@ -145,10 +134,16 @@ static bool openJoystickDevice(const char* path)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_GLFWjoystickLinux linjs = {0};
|
||||||
linjs.fd = open(path, O_RDONLY | O_NONBLOCK);
|
linjs.fd = open(path, O_RDONLY | O_NONBLOCK);
|
||||||
if (linjs.fd == -1)
|
if (linjs.fd == -1)
|
||||||
return false;
|
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 ||
|
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_KEY, sizeof(keyBits)), keyBits) < 0 ||
|
||||||
ioctl(linjs.fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits) < 0 ||
|
ioctl(linjs.fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits) < 0 ||
|
||||||
@@ -168,9 +163,13 @@ static bool openJoystickDevice(const char* path)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char name[256] = "";
|
||||||
|
|
||||||
if (ioctl(linjs.fd, EVIOCGNAME(sizeof(name)), name) < 0)
|
if (ioctl(linjs.fd, EVIOCGNAME(sizeof(name)), name) < 0)
|
||||||
strncpy(name, "Unknown", sizeof(name));
|
strncpy(name, "Unknown", sizeof(name));
|
||||||
|
|
||||||
|
char guid[33] = "";
|
||||||
|
|
||||||
// Generate a joystick GUID that matches the SDL 2.0.5+ one
|
// Generate a joystick GUID that matches the SDL 2.0.5+ one
|
||||||
if (id.vendor && id.product && id.version)
|
if (id.vendor && id.product && id.version)
|
||||||
{
|
{
|
||||||
@@ -189,7 +188,9 @@ static bool openJoystickDevice(const char* path)
|
|||||||
name[8], name[9], name[10]);
|
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))
|
if (!isBitSet(code, keyBits))
|
||||||
continue;
|
continue;
|
||||||
@@ -198,7 +199,7 @@ static bool openJoystickDevice(const char* path)
|
|||||||
buttonCount++;
|
buttonCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (code = 0; code < ABS_CNT; code++)
|
for (int code = 0; code < ABS_CNT; code++)
|
||||||
{
|
{
|
||||||
linjs.absMap[code] = -1;
|
linjs.absMap[code] = -1;
|
||||||
if (!isBitSet(code, absBits))
|
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)
|
if (!js)
|
||||||
{
|
{
|
||||||
close(linjs.fd);
|
close(linjs.fd);
|
||||||
@@ -266,8 +267,6 @@ static int compareJoysticks(const void* fp, const void* sp)
|
|||||||
//
|
//
|
||||||
bool _glfwInitJoysticksLinux(void)
|
bool _glfwInitJoysticksLinux(void)
|
||||||
{
|
{
|
||||||
DIR* dir;
|
|
||||||
int count = 0;
|
|
||||||
const char* dirname = "/dev/input";
|
const char* dirname = "/dev/input";
|
||||||
|
|
||||||
_glfw.linjs.inotify = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
_glfw.linjs.inotify = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
||||||
@@ -289,7 +288,9 @@ bool _glfwInitJoysticksLinux(void)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
dir = opendir(dirname);
|
int count = 0;
|
||||||
|
|
||||||
|
DIR* dir = opendir(dirname);
|
||||||
if (dir)
|
if (dir)
|
||||||
{
|
{
|
||||||
struct dirent* entry;
|
struct dirent* entry;
|
||||||
@@ -314,7 +315,7 @@ bool _glfwInitJoysticksLinux(void)
|
|||||||
|
|
||||||
// Continue with no joysticks if enumeration fails
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,12 +345,12 @@ void _glfwTerminateJoysticksLinux(void)
|
|||||||
|
|
||||||
void _glfwDetectJoystickConnectionLinux(void)
|
void _glfwDetectJoystickConnectionLinux(void)
|
||||||
{
|
{
|
||||||
ssize_t offset = 0;
|
|
||||||
char buffer[16384];
|
|
||||||
|
|
||||||
if (_glfw.linjs.inotify <= 0)
|
if (_glfw.linjs.inotify <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
ssize_t offset = 0;
|
||||||
|
char buffer[16384];
|
||||||
const ssize_t size = read(_glfw.linjs.inotify, buffer, sizeof(buffer));
|
const ssize_t size = read(_glfw.linjs.inotify, buffer, sizeof(buffer));
|
||||||
|
|
||||||
while (size > offset)
|
while (size > offset)
|
||||||
@@ -369,9 +370,7 @@ void _glfwDetectJoystickConnectionLinux(void)
|
|||||||
openJoystickDevice(path);
|
openJoystickDevice(path);
|
||||||
else if (e->mask & IN_DELETE)
|
else if (e->mask & IN_DELETE)
|
||||||
{
|
{
|
||||||
int jid;
|
for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
|
||||||
|
|
||||||
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
|
|
||||||
{
|
{
|
||||||
if (strcmp(_glfw.joysticks[jid].linjs.path, path) == 0)
|
if (strcmp(_glfw.joysticks[jid].linjs.path, path) == 0)
|
||||||
{
|
{
|
||||||
@@ -388,7 +387,7 @@ void _glfwDetectJoystickConnectionLinux(void)
|
|||||||
////// GLFW platform API //////
|
////// GLFW platform API //////
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode)
|
int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode UNUSED)
|
||||||
{
|
{
|
||||||
// Read all queued events (non-blocking)
|
// Read all queued events (non-blocking)
|
||||||
for (;;)
|
for (;;)
|
||||||
@@ -428,6 +427,6 @@ int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode)
|
|||||||
return js->present;
|
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>
|
#include <regex.h>
|
||||||
|
|
||||||
#define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickLinux linjs
|
#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"
|
#define _GLFW_PLATFORM_MAPPING_NAME "Linux"
|
||||||
|
|
||||||
@@ -59,4 +59,3 @@ typedef struct _GLFWlibraryLinux
|
|||||||
bool _glfwInitJoysticksLinux(void);
|
bool _glfwInitJoysticksLinux(void);
|
||||||
void _glfwTerminateJoysticksLinux(void);
|
void _glfwTerminateJoysticksLinux(void);
|
||||||
void _glfwDetectJoystickConnectionLinux(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
|
static DBusHandlerResult
|
||||||
message_handler(DBusConnection *conn, DBusMessage *msg, void *user_data) {
|
message_handler(DBusConnection *conn UNUSED, DBusMessage *msg, void *user_data UNUSED) {
|
||||||
(void)(user_data);
|
|
||||||
/* printf("session_bus message_handler invoked interface: %s member: %s\n", dbus_message_get_interface(msg), dbus_message_get_member(msg)); */
|
/* 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")) {
|
if (dbus_message_is_signal(msg, NOTIFICATIONS_IFACE, "ActionInvoked")) {
|
||||||
uint32_t notification_id;
|
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;
|
static bool keep_going = false;
|
||||||
|
|
||||||
void _glfwPlatformRequestTickCallback() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void _glfwPlatformStopMainLoop(void) {
|
void _glfwPlatformStopMainLoop(void) {
|
||||||
if (keep_going) {
|
if (keep_going) {
|
||||||
@@ -25,12 +23,17 @@ void _glfwPlatformStopMainLoop(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformRunMainLoop(GLFWtickcallback tick_callback, void* data) {
|
void _glfwPlatformRunMainLoop(GLFWtickcallback tick_callback, void* data) {
|
||||||
keep_going = true;
|
keep_going = 1;
|
||||||
|
EventLoopData *eld = &_glfw.GLFW_LOOP_BACKEND.eventLoopData;
|
||||||
while(keep_going) {
|
while(keep_going) {
|
||||||
_glfwPlatformWaitEvents();
|
_glfwPlatformWaitEvents();
|
||||||
EVDBG("loop tick");
|
EVDBG("--------- loop tick, wakeups_happened: %d ----------", eld->wakeup_data_read);
|
||||||
tick_callback(data);
|
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) {
|
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
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// 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
|
// GLFW 3.3 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -24,6 +24,8 @@
|
|||||||
// distribution.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// Please use C89 style variable declarations in this file because VS 2010
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
@@ -72,7 +74,7 @@ static bool refreshVideoModes(_GLFWmonitor* monitor)
|
|||||||
if (!modes)
|
if (!modes)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
qsort(modes, modeCount, sizeof(GLFWvidmode), compareVideoModes);
|
qsort(modes, modeCount, sizeof(modes[0]), compareVideoModes);
|
||||||
|
|
||||||
free(monitor->modes);
|
free(monitor->modes);
|
||||||
monitor->modes = modes;
|
monitor->modes = modes;
|
||||||
@@ -100,7 +102,7 @@ void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement)
|
|||||||
{
|
{
|
||||||
memmove(_glfw.monitors + 1,
|
memmove(_glfw.monitors + 1,
|
||||||
_glfw.monitors,
|
_glfw.monitors,
|
||||||
(_glfw.monitorCount - 1) * sizeof(_GLFWmonitor*));
|
((size_t) _glfw.monitorCount - 1) * sizeof(_GLFWmonitor*));
|
||||||
_glfw.monitors[0] = monitor;
|
_glfw.monitors[0] = monitor;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -327,7 +329,9 @@ GLFWAPI void glfwGetMonitorPos(GLFWmonitor* handle, int* xpos, int* ypos)
|
|||||||
_glfwPlatformGetMonitorPos(monitor, xpos, 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;
|
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||||
assert(monitor != NULL);
|
assert(monitor != NULL);
|
||||||
@@ -448,7 +452,7 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
|
|||||||
GLFWgammaramp ramp;
|
GLFWgammaramp ramp;
|
||||||
const GLFWgammaramp* original;
|
const GLFWgammaramp* original;
|
||||||
assert(handle != NULL);
|
assert(handle != NULL);
|
||||||
assert(gamma >= 0.f);
|
assert(gamma > 0.f);
|
||||||
assert(gamma <= FLT_MAX);
|
assert(gamma <= FLT_MAX);
|
||||||
|
|
||||||
_GLFW_REQUIRE_INIT();
|
_GLFW_REQUIRE_INIT();
|
||||||
@@ -458,6 +462,7 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
|
|||||||
_glfwInputError(GLFW_INVALID_VALUE, "Invalid gamma value %f", gamma);
|
_glfwInputError(GLFW_INVALID_VALUE, "Invalid gamma value %f", gamma);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
original = glfwGetGammaRamp(handle);
|
original = glfwGetGammaRamp(handle);
|
||||||
if (!original)
|
if (!original)
|
||||||
return;
|
return;
|
||||||
@@ -472,10 +477,8 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
|
|||||||
value = i / (float) (original->size - 1);
|
value = i / (float) (original->size - 1);
|
||||||
// Apply gamma curve
|
// Apply gamma curve
|
||||||
value = powf(value, 1.f / gamma) * 65535.f + 0.5f;
|
value = powf(value, 1.f / gamma) * 65535.f + 0.5f;
|
||||||
|
|
||||||
// Clamp to value range
|
// Clamp to value range
|
||||||
if (value > 65535.f)
|
value = fminf(value, 65535.f);
|
||||||
value = 65535.f;
|
|
||||||
|
|
||||||
values[i] = (unsigned short) value;
|
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
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// 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_CONTEXT_STATE _GLFWcontextNSGL nsgl;
|
||||||
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryNSGL nsgl
|
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryNSGL nsgl;
|
||||||
|
|
||||||
|
|
||||||
// NSGL-specific per-context data
|
// NSGL-specific per-context data
|
||||||
@@ -53,4 +53,3 @@ bool _glfwCreateContextNSGL(_GLFWwindow* window,
|
|||||||
const _GLFWctxconfig* ctxconfig,
|
const _GLFWctxconfig* ctxconfig,
|
||||||
const _GLFWfbconfig* fbconfig);
|
const _GLFWfbconfig* fbconfig);
|
||||||
void _glfwDestroyContextNSGL(_GLFWwindow* window);
|
void _glfwDestroyContextNSGL(_GLFWwindow* window);
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
// GLFW 3.3 macOS - www.glfw.org
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -23,6 +23,8 @@
|
|||||||
// distribution.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// It is fine to use C99 in this file because it will not be built with VS
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
@@ -43,15 +45,14 @@ static void swapBuffersNSGL(_GLFWwindow* window)
|
|||||||
[window->context.nsgl.object flushBuffer];
|
[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
|
// As of Mojave this does not work so we use CVDisplayLink instead
|
||||||
(void)(interval);
|
|
||||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||||
"NSGL: Swap intervals do not work on macOS");
|
"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
|
// There are no NSGL extensions
|
||||||
return false;
|
return false;
|
||||||
@@ -63,8 +64,9 @@ static GLFWglproc getProcAddressNSGL(const char* procname)
|
|||||||
procname,
|
procname,
|
||||||
kCFStringEncodingASCII);
|
kCFStringEncodingASCII);
|
||||||
|
|
||||||
GLFWglproc symbol = CFBundleGetFunctionPointerForName(_glfw.nsgl.framework,
|
GLFWglproc symbol;
|
||||||
symbolName);
|
*(void **) &symbol = CFBundleGetFunctionPointerForName(_glfw.nsgl.framework,
|
||||||
|
symbolName);
|
||||||
|
|
||||||
CFRelease(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");
|
"NSGL: The targeted version of macOS does not support OpenGL 3.0 or 3.1 but may support 3.2 and above");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Context robustness modes (GL_KHR_robustness) are not yet supported by
|
// Context robustness modes (GL_KHR_robustness) are not yet supported by
|
||||||
@@ -288,7 +289,8 @@ bool _glfwCreateContextNSGL(_GLFWwindow* window,
|
|||||||
if (fbconfig->transparent)
|
if (fbconfig->transparent)
|
||||||
{
|
{
|
||||||
GLint opaque = 0;
|
GLint opaque = 0;
|
||||||
[window->context.nsgl.object setValues:&opaque forParameter:NSOpenGLContextParameterSurfaceOpacity];
|
[window->context.nsgl.object setValues:&opaque
|
||||||
|
forParameter:NSOpenGLContextParameterSurfaceOpacity];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window->ns.retina)
|
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
|
// GLFW 3.3 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2016 Google Inc.
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -24,6 +24,8 @@
|
|||||||
// distribution.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// It is fine to use C99 in this file because it will not be built with VS
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#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
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -23,6 +23,8 @@
|
|||||||
// distribution.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// It is fine to use C99 in this file because it will not be built with VS
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#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
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// 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_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 ""
|
#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
|
// GLFW 3.3 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2016 Google Inc.
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -24,6 +24,8 @@
|
|||||||
// distribution.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// It is fine to use C99 in this file because it will not be built with VS
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
@@ -49,7 +51,9 @@ void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
|
|||||||
*yscale = 1.f;
|
*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)
|
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
|
// GLFW 3.3 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2016 Google Inc.
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// 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
|
// GLFW 3.3 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2016 Google Inc.
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -24,6 +24,8 @@
|
|||||||
// distribution.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// It is fine to use C99 in this file because it will not be built with VS
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
@@ -333,3 +335,4 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
|
|||||||
// This seems like the most appropriate error to return here
|
// This seems like the most appropriate error to return here
|
||||||
return VK_ERROR_INITIALIZATION_FAILED;
|
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
|
// GLFW 3.3 OSMesa - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2016 Google Inc.
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -24,6 +24,8 @@
|
|||||||
// distribution.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// Please use C89 style variable declarations in this file because VS 2010
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -47,7 +49,7 @@ static void makeContextCurrentOSMesa(_GLFWwindow* window)
|
|||||||
free(window->context.osmesa.buffer);
|
free(window->context.osmesa.buffer);
|
||||||
|
|
||||||
// Allocate the new buffer (width * height * 8-bit RGBA)
|
// 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.width = width;
|
||||||
window->context.osmesa.height = height;
|
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
|
// No double buffering on OSMesa
|
||||||
}
|
}
|
||||||
|
|
||||||
static void swapIntervalOSMesa(int interval)
|
static void swapIntervalOSMesa(int interval UNUSED)
|
||||||
{
|
{
|
||||||
// No swap interval on OSMesa
|
// No swap interval on OSMesa
|
||||||
}
|
}
|
||||||
|
|
||||||
static int extensionSupportedOSMesa(const char* extension)
|
static int extensionSupportedOSMesa(const char* extension UNUSED)
|
||||||
{
|
{
|
||||||
// OSMesa does not have extensions
|
// OSMesa does not have extensions
|
||||||
return false;
|
return false;
|
||||||
@@ -145,20 +147,13 @@ bool _glfwInitOSMesa(void)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_glfw.osmesa.CreateContextExt = (PFN_OSMesaCreateContextExt)
|
glfw_dlsym(_glfw.osmesa.CreateContextExt, _glfw.osmesa.handle, "OSMesaCreateContextExt");
|
||||||
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaCreateContextExt");
|
glfw_dlsym(_glfw.osmesa.CreateContextAttribs, _glfw.osmesa.handle, "OSMesaCreateContextAttribs");
|
||||||
_glfw.osmesa.CreateContextAttribs = (PFN_OSMesaCreateContextAttribs)
|
glfw_dlsym(_glfw.osmesa.DestroyContext, _glfw.osmesa.handle, "OSMesaDestroyContext");
|
||||||
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaCreateContextAttribs");
|
glfw_dlsym(_glfw.osmesa.MakeCurrent, _glfw.osmesa.handle, "OSMesaMakeCurrent");
|
||||||
_glfw.osmesa.DestroyContext = (PFN_OSMesaDestroyContext)
|
glfw_dlsym(_glfw.osmesa.GetColorBuffer, _glfw.osmesa.handle, "OSMesaGetColorBuffer");
|
||||||
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaDestroyContext");
|
glfw_dlsym(_glfw.osmesa.GetDepthBuffer, _glfw.osmesa.handle, "OSMesaGetDepthBuffer");
|
||||||
_glfw.osmesa.MakeCurrent = (PFN_OSMesaMakeCurrent)
|
glfw_dlsym(_glfw.osmesa.GetProcAddress, _glfw.osmesa.handle, "OSMesaGetProcAddress");
|
||||||
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaMakeCurrent");
|
|
||||||
_glfw.osmesa.GetColorBuffer = (PFN_OSMesaGetColorBuffer)
|
|
||||||
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetColorBuffer");
|
|
||||||
_glfw.osmesa.GetDepthBuffer = (PFN_OSMesaGetDepthBuffer)
|
|
||||||
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetDepthBuffer");
|
|
||||||
_glfw.osmesa.GetProcAddress = (PFN_OSMesaGetProcAddress)
|
|
||||||
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetProcAddress");
|
|
||||||
|
|
||||||
if (!_glfw.osmesa.CreateContextExt ||
|
if (!_glfw.osmesa.CreateContextExt ||
|
||||||
!_glfw.osmesa.DestroyContext ||
|
!_glfw.osmesa.DestroyContext ||
|
||||||
@@ -188,7 +183,7 @@ void _glfwTerminateOSMesa(void)
|
|||||||
|
|
||||||
#define setAttrib(a, v) \
|
#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++] = a; \
|
||||||
attribs[index++] = v; \
|
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
|
// GLFW 3.3 OSMesa - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2016 Google Inc.
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// 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
|
// GLFW 3.3 POSIX - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -24,6 +24,8 @@
|
|||||||
// distribution.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// It is fine to use C99 in this file because it will not be built with VS
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#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
|
// GLFW 3.3 POSIX - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// 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
|
// GLFW 3.3 POSIX - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -24,6 +24,8 @@
|
|||||||
// distribution.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// It is fine to use C99 in this file because it will not be built with VS
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#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
|
// GLFW 3.3 POSIX - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// 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
|
// GLFW 3.3 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -24,6 +24,8 @@
|
|||||||
// distribution.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// Please use C89 style variable declarations in this file because VS 2010
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
@@ -66,7 +68,7 @@ bool _glfwInitVulkan(int mode)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_glfw.vk.GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)
|
*(void **) &_glfw.vk.GetInstanceProcAddr =
|
||||||
_glfw_dlsym(_glfw.vk.handle, "vkGetInstanceProcAddr");
|
_glfw_dlsym(_glfw.vk.handle, "vkGetInstanceProcAddr");
|
||||||
if (!_glfw.vk.GetInstanceProcAddr)
|
if (!_glfw.vk.GetInstanceProcAddr)
|
||||||
{
|
{
|
||||||
@@ -260,7 +262,7 @@ GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance,
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (!proc)
|
if (!proc)
|
||||||
proc = (GLFWvkproc) _glfw_dlsym(_glfw.vk.handle, procname);
|
*(void **) &proc = _glfw_dlsym(_glfw.vk.handle, procname);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return proc;
|
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
|
// GLFW 3.3 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// 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>
|
// Copyright (c) 2012 Torsten Walluhn <tw@mad-cad.net>
|
||||||
//
|
//
|
||||||
// This software is provided 'as-is', without any express or implied
|
// This software is provided 'as-is', without any express or implied
|
||||||
@@ -25,6 +25,8 @@
|
|||||||
// distribution.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// Please use C89 style variable declarations in this file because VS 2010
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
@@ -82,7 +84,7 @@ _GLFWwindow* _glfwFocusedWindow() {
|
|||||||
_GLFWwindow* _glfwWindowForId(GLFWid id) {
|
_GLFWwindow* _glfwWindowForId(GLFWid id) {
|
||||||
_GLFWwindow *w = _glfw.windowListHead;
|
_GLFWwindow *w = _glfw.windowListHead;
|
||||||
while (w) {
|
while (w) {
|
||||||
if (w->id == _glfw.focusedWindowId) return w;
|
if (w->id == id) return w;
|
||||||
w = w->next;
|
w = w->next;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -181,7 +183,6 @@ void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor)
|
|||||||
window->monitor = monitor;
|
window->monitor = monitor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
////// GLFW public API //////
|
////// GLFW public API //////
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
@@ -1165,6 +1166,5 @@ GLFWAPI GLFWwindowcontentscalefun glfwSetWindowContentScaleCallback(GLFWwindow*
|
|||||||
GLFWAPI void glfwPostEmptyEvent(void)
|
GLFWAPI void glfwPostEmptyEvent(void)
|
||||||
{
|
{
|
||||||
_GLFW_REQUIRE_INIT();
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
_glfwPlatformPostEmptyEvent();
|
_glfwPlatformPostEmptyEvent();
|
||||||
}
|
}
|
||||||
|
|||||||
153
glfw/wl_init.c
vendored
153
glfw/wl_init.c
vendored
@@ -23,6 +23,8 @@
|
|||||||
// distribution.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// It is fine to use C99 in this file because it will not be built with VS
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
@@ -31,7 +33,6 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <linux/input.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -39,6 +40,16 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <wayland-client.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)
|
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;
|
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;
|
int focus;
|
||||||
_GLFWwindow* window = _glfw.windowListHead;
|
_GLFWwindow* window = _glfw.windowListHead;
|
||||||
@@ -79,12 +91,12 @@ static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface,
|
|||||||
return window;
|
return window;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pointerHandleEnter(void* data,
|
static void pointerHandleEnter(void* data UNUSED,
|
||||||
struct wl_pointer* pointer,
|
struct wl_pointer* pointer UNUSED,
|
||||||
uint32_t serial,
|
uint32_t serial,
|
||||||
struct wl_surface* surface,
|
struct wl_surface* surface,
|
||||||
wl_fixed_t sx,
|
wl_fixed_t sx UNUSED,
|
||||||
wl_fixed_t sy)
|
wl_fixed_t sy UNUSED)
|
||||||
{
|
{
|
||||||
// Happens in the case we just destroyed the surface.
|
// Happens in the case we just destroyed the surface.
|
||||||
if (!surface)
|
if (!surface)
|
||||||
@@ -109,10 +121,10 @@ static void pointerHandleEnter(void* data,
|
|||||||
_glfwInputCursorEnter(window, true);
|
_glfwInputCursorEnter(window, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pointerHandleLeave(void* data,
|
static void pointerHandleLeave(void* data UNUSED,
|
||||||
struct wl_pointer* pointer,
|
struct wl_pointer* pointer UNUSED,
|
||||||
uint32_t serial,
|
uint32_t serial,
|
||||||
struct wl_surface* surface)
|
struct wl_surface* surface UNUSED)
|
||||||
{
|
{
|
||||||
_GLFWwindow* window = _glfw.wl.pointerFocus;
|
_GLFWwindow* window = _glfw.wl.pointerFocus;
|
||||||
|
|
||||||
@@ -154,9 +166,9 @@ static void setCursor(GLFWCursorShape shape)
|
|||||||
wl_surface_commit(surface);
|
wl_surface_commit(surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pointerHandleMotion(void* data,
|
static void pointerHandleMotion(void* data UNUSED,
|
||||||
struct wl_pointer* pointer,
|
struct wl_pointer* pointer UNUSED,
|
||||||
uint32_t time,
|
uint32_t time UNUSED,
|
||||||
wl_fixed_t sx,
|
wl_fixed_t sx,
|
||||||
wl_fixed_t sy)
|
wl_fixed_t sy)
|
||||||
{
|
{
|
||||||
@@ -174,7 +186,8 @@ static void pointerHandleMotion(void* data,
|
|||||||
switch (window->wl.decorations.focus)
|
switch (window->wl.decorations.focus)
|
||||||
{
|
{
|
||||||
case mainWindow:
|
case mainWindow:
|
||||||
_glfwInputCursorPos(window, window->wl.cursorPosX, window->wl.cursorPosY);
|
_glfwInputCursorPos(window,
|
||||||
|
window->wl.cursorPosX, window->wl.cursorPosY);
|
||||||
return;
|
return;
|
||||||
case topDecoration:
|
case topDecoration:
|
||||||
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
|
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
|
||||||
@@ -208,16 +221,15 @@ static void pointerHandleMotion(void* data,
|
|||||||
setCursor(cursorShape);
|
setCursor(cursorShape);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pointerHandleButton(void* data,
|
static void pointerHandleButton(void* data UNUSED,
|
||||||
struct wl_pointer* pointer,
|
struct wl_pointer* pointer UNUSED,
|
||||||
uint32_t serial,
|
uint32_t serial,
|
||||||
uint32_t time,
|
uint32_t time UNUSED,
|
||||||
uint32_t button,
|
uint32_t button,
|
||||||
uint32_t state)
|
uint32_t state)
|
||||||
{
|
{
|
||||||
_GLFWwindow* window = _glfw.wl.pointerFocus;
|
_GLFWwindow* window = _glfw.wl.pointerFocus;
|
||||||
int glfwButton;
|
int glfwButton;
|
||||||
|
|
||||||
uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE;
|
uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE;
|
||||||
|
|
||||||
if (!window)
|
if (!window)
|
||||||
@@ -296,9 +308,9 @@ static void pointerHandleButton(void* data,
|
|||||||
_glfw.wl.xkb.states.modifiers);
|
_glfw.wl.xkb.states.modifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pointerHandleAxis(void* data,
|
static void pointerHandleAxis(void* data UNUSED,
|
||||||
struct wl_pointer* pointer,
|
struct wl_pointer* pointer UNUSED,
|
||||||
uint32_t time,
|
uint32_t time UNUSED,
|
||||||
uint32_t axis,
|
uint32_t axis,
|
||||||
wl_fixed_t value)
|
wl_fixed_t value)
|
||||||
{
|
{
|
||||||
@@ -326,8 +338,8 @@ static const struct wl_pointer_listener pointerListener = {
|
|||||||
pointerHandleAxis,
|
pointerHandleAxis,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void keyboardHandleKeymap(void* data,
|
static void keyboardHandleKeymap(void* data UNUSED,
|
||||||
struct wl_keyboard* keyboard,
|
struct wl_keyboard* keyboard UNUSED,
|
||||||
uint32_t format,
|
uint32_t format,
|
||||||
int fd,
|
int fd,
|
||||||
uint32_t size)
|
uint32_t size)
|
||||||
@@ -351,11 +363,11 @@ static void keyboardHandleKeymap(void* data,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void keyboardHandleEnter(void* data,
|
static void keyboardHandleEnter(void* data UNUSED,
|
||||||
struct wl_keyboard* keyboard,
|
struct wl_keyboard* keyboard UNUSED,
|
||||||
uint32_t serial,
|
uint32_t serial UNUSED,
|
||||||
struct wl_surface* surface,
|
struct wl_surface* surface,
|
||||||
struct wl_array* keys)
|
struct wl_array* keys UNUSED)
|
||||||
{
|
{
|
||||||
// Happens in the case we just destroyed the surface.
|
// Happens in the case we just destroyed the surface.
|
||||||
if (!surface)
|
if (!surface)
|
||||||
@@ -373,10 +385,10 @@ static void keyboardHandleEnter(void* data,
|
|||||||
_glfwInputWindowFocus(window, true);
|
_glfwInputWindowFocus(window, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void keyboardHandleLeave(void* data,
|
static void keyboardHandleLeave(void* data UNUSED,
|
||||||
struct wl_keyboard* keyboard,
|
struct wl_keyboard* keyboard UNUSED,
|
||||||
uint32_t serial,
|
uint32_t serial UNUSED,
|
||||||
struct wl_surface* surface)
|
struct wl_surface* surface UNUSED)
|
||||||
{
|
{
|
||||||
_GLFWwindow* window = _glfw.wl.keyboardFocus;
|
_GLFWwindow* window = _glfw.wl.keyboardFocus;
|
||||||
|
|
||||||
@@ -388,7 +400,7 @@ static void keyboardHandleLeave(void* data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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;
|
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);
|
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));
|
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,
|
static void keyboardHandleKey(void* data UNUSED,
|
||||||
struct wl_keyboard* keyboard,
|
struct wl_keyboard* keyboard UNUSED,
|
||||||
uint32_t serial,
|
uint32_t serial UNUSED,
|
||||||
uint32_t time,
|
uint32_t time UNUSED,
|
||||||
uint32_t key,
|
uint32_t key,
|
||||||
uint32_t state)
|
uint32_t state)
|
||||||
{
|
{
|
||||||
@@ -422,9 +434,9 @@ static void keyboardHandleKey(void* data,
|
|||||||
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, repeatable ? 1 : 0);
|
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, repeatable ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void keyboardHandleModifiers(void* data,
|
static void keyboardHandleModifiers(void* data UNUSED,
|
||||||
struct wl_keyboard* keyboard,
|
struct wl_keyboard* keyboard UNUSED,
|
||||||
uint32_t serial,
|
uint32_t serial UNUSED,
|
||||||
uint32_t modsDepressed,
|
uint32_t modsDepressed,
|
||||||
uint32_t modsLatched,
|
uint32_t modsLatched,
|
||||||
uint32_t modsLocked,
|
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);
|
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,
|
struct wl_keyboard* keyboard,
|
||||||
int32_t rate,
|
int32_t rate,
|
||||||
int32_t delay)
|
int32_t delay)
|
||||||
@@ -454,7 +466,7 @@ static const struct wl_keyboard_listener keyboardListener = {
|
|||||||
keyboardHandleRepeatInfo,
|
keyboardHandleRepeatInfo,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void seatHandleCapabilities(void* data,
|
static void seatHandleCapabilities(void* data UNUSED,
|
||||||
struct wl_seat* seat,
|
struct wl_seat* seat,
|
||||||
enum wl_seat_capability caps)
|
enum wl_seat_capability caps)
|
||||||
{
|
{
|
||||||
@@ -481,9 +493,9 @@ static void seatHandleCapabilities(void* data,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void seatHandleName(void* data,
|
static void seatHandleName(void* data UNUSED,
|
||||||
struct wl_seat* seat,
|
struct wl_seat* seat UNUSED,
|
||||||
const char* name)
|
const char* name UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -492,7 +504,7 @@ static const struct wl_seat_listener seatListener = {
|
|||||||
seatHandleName,
|
seatHandleName,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void wmBaseHandlePing(void* data,
|
static void wmBaseHandlePing(void* data UNUSED,
|
||||||
struct xdg_wm_base* wmBase,
|
struct xdg_wm_base* wmBase,
|
||||||
uint32_t serial)
|
uint32_t serial)
|
||||||
{
|
{
|
||||||
@@ -503,7 +515,7 @@ static const struct xdg_wm_base_listener wmBaseListener = {
|
|||||||
wmBaseHandlePing
|
wmBaseHandlePing
|
||||||
};
|
};
|
||||||
|
|
||||||
static void registryHandleGlobal(void* data,
|
static void registryHandleGlobal(void* data UNUSED,
|
||||||
struct wl_registry* registry,
|
struct wl_registry* registry,
|
||||||
uint32_t name,
|
uint32_t name,
|
||||||
const char* interface,
|
const char* interface,
|
||||||
@@ -609,8 +621,8 @@ static void registryHandleGlobal(void* data,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void registryHandleGlobalRemove(void *data,
|
static void registryHandleGlobalRemove(void *data UNUSED,
|
||||||
struct wl_registry *registry,
|
struct wl_registry *registry UNUSED,
|
||||||
uint32_t name)
|
uint32_t name)
|
||||||
{
|
{
|
||||||
_GLFWmonitor* monitor;
|
_GLFWmonitor* monitor;
|
||||||
@@ -642,19 +654,19 @@ static const struct wl_registry_listener registryListener = {
|
|||||||
|
|
||||||
|
|
||||||
static void registry_handle_global(void* data,
|
static void registry_handle_global(void* data,
|
||||||
struct wl_registry* registry,
|
struct wl_registry* registry UNUSED,
|
||||||
uint32_t name,
|
uint32_t name UNUSED,
|
||||||
const char* interface,
|
const char* interface,
|
||||||
uint32_t version) {
|
uint32_t version UNUSED) {
|
||||||
if (strcmp(interface, "zxdg_decoration_manager_v1") == 0) {
|
if (strcmp(interface, "zxdg_decoration_manager_v1") == 0) {
|
||||||
bool *has_ssd = (bool*)data;
|
bool *has_ssd = (bool*)data;
|
||||||
if (has_ssd) *has_ssd = true;
|
if (has_ssd) *has_ssd = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void registry_handle_global_remove(void *data,
|
static void registry_handle_global_remove(void *data UNUSED,
|
||||||
struct wl_registry *registry,
|
struct wl_registry *registry UNUSED,
|
||||||
uint32_t name) {}
|
uint32_t name UNUSED) {}
|
||||||
GLFWAPI const char*
|
GLFWAPI const char*
|
||||||
glfwWaylandCheckForServerSideDecorations(void) {
|
glfwWaylandCheckForServerSideDecorations(void) {
|
||||||
struct wl_display *display = wl_display_connect(NULL);
|
struct wl_display *display = wl_display_connect(NULL);
|
||||||
@@ -679,13 +691,6 @@ glfwWaylandCheckForServerSideDecorations(void) {
|
|||||||
|
|
||||||
int _glfwPlatformInit(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");
|
_glfw.wl.cursor.handle = _glfw_dlopen("libwayland-cursor.so.0");
|
||||||
if (!_glfw.wl.cursor.handle)
|
if (!_glfw.wl.cursor.handle)
|
||||||
{
|
{
|
||||||
@@ -694,14 +699,10 @@ int _glfwPlatformInit(void)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_glfw.wl.cursor.theme_load = (PFN_wl_cursor_theme_load)
|
glfw_dlsym(_glfw.wl.cursor.theme_load, _glfw.wl.cursor.handle, "wl_cursor_theme_load");
|
||||||
_glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_load");
|
glfw_dlsym(_glfw.wl.cursor.theme_destroy, _glfw.wl.cursor.handle, "wl_cursor_theme_destroy");
|
||||||
_glfw.wl.cursor.theme_destroy = (PFN_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.handle, "wl_cursor_theme_destroy");
|
glfw_dlsym(_glfw.wl.cursor.image_get_buffer, _glfw.wl.cursor.handle, "wl_cursor_image_get_buffer");
|
||||||
_glfw.wl.cursor.theme_get_cursor = (PFN_wl_cursor_theme_get_cursor)
|
|
||||||
_glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_get_cursor");
|
|
||||||
_glfw.wl.cursor.image_get_buffer = (PFN_wl_cursor_image_get_buffer)
|
|
||||||
_glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_image_get_buffer");
|
|
||||||
|
|
||||||
_glfw.wl.egl.handle = _glfw_dlopen("libwayland-egl.so.1");
|
_glfw.wl.egl.handle = _glfw_dlopen("libwayland-egl.so.1");
|
||||||
if (!_glfw.wl.egl.handle)
|
if (!_glfw.wl.egl.handle)
|
||||||
@@ -711,12 +712,9 @@ int _glfwPlatformInit(void)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_glfw.wl.egl.window_create = (PFN_wl_egl_window_create)
|
glfw_dlsym(_glfw.wl.egl.window_create, _glfw.wl.egl.handle, "wl_egl_window_create");
|
||||||
_glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_create");
|
glfw_dlsym(_glfw.wl.egl.window_destroy, _glfw.wl.egl.handle, "wl_egl_window_destroy");
|
||||||
_glfw.wl.egl.window_destroy = (PFN_wl_egl_window_destroy)
|
glfw_dlsym(_glfw.wl.egl.window_resize, _glfw.wl.egl.handle, "wl_egl_window_resize");
|
||||||
_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.wl.display = wl_display_connect(NULL);
|
_glfw.wl.display = wl_display_connect(NULL);
|
||||||
if (!_glfw.wl.display)
|
if (!_glfw.wl.display)
|
||||||
@@ -725,7 +723,10 @@ int _glfwPlatformInit(void)
|
|||||||
"Wayland: Failed to connect to display");
|
"Wayland: Failed to connect to display");
|
||||||
return false;
|
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_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.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);
|
_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_flush(_glfw.wl.display);
|
||||||
wl_display_disconnect(_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.clipboardString); _glfw.wl.clipboardString = NULL;
|
||||||
free(_glfw.wl.primarySelectionString); _glfw.wl.primarySelectionString = NULL;
|
free(_glfw.wl.primarySelectionString); _glfw.wl.primarySelectionString = NULL;
|
||||||
free(_glfw.wl.pasteString); _glfw.wl.pasteString = 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.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// It is fine to use C99 in this file because it will not be built with VS
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
@@ -34,15 +36,15 @@
|
|||||||
|
|
||||||
|
|
||||||
static void outputHandleGeometry(void* data,
|
static void outputHandleGeometry(void* data,
|
||||||
struct wl_output* output,
|
struct wl_output* output UNUSED,
|
||||||
int32_t x,
|
int32_t x,
|
||||||
int32_t y,
|
int32_t y,
|
||||||
int32_t physicalWidth,
|
int32_t physicalWidth,
|
||||||
int32_t physicalHeight,
|
int32_t physicalHeight,
|
||||||
int32_t subpixel,
|
int32_t subpixel UNUSED,
|
||||||
const char* make,
|
const char* make,
|
||||||
const char* model,
|
const char* model,
|
||||||
int32_t transform)
|
int32_t transform UNUSED)
|
||||||
{
|
{
|
||||||
struct _GLFWmonitor *monitor = data;
|
struct _GLFWmonitor *monitor = data;
|
||||||
char name[1024];
|
char name[1024];
|
||||||
@@ -57,11 +59,11 @@ static void outputHandleGeometry(void* data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void outputHandleMode(void* data,
|
static void outputHandleMode(void* data,
|
||||||
struct wl_output* output,
|
struct wl_output* output UNUSED,
|
||||||
uint32_t flags,
|
uint32_t flags,
|
||||||
int32_t width,
|
int32_t width,
|
||||||
int32_t height,
|
int32_t height,
|
||||||
int32_t refresh)
|
int32_t refresh)
|
||||||
{
|
{
|
||||||
struct _GLFWmonitor *monitor = data;
|
struct _GLFWmonitor *monitor = data;
|
||||||
GLFWvidmode mode;
|
GLFWvidmode mode;
|
||||||
@@ -71,7 +73,7 @@ static void outputHandleMode(void* data,
|
|||||||
mode.redBits = 8;
|
mode.redBits = 8;
|
||||||
mode.greenBits = 8;
|
mode.greenBits = 8;
|
||||||
mode.blueBits = 8;
|
mode.blueBits = 8;
|
||||||
mode.refreshRate = (int)round(refresh / 1000.0);
|
mode.refreshRate = (int) round(refresh / 1000.0);
|
||||||
|
|
||||||
monitor->modeCount++;
|
monitor->modeCount++;
|
||||||
monitor->modes =
|
monitor->modes =
|
||||||
@@ -82,7 +84,7 @@ static void outputHandleMode(void* data,
|
|||||||
monitor->wl.currentMode = monitor->modeCount - 1;
|
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;
|
struct _GLFWmonitor *monitor = data;
|
||||||
for (int i = 0; i < _glfw.monitorCount; i++) {
|
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,
|
static void outputHandleScale(void* data,
|
||||||
struct wl_output* output,
|
struct wl_output* output UNUSED,
|
||||||
int32_t factor)
|
int32_t factor)
|
||||||
{
|
{
|
||||||
struct _GLFWmonitor *monitor = data;
|
struct _GLFWmonitor *monitor = data;
|
||||||
if (factor > 0 && factor < 24)
|
if (factor > 0 && factor < 24)
|
||||||
@@ -173,7 +175,9 @@ void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
|
|||||||
*yscale = (float) monitor->wl.scale;
|
*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)
|
if (xpos)
|
||||||
*xpos = monitor->wl.x;
|
*xpos = monitor->wl.x;
|
||||||
@@ -196,14 +200,15 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
|
|||||||
*mode = monitor->modes[monitor->wl.currentMode];
|
*mode = monitor->modes[monitor->wl.currentMode];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
bool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor UNUSED, GLFWgammaramp* ramp UNUSED)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
"Wayland: Gamma ramp access is not available");
|
"Wayland: Gamma ramp access is not available");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
|
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor UNUSED,
|
||||||
|
const GLFWgammaramp* ramp UNUSED)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
"Wayland: Gamma ramp access is not available");
|
"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
|
typedef struct _GLFWwindowWayland
|
||||||
{
|
{
|
||||||
int width, height;
|
int width, height;
|
||||||
bool visible;
|
bool visible;
|
||||||
bool maximized;
|
bool maximized;
|
||||||
bool hovered;
|
bool hovered;
|
||||||
bool transparent;
|
bool transparent;
|
||||||
struct wl_surface* surface;
|
struct wl_surface* surface;
|
||||||
struct wl_egl_window* native;
|
struct wl_egl_window* native;
|
||||||
struct wl_callback* callback;
|
struct wl_callback* callback;
|
||||||
@@ -167,10 +167,10 @@ typedef struct _GLFWwindowWayland
|
|||||||
|
|
||||||
struct zwp_idle_inhibitor_v1* idleInhibitor;
|
struct zwp_idle_inhibitor_v1* idleInhibitor;
|
||||||
|
|
||||||
bool fullscreened;
|
bool fullscreened;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool serverSide;
|
bool serverSide;
|
||||||
struct wl_buffer* buffer;
|
struct wl_buffer* buffer;
|
||||||
_GLFWdecorationWayland top, left, right, bottom;
|
_GLFWdecorationWayland top, left, right, bottom;
|
||||||
int focus;
|
int focus;
|
||||||
@@ -295,7 +295,7 @@ typedef struct _GLFWlibraryWayland
|
|||||||
typedef struct _GLFWmonitorWayland
|
typedef struct _GLFWmonitorWayland
|
||||||
{
|
{
|
||||||
struct wl_output* output;
|
struct wl_output* output;
|
||||||
int name;
|
uint32_t name;
|
||||||
int currentMode;
|
int currentMode;
|
||||||
|
|
||||||
int x;
|
int x;
|
||||||
|
|||||||
157
glfw/wl_window.c
vendored
157
glfw/wl_window.c
vendored
@@ -23,6 +23,8 @@
|
|||||||
// distribution.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// It is fine to use C99 in this file because it will not be built with VS
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
@@ -239,7 +241,7 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image)
|
|||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_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);
|
length);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -248,7 +250,7 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image)
|
|||||||
if (data == MAP_FAILED)
|
if (data == MAP_FAILED)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
"Wayland: mmap failed: %m");
|
"Wayland: mmap failed: %%m");
|
||||||
close(fd);
|
close(fd);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -363,12 +365,12 @@ static void destroyDecorations(_GLFWwindow* window)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void xdgDecorationHandleConfigure(void* data,
|
static void xdgDecorationHandleConfigure(void* data,
|
||||||
struct zxdg_toplevel_decoration_v1* decoration,
|
struct zxdg_toplevel_decoration_v1* decoration UNUSED,
|
||||||
uint32_t mode)
|
uint32_t mode)
|
||||||
{
|
{
|
||||||
_GLFWwindow* window = data;
|
_GLFWwindow* window = data;
|
||||||
window->wl.decorations.serverSide = (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
|
window->wl.decorations.serverSide = (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
|
||||||
if (!window->wl.decorations.serverSide)
|
if (!window->wl.decorations.serverSide)
|
||||||
createDecorations(window);
|
createDecorations(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,7 +379,7 @@ static const struct zxdg_toplevel_decoration_v1_listener xdgDecorationListener =
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void handleEnter(void *data,
|
static void handleEnter(void *data,
|
||||||
struct wl_surface *surface,
|
struct wl_surface *surface UNUSED,
|
||||||
struct wl_output *output)
|
struct wl_output *output)
|
||||||
{
|
{
|
||||||
_GLFWwindow* window = data;
|
_GLFWwindow* window = data;
|
||||||
@@ -400,7 +402,7 @@ static void handleEnter(void *data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void handleLeave(void *data,
|
static void handleLeave(void *data,
|
||||||
struct wl_surface *surface,
|
struct wl_surface *surface UNUSED,
|
||||||
struct wl_output *output)
|
struct wl_output *output)
|
||||||
{
|
{
|
||||||
_GLFWwindow* window = data;
|
_GLFWwindow* window = data;
|
||||||
@@ -496,15 +498,14 @@ setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor, bool on)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
_glfwPlatformToggleFullscreen(_GLFWwindow *window, unsigned int flags) {
|
_glfwPlatformToggleFullscreen(_GLFWwindow *window, unsigned int flags UNUSED) {
|
||||||
(void) flags;
|
|
||||||
bool already_fullscreen = window->wl.fullscreened;
|
bool already_fullscreen = window->wl.fullscreened;
|
||||||
setFullscreen(window, NULL, !already_fullscreen);
|
setFullscreen(window, NULL, !already_fullscreen);
|
||||||
return !already_fullscreen;
|
return !already_fullscreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xdgToplevelHandleConfigure(void* data,
|
static void xdgToplevelHandleConfigure(void* data,
|
||||||
struct xdg_toplevel* toplevel,
|
struct xdg_toplevel* toplevel UNUSED,
|
||||||
int32_t width,
|
int32_t width,
|
||||||
int32_t height,
|
int32_t height,
|
||||||
struct wl_array* states)
|
struct wl_array* states)
|
||||||
@@ -562,7 +563,7 @@ static void xdgToplevelHandleConfigure(void* data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void xdgToplevelHandleClose(void* data,
|
static void xdgToplevelHandleClose(void* data,
|
||||||
struct xdg_toplevel* toplevel)
|
struct xdg_toplevel* toplevel UNUSED)
|
||||||
{
|
{
|
||||||
_GLFWwindow* window = data;
|
_GLFWwindow* window = data;
|
||||||
_glfwInputWindowCloseRequest(window);
|
_glfwInputWindowCloseRequest(window);
|
||||||
@@ -573,7 +574,7 @@ static const struct xdg_toplevel_listener xdgToplevelListener = {
|
|||||||
xdgToplevelHandleClose
|
xdgToplevelHandleClose
|
||||||
};
|
};
|
||||||
|
|
||||||
static void xdgSurfaceHandleConfigure(void* data,
|
static void xdgSurfaceHandleConfigure(void* data UNUSED,
|
||||||
struct xdg_surface* surface,
|
struct xdg_surface* surface,
|
||||||
uint32_t serial)
|
uint32_t serial)
|
||||||
{
|
{
|
||||||
@@ -726,7 +727,7 @@ incrementCursorImage(_GLFWwindow* window)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
animateCursorImage(id_type timer_id, void *data) {
|
animateCursorImage(id_type timer_id UNUSED, void *data UNUSED) {
|
||||||
incrementCursorImage(_glfw.wl.pointerFocus);
|
incrementCursorImage(_glfw.wl.pointerFocus);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -739,6 +740,8 @@ abortOnFatalError(int last_error) {
|
|||||||
_glfwInputWindowCloseRequest(window);
|
_glfwInputWindowCloseRequest(window);
|
||||||
window = window->next;
|
window = window->next;
|
||||||
}
|
}
|
||||||
|
// ensure the tick callback is called
|
||||||
|
_glfw.wl.eventLoopData.wakeup_data_read = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -746,16 +749,17 @@ handleEvents(double timeout)
|
|||||||
{
|
{
|
||||||
struct wl_display* display = _glfw.wl.display;
|
struct wl_display* display = _glfw.wl.display;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
EVDBG("starting handleEvents(%.2f)", timeout);
|
||||||
|
|
||||||
while (wl_display_prepare_read(display) != 0) {
|
while (wl_display_prepare_read(display) != 0) {
|
||||||
while(1) {
|
while(1) {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
int num_dispatched = wl_display_dispatch_pending(display);
|
int num_dispatched = wl_display_dispatch_pending(display);
|
||||||
if (num_dispatched == 0) return;
|
|
||||||
if (num_dispatched < 0) {
|
if (num_dispatched < 0) {
|
||||||
if (errno == EAGAIN) continue;
|
if (errno == EAGAIN) continue;
|
||||||
int last_error = wl_display_get_error(display);
|
int last_error = wl_display_get_error(display);
|
||||||
if (last_error) abortOnFatalError(last_error);
|
if (last_error) abortOnFatalError(last_error);
|
||||||
|
wl_display_cancel_read(display);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -774,9 +778,12 @@ handleEvents(double timeout)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool display_read_ok = pollForEvents(&_glfw.wl.eventLoopData, timeout);
|
bool display_read_ok = pollForEvents(&_glfw.wl.eventLoopData, timeout);
|
||||||
|
EVDBG("display_read_ok: %d", display_read_ok);
|
||||||
if (display_read_ok) {
|
if (display_read_ok) {
|
||||||
wl_display_read_events(display);
|
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
|
else
|
||||||
{
|
{
|
||||||
@@ -784,6 +791,8 @@ handleEvents(double timeout)
|
|||||||
}
|
}
|
||||||
glfw_ibus_dispatch(&_glfw.wl.xkb.ibus);
|
glfw_ibus_dispatch(&_glfw.wl.xkb.ibus);
|
||||||
glfw_dbus_session_bus_dispatch();
|
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*
|
static struct wl_cursor*
|
||||||
@@ -914,6 +923,7 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
|
|||||||
destroyDecorations(window);
|
destroyDecorations(window);
|
||||||
if (window->wl.xdg.decoration)
|
if (window->wl.xdg.decoration)
|
||||||
zxdg_toplevel_decoration_v1_destroy(window->wl.xdg.decoration);
|
zxdg_toplevel_decoration_v1_destroy(window->wl.xdg.decoration);
|
||||||
|
|
||||||
if (window->wl.decorations.buffer)
|
if (window->wl.decorations.buffer)
|
||||||
wl_buffer_destroy(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);
|
xdg_toplevel_set_title(window->wl.xdg.toplevel, title);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
|
void _glfwPlatformSetWindowIcon(_GLFWwindow* window UNUSED,
|
||||||
int count, const GLFWimage* images)
|
int count UNUSED, const GLFWimage* images UNUSED)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
"Wayland: Setting window icon not supported");
|
"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
|
// A Wayland client is not aware of its position, so just warn and leave it
|
||||||
// as (0, 0)
|
// as (0, 0)
|
||||||
@@ -960,7 +970,7 @@ void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
|
|||||||
"Wayland: Window position retrieval not supported");
|
"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
|
// 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.
|
// TODO: find out how to trigger a resize.
|
||||||
// The actual limits are checked in the xdg_toplevel::configure handler.
|
// 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);
|
_glfwPlatformGetWindowSize(window, width, height);
|
||||||
*width *= window->wl.scale;
|
*width *= window->wl.scale;
|
||||||
@@ -1040,7 +1052,7 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
|
|||||||
*yscale = (float) window->wl.scale;
|
*yscale = (float) window->wl.scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window)
|
double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
return 0.5;
|
return 0.5;
|
||||||
}
|
}
|
||||||
@@ -1096,7 +1108,7 @@ void _glfwPlatformHideWindow(_GLFWwindow* window)
|
|||||||
window->wl.visible = false;
|
window->wl.visible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window)
|
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
static bool notified = false;
|
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
|
// TODO: Use an actual Wayland API to implement this when one becomes available
|
||||||
static char tty[L_ctermid + 1];
|
static char tty[L_ctermid + 1];
|
||||||
@@ -1120,7 +1132,7 @@ int _glfwPlatformWindowBell(_GLFWwindow* window)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformFocusWindow(_GLFWwindow* window)
|
void _glfwPlatformFocusWindow(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
"Wayland: Focusing a window requires user interaction");
|
"Wayland: Focusing a window requires user interaction");
|
||||||
@@ -1128,9 +1140,9 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window)
|
|||||||
|
|
||||||
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
|
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
|
||||||
_GLFWmonitor* monitor,
|
_GLFWmonitor* monitor,
|
||||||
int xpos, int ypos,
|
int xpos UNUSED, int ypos UNUSED,
|
||||||
int width, int height,
|
int width UNUSED, int height UNUSED,
|
||||||
int refreshRate)
|
int refreshRate UNUSED)
|
||||||
{
|
{
|
||||||
setFullscreen(window, monitor, monitor != NULL);
|
setFullscreen(window, monitor, monitor != NULL);
|
||||||
_glfwInputWindowMonitor(window, monitor);
|
_glfwInputWindowMonitor(window, monitor);
|
||||||
@@ -1141,12 +1153,12 @@ int _glfwPlatformWindowFocused(_GLFWwindow* window)
|
|||||||
return _glfw.wl.keyboardFocus == window;
|
return _glfw.wl.keyboardFocus == window;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _glfwPlatformWindowOccluded(_GLFWwindow* window)
|
int _glfwPlatformWindowOccluded(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _glfwPlatformWindowIconified(_GLFWwindow* window)
|
int _glfwPlatformWindowIconified(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
// xdg-shell doesn’t give any way to request whether a surface is
|
// xdg-shell doesn’t give any way to request whether a surface is
|
||||||
// iconified.
|
// iconified.
|
||||||
@@ -1173,7 +1185,7 @@ int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
|
|||||||
return window->wl.transparent;
|
return window->wl.transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, bool enabled)
|
void _glfwPlatformSetWindowResizable(_GLFWwindow* window UNUSED, bool enabled UNUSED)
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_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
|
// TODO
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
"Wayland: Window attribute setting not implemented yet");
|
"Wayland: Window attribute setting not implemented yet");
|
||||||
}
|
}
|
||||||
|
|
||||||
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window)
|
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
return 1.f;
|
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)
|
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)
|
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);
|
_glfwPlatformSetCursor(window, window->wl.currentCursor);
|
||||||
}
|
}
|
||||||
@@ -1268,7 +1280,7 @@ int _glfwPlatformGetKeyScancode(int key)
|
|||||||
|
|
||||||
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||||
const GLFWimage* image,
|
const GLFWimage* image,
|
||||||
int xhot, int yhot, int count)
|
int xhot, int yhot, int count UNUSED)
|
||||||
{
|
{
|
||||||
cursor->wl.buffer = createShmBuffer(image);
|
cursor->wl.buffer = createShmBuffer(image);
|
||||||
if (!cursor->wl.buffer)
|
if (!cursor->wl.buffer)
|
||||||
@@ -1302,11 +1314,11 @@ void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void handleRelativeMotion(void* data,
|
static void handleRelativeMotion(void* data,
|
||||||
struct zwp_relative_pointer_v1* pointer,
|
struct zwp_relative_pointer_v1* pointer UNUSED,
|
||||||
uint32_t timeHi,
|
uint32_t timeHi UNUSED,
|
||||||
uint32_t timeLo,
|
uint32_t timeLo UNUSED,
|
||||||
wl_fixed_t dx,
|
wl_fixed_t dx UNUSED,
|
||||||
wl_fixed_t dy,
|
wl_fixed_t dy UNUSED,
|
||||||
wl_fixed_t dxUnaccel,
|
wl_fixed_t dxUnaccel,
|
||||||
wl_fixed_t dyUnaccel)
|
wl_fixed_t dyUnaccel)
|
||||||
{
|
{
|
||||||
@@ -1324,8 +1336,8 @@ static const struct zwp_relative_pointer_v1_listener relativePointerListener = {
|
|||||||
handleRelativeMotion
|
handleRelativeMotion
|
||||||
};
|
};
|
||||||
|
|
||||||
static void handleLocked(void* data,
|
static void handleLocked(void* data UNUSED,
|
||||||
struct zwp_locked_pointer_v1* lockedPointer)
|
struct zwp_locked_pointer_v1* lockedPointer UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1343,10 +1355,10 @@ static void unlockPointer(_GLFWwindow* window)
|
|||||||
window->wl.pointerLock.lockedPointer = NULL;
|
window->wl.pointerLock.lockedPointer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lockPointer(_GLFWwindow* window);
|
static void lockPointer(_GLFWwindow* window UNUSED);
|
||||||
|
|
||||||
static void handleUnlocked(void* data,
|
static void handleUnlocked(void* data UNUSED,
|
||||||
struct zwp_locked_pointer_v1* lockedPointer)
|
struct zwp_locked_pointer_v1* lockedPointer UNUSED)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1468,12 +1480,12 @@ static void send_text(char *text, int fd)
|
|||||||
close(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);
|
send_text(_glfw.wl.clipboardString, fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _glfwSendPrimarySelectionText(void *data, struct zwp_primary_selection_source_v1 *primary_selection_source,
|
static void _glfwSendPrimarySelectionText(void *data UNUSED, struct zwp_primary_selection_source_v1 *primary_selection_source UNUSED,
|
||||||
const char *mime_type, int fd) {
|
const char *mime_type UNUSED, int fd) {
|
||||||
send_text(_glfw.wl.primarySelectionString, 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]);
|
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)
|
if (_glfw.wl.dataSourceForClipboard == wl_data_source)
|
||||||
_glfw.wl.dataSourceForClipboard = NULL;
|
_glfw.wl.dataSourceForClipboard = NULL;
|
||||||
wl_data_source_destroy(wl_data_source);
|
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)
|
if (_glfw.wl.dataSourceForPrimarySelection == primary_selection_source)
|
||||||
_glfw.wl.dataSourceForPrimarySelection = NULL;
|
_glfw.wl.dataSourceForPrimarySelection = NULL;
|
||||||
zwp_primary_selection_source_v1_destroy(primary_selection_source);
|
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,
|
.send = _glfwSendClipboardText,
|
||||||
.cancelled = data_source_canceled,
|
.cancelled = data_source_canceled,
|
||||||
.target = data_source_target,
|
.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,
|
.send = _glfwSendPrimarySelectionText,
|
||||||
.cancelled = primary_selection_source_canceled,
|
.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++) {
|
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||||
if (_glfw.wl.dataOffers[i].id == data_offer) {
|
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();
|
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) {
|
struct zwp_primary_selection_offer_v1 *primary_selection_offer) {
|
||||||
for (size_t i = 0; i < arraysz(_glfw.wl.primarySelectionOffers); i++) {
|
for (size_t i = 0; i < arraysz(_glfw.wl.primarySelectionOffers); i++) {
|
||||||
if (_glfw.wl.primarySelectionOffers[i].id == primary_selection_offer) {
|
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;
|
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++) {
|
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||||
if (_glfw.wl.dataOffers[i].id == id) {
|
if (_glfw.wl.dataOffers[i].id == id) {
|
||||||
set_offer_mimetype(&_glfw.wl.dataOffers[i], mime);
|
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++) {
|
for (size_t i = 0; i < arraysz(_glfw.wl.primarySelectionOffers); i++) {
|
||||||
if (_glfw.wl.primarySelectionOffers[i].id == id) {
|
if (_glfw.wl.primarySelectionOffers[i].id == id) {
|
||||||
set_offer_mimetype((struct _GLFWWaylandDataOffer*)&_glfw.wl.primarySelectionOffers[i], mime);
|
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++) {
|
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||||
if (_glfw.wl.dataOffers[i].id == id) {
|
if (_glfw.wl.dataOffers[i].id == id) {
|
||||||
_glfw.wl.dataOffers[i].source_actions = actions;
|
_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++) {
|
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||||
if (_glfw.wl.dataOffers[i].id == id) {
|
if (_glfw.wl.dataOffers[i].id == id) {
|
||||||
_glfw.wl.dataOffers[i].dnd_action = action;
|
_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,
|
.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;
|
size_t smallest_idx = SIZE_MAX, pos = 0;
|
||||||
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||||
if (_glfw.wl.dataOffers[i].idx && _glfw.wl.dataOffers[i].idx < smallest_idx) {
|
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);
|
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;
|
size_t smallest_idx = SIZE_MAX, pos = 0;
|
||||||
for (size_t i = 0; i < arraysz(_glfw.wl.primarySelectionOffers); i++) {
|
for (size_t i = 0; i < arraysz(_glfw.wl.primarySelectionOffers); i++) {
|
||||||
if (_glfw.wl.primarySelectionOffers[i].idx && _glfw.wl.primarySelectionOffers[i].idx < smallest_idx) {
|
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);
|
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++) {
|
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||||
if (_glfw.wl.dataOffers[i].id == id) {
|
if (_glfw.wl.dataOffers[i].id == id) {
|
||||||
_glfw.wl.dataOffers[i].offer_type = DRAG_AND_DROP;
|
_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();
|
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++) {
|
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||||
if (_glfw.wl.dataOffers[i].offer_type == DRAG_AND_DROP) {
|
if (_glfw.wl.dataOffers[i].offer_type == DRAG_AND_DROP) {
|
||||||
wl_data_offer_destroy(_glfw.wl.dataOffers[i].id);
|
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++) {
|
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||||
if (_glfw.wl.dataOffers[i].offer_type == DRAG_AND_DROP) {
|
if (_glfw.wl.dataOffers[i].offer_type == DRAG_AND_DROP) {
|
||||||
char *uri_list = read_data_offer(_glfw.wl.dataOffers[i].id, URI_LIST_MIME);
|
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,
|
.data_offer = handle_data_offer,
|
||||||
.selection = mark_selection_offer,
|
.selection = mark_selection_offer,
|
||||||
.enter = drag_enter,
|
.enter = drag_enter,
|
||||||
@@ -1773,7 +1785,7 @@ const static struct wl_data_device_listener data_device_listener = {
|
|||||||
.leave = drag_leave,
|
.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,
|
.data_offer = handle_primary_selection_offer,
|
||||||
.selection = mark_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, "STRING");
|
||||||
wl_data_source_offer(_glfw.wl.dataSourceForClipboard, "UTF8_STRING");
|
wl_data_source_offer(_glfw.wl.dataSourceForClipboard, "UTF8_STRING");
|
||||||
struct wl_callback *callback = wl_display_sync(_glfw.wl.display);
|
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);
|
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, "STRING");
|
||||||
zwp_primary_selection_source_v1_offer(_glfw.wl.dataSourceForPrimarySelection, "UTF8_STRING");
|
zwp_primary_selection_source_v1_offer(_glfw.wl.dataSourceForPrimarySelection, "UTF8_STRING");
|
||||||
struct wl_callback *callback = wl_display_sync(_glfw.wl.display);
|
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);
|
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
|
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;
|
_GLFWwindow* window = (_GLFWwindow*) data;
|
||||||
if (callback == window->wl.frameCallbackData.current_wl_callback) {
|
if (callback == window->wl.frameCallbackData.current_wl_callback) {
|
||||||
window->wl.frameCallbackData.callback(window->wl.frameCallbackData.id);
|
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);
|
wl_callback_destroy(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
////// GLFW native API //////
|
////// 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
|
// GLFW 3.3 X11 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -24,6 +24,8 @@
|
|||||||
// distribution.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// It is fine to use C99 in this file because it will not be built with VS
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
@@ -46,10 +48,9 @@ static Atom getSupportedAtom(Atom* supportedAtoms,
|
|||||||
unsigned long atomCount,
|
unsigned long atomCount,
|
||||||
const char* atomName)
|
const char* atomName)
|
||||||
{
|
{
|
||||||
unsigned long i;
|
|
||||||
const Atom atom = XInternAtom(_glfw.x11.display, atomName, False);
|
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)
|
if (supportedAtoms[i] == atom)
|
||||||
return atom;
|
return atom;
|
||||||
@@ -62,18 +63,12 @@ static Atom getSupportedAtom(Atom* supportedAtoms,
|
|||||||
//
|
//
|
||||||
static void detectEWMH(void)
|
static void detectEWMH(void)
|
||||||
{
|
{
|
||||||
|
// First we read the _NET_SUPPORTING_WM_CHECK property on the root window
|
||||||
Window* windowFromRoot = NULL;
|
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
|
// Then we look for the _NET_SUPPORTING_WM_CHECK property of the root window
|
||||||
if (!_glfwGetWindowPropertyX11(_glfw.x11.root,
|
if (!_glfwGetWindowPropertyX11(_glfw.x11.root,
|
||||||
supportingWmCheck,
|
_glfw.x11.NET_SUPPORTING_WM_CHECK,
|
||||||
XA_WINDOW,
|
XA_WINDOW,
|
||||||
(unsigned char**) &windowFromRoot))
|
(unsigned char**) &windowFromRoot))
|
||||||
{
|
{
|
||||||
@@ -82,10 +77,12 @@ static void detectEWMH(void)
|
|||||||
|
|
||||||
_glfwGrabErrorHandlerX11();
|
_glfwGrabErrorHandlerX11();
|
||||||
|
|
||||||
// It should be the ID of a child window (of the root)
|
// If it exists, it should be the XID of a top-level window
|
||||||
// Then we look for the same property on the child window
|
// Then we look for the same property on that window
|
||||||
|
|
||||||
|
Window* windowFromChild = NULL;
|
||||||
if (!_glfwGetWindowPropertyX11(*windowFromRoot,
|
if (!_glfwGetWindowPropertyX11(*windowFromRoot,
|
||||||
supportingWmCheck,
|
_glfw.x11.NET_SUPPORTING_WM_CHECK,
|
||||||
XA_WINDOW,
|
XA_WINDOW,
|
||||||
(unsigned char**) &windowFromChild))
|
(unsigned char**) &windowFromChild))
|
||||||
{
|
{
|
||||||
@@ -95,7 +92,7 @@ static void detectEWMH(void)
|
|||||||
|
|
||||||
_glfwReleaseErrorHandlerX11();
|
_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)
|
if (*windowFromRoot != *windowFromChild)
|
||||||
{
|
{
|
||||||
XFree(windowFromRoot);
|
XFree(windowFromRoot);
|
||||||
@@ -107,18 +104,20 @@ static void detectEWMH(void)
|
|||||||
XFree(windowFromChild);
|
XFree(windowFromChild);
|
||||||
|
|
||||||
// We are now fairly sure that an EWMH-compliant window manager is running
|
// 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;
|
Atom* supportedAtoms = NULL;
|
||||||
unsigned long atomCount;
|
const unsigned long atomCount = _glfwGetWindowPropertyX11(_glfw.x11.root,
|
||||||
|
_glfw.x11.NET_SUPPORTED,
|
||||||
// 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,
|
|
||||||
XA_ATOM,
|
XA_ATOM,
|
||||||
(unsigned char**) &supportedAtoms);
|
(unsigned char**) &supportedAtoms);
|
||||||
|
if (!supportedAtoms)
|
||||||
|
return;
|
||||||
|
|
||||||
// See which of the atoms we support that are supported by the WM
|
// See which of the atoms we support that are supported by the WM
|
||||||
|
|
||||||
_glfw.x11.NET_WM_STATE =
|
_glfw.x11.NET_WM_STATE =
|
||||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE");
|
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE");
|
||||||
_glfw.x11.NET_WM_STATE_ABOVE =
|
_glfw.x11.NET_WM_STATE_ABOVE =
|
||||||
@@ -148,8 +147,7 @@ static void detectEWMH(void)
|
|||||||
_glfw.x11.NET_REQUEST_FRAME_EXTENTS =
|
_glfw.x11.NET_REQUEST_FRAME_EXTENTS =
|
||||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_REQUEST_FRAME_EXTENTS");
|
getSupportedAtom(supportedAtoms, atomCount, "_NET_REQUEST_FRAME_EXTENTS");
|
||||||
|
|
||||||
if (supportedAtoms)
|
XFree(supportedAtoms);
|
||||||
XFree(supportedAtoms);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look for and initialize supported X11 extensions
|
// Look for and initialize supported X11 extensions
|
||||||
@@ -159,14 +157,10 @@ static bool initExtensions(void)
|
|||||||
_glfw.x11.vidmode.handle = _glfw_dlopen("libXxf86vm.so.1");
|
_glfw.x11.vidmode.handle = _glfw_dlopen("libXxf86vm.so.1");
|
||||||
if (_glfw.x11.vidmode.handle)
|
if (_glfw.x11.vidmode.handle)
|
||||||
{
|
{
|
||||||
_glfw.x11.vidmode.QueryExtension = (PFN_XF86VidModeQueryExtension)
|
glfw_dlsym(_glfw.x11.vidmode.QueryExtension, _glfw.x11.vidmode.handle, "XF86VidModeQueryExtension");
|
||||||
_glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeQueryExtension");
|
glfw_dlsym(_glfw.x11.vidmode.GetGammaRamp, _glfw.x11.vidmode.handle, "XF86VidModeGetGammaRamp");
|
||||||
_glfw.x11.vidmode.GetGammaRamp = (PFN_XF86VidModeGetGammaRamp)
|
glfw_dlsym(_glfw.x11.vidmode.SetGammaRamp, _glfw.x11.vidmode.handle, "XF86VidModeSetGammaRamp");
|
||||||
_glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRamp");
|
glfw_dlsym(_glfw.x11.vidmode.GetGammaRampSize, _glfw.x11.vidmode.handle, "XF86VidModeGetGammaRampSize");
|
||||||
_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.x11.vidmode.available =
|
_glfw.x11.vidmode.available =
|
||||||
XF86VidModeQueryExtension(_glfw.x11.display,
|
XF86VidModeQueryExtension(_glfw.x11.display,
|
||||||
@@ -181,10 +175,8 @@ static bool initExtensions(void)
|
|||||||
#endif
|
#endif
|
||||||
if (_glfw.x11.xi.handle)
|
if (_glfw.x11.xi.handle)
|
||||||
{
|
{
|
||||||
_glfw.x11.xi.QueryVersion = (PFN_XIQueryVersion)
|
glfw_dlsym(_glfw.x11.xi.QueryVersion, _glfw.x11.xi.handle, "XIQueryVersion");
|
||||||
_glfw_dlsym(_glfw.x11.xi.handle, "XIQueryVersion");
|
glfw_dlsym(_glfw.x11.xi.SelectEvents, _glfw.x11.xi.handle, "XISelectEvents");
|
||||||
_glfw.x11.xi.SelectEvents = (PFN_XISelectEvents)
|
|
||||||
_glfw_dlsym(_glfw.x11.xi.handle, "XISelectEvents");
|
|
||||||
|
|
||||||
if (XQueryExtension(_glfw.x11.display,
|
if (XQueryExtension(_glfw.x11.display,
|
||||||
"XInputExtension",
|
"XInputExtension",
|
||||||
@@ -211,42 +203,24 @@ static bool initExtensions(void)
|
|||||||
#endif
|
#endif
|
||||||
if (_glfw.x11.randr.handle)
|
if (_glfw.x11.randr.handle)
|
||||||
{
|
{
|
||||||
_glfw.x11.randr.AllocGamma = (PFN_XRRAllocGamma)
|
glfw_dlsym(_glfw.x11.randr.AllocGamma, _glfw.x11.randr.handle, "XRRAllocGamma");
|
||||||
_glfw_dlsym(_glfw.x11.randr.handle, "XRRAllocGamma");
|
glfw_dlsym(_glfw.x11.randr.FreeGamma, _glfw.x11.randr.handle, "XRRFreeGamma");
|
||||||
_glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma)
|
glfw_dlsym(_glfw.x11.randr.FreeCrtcInfo, _glfw.x11.randr.handle, "XRRFreeCrtcInfo");
|
||||||
_glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeGamma");
|
glfw_dlsym(_glfw.x11.randr.FreeGamma, _glfw.x11.randr.handle, "XRRFreeGamma");
|
||||||
_glfw.x11.randr.FreeCrtcInfo = (PFN_XRRFreeCrtcInfo)
|
glfw_dlsym(_glfw.x11.randr.FreeOutputInfo, _glfw.x11.randr.handle, "XRRFreeOutputInfo");
|
||||||
_glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeCrtcInfo");
|
glfw_dlsym(_glfw.x11.randr.FreeScreenResources, _glfw.x11.randr.handle, "XRRFreeScreenResources");
|
||||||
_glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma)
|
glfw_dlsym(_glfw.x11.randr.GetCrtcGamma, _glfw.x11.randr.handle, "XRRGetCrtcGamma");
|
||||||
_glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeGamma");
|
glfw_dlsym(_glfw.x11.randr.GetCrtcGammaSize, _glfw.x11.randr.handle, "XRRGetCrtcGammaSize");
|
||||||
_glfw.x11.randr.FreeOutputInfo = (PFN_XRRFreeOutputInfo)
|
glfw_dlsym(_glfw.x11.randr.GetCrtcInfo, _glfw.x11.randr.handle, "XRRGetCrtcInfo");
|
||||||
_glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeOutputInfo");
|
glfw_dlsym(_glfw.x11.randr.GetOutputInfo, _glfw.x11.randr.handle, "XRRGetOutputInfo");
|
||||||
_glfw.x11.randr.FreeScreenResources = (PFN_XRRFreeScreenResources)
|
glfw_dlsym(_glfw.x11.randr.GetOutputPrimary, _glfw.x11.randr.handle, "XRRGetOutputPrimary");
|
||||||
_glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeScreenResources");
|
glfw_dlsym(_glfw.x11.randr.GetScreenResourcesCurrent, _glfw.x11.randr.handle, "XRRGetScreenResourcesCurrent");
|
||||||
_glfw.x11.randr.GetCrtcGamma = (PFN_XRRGetCrtcGamma)
|
glfw_dlsym(_glfw.x11.randr.QueryExtension, _glfw.x11.randr.handle, "XRRQueryExtension");
|
||||||
_glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGamma");
|
glfw_dlsym(_glfw.x11.randr.QueryVersion, _glfw.x11.randr.handle, "XRRQueryVersion");
|
||||||
_glfw.x11.randr.GetCrtcGammaSize = (PFN_XRRGetCrtcGammaSize)
|
glfw_dlsym(_glfw.x11.randr.SelectInput, _glfw.x11.randr.handle, "XRRSelectInput");
|
||||||
_glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGammaSize");
|
glfw_dlsym(_glfw.x11.randr.SetCrtcConfig, _glfw.x11.randr.handle, "XRRSetCrtcConfig");
|
||||||
_glfw.x11.randr.GetCrtcInfo = (PFN_XRRGetCrtcInfo)
|
glfw_dlsym(_glfw.x11.randr.SetCrtcGamma, _glfw.x11.randr.handle, "XRRSetCrtcGamma");
|
||||||
_glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcInfo");
|
glfw_dlsym(_glfw.x11.randr.UpdateConfiguration, _glfw.x11.randr.handle, "XRRUpdateConfiguration");
|
||||||
_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");
|
|
||||||
|
|
||||||
if (XRRQueryExtension(_glfw.x11.display,
|
if (XRRQueryExtension(_glfw.x11.display,
|
||||||
&_glfw.x11.randr.eventBase,
|
&_glfw.x11.randr.eventBase,
|
||||||
@@ -303,12 +277,9 @@ static bool initExtensions(void)
|
|||||||
#endif
|
#endif
|
||||||
if (_glfw.x11.xcursor.handle)
|
if (_glfw.x11.xcursor.handle)
|
||||||
{
|
{
|
||||||
_glfw.x11.xcursor.ImageCreate = (PFN_XcursorImageCreate)
|
glfw_dlsym(_glfw.x11.xcursor.ImageCreate, _glfw.x11.xcursor.handle, "XcursorImageCreate");
|
||||||
_glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageCreate");
|
glfw_dlsym(_glfw.x11.xcursor.ImageDestroy, _glfw.x11.xcursor.handle, "XcursorImageDestroy");
|
||||||
_glfw.x11.xcursor.ImageDestroy = (PFN_XcursorImageDestroy)
|
glfw_dlsym(_glfw.x11.xcursor.ImageLoadCursor, _glfw.x11.xcursor.handle, "XcursorImageLoadCursor");
|
||||||
_glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageDestroy");
|
|
||||||
_glfw.x11.xcursor.ImageLoadCursor = (PFN_XcursorImageLoadCursor)
|
|
||||||
_glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageLoadCursor");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__CYGWIN__)
|
#if defined(__CYGWIN__)
|
||||||
@@ -318,12 +289,9 @@ static bool initExtensions(void)
|
|||||||
#endif
|
#endif
|
||||||
if (_glfw.x11.xinerama.handle)
|
if (_glfw.x11.xinerama.handle)
|
||||||
{
|
{
|
||||||
_glfw.x11.xinerama.IsActive = (PFN_XineramaIsActive)
|
glfw_dlsym(_glfw.x11.xinerama.IsActive, _glfw.x11.xinerama.handle, "XineramaIsActive");
|
||||||
_glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaIsActive");
|
glfw_dlsym(_glfw.x11.xinerama.QueryExtension, _glfw.x11.xinerama.handle, "XineramaQueryExtension");
|
||||||
_glfw.x11.xinerama.QueryExtension = (PFN_XineramaQueryExtension)
|
glfw_dlsym(_glfw.x11.xinerama.QueryScreens, _glfw.x11.xinerama.handle, "XineramaQueryScreens");
|
||||||
_glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaQueryExtension");
|
|
||||||
_glfw.x11.xinerama.QueryScreens = (PFN_XineramaQueryScreens)
|
|
||||||
_glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaQueryScreens");
|
|
||||||
|
|
||||||
if (XineramaQueryExtension(_glfw.x11.display,
|
if (XineramaQueryExtension(_glfw.x11.display,
|
||||||
&_glfw.x11.xinerama.major,
|
&_glfw.x11.xinerama.major,
|
||||||
@@ -341,12 +309,9 @@ static bool initExtensions(void)
|
|||||||
#endif
|
#endif
|
||||||
if (_glfw.x11.xrender.handle)
|
if (_glfw.x11.xrender.handle)
|
||||||
{
|
{
|
||||||
_glfw.x11.xrender.QueryExtension = (PFN_XRenderQueryExtension)
|
glfw_dlsym(_glfw.x11.xrender.QueryExtension, _glfw.x11.xrender.handle, "XRenderQueryExtension");
|
||||||
_glfw_dlsym(_glfw.x11.xrender.handle, "XRenderQueryExtension");
|
glfw_dlsym(_glfw.x11.xrender.QueryVersion, _glfw.x11.xrender.handle, "XRenderQueryVersion");
|
||||||
_glfw.x11.xrender.QueryVersion = (PFN_XRenderQueryVersion)
|
glfw_dlsym(_glfw.x11.xrender.FindVisualFormat, _glfw.x11.xrender.handle, "XRenderFindVisualFormat");
|
||||||
_glfw_dlsym(_glfw.x11.xrender.handle, "XRenderQueryVersion");
|
|
||||||
_glfw.x11.xrender.FindVisualFormat = (PFN_XRenderFindVisualFormat)
|
|
||||||
_glfw_dlsym(_glfw.x11.xrender.handle, "XRenderFindVisualFormat");
|
|
||||||
|
|
||||||
if (XRenderQueryExtension(_glfw.x11.display,
|
if (XRenderQueryExtension(_glfw.x11.display,
|
||||||
&_glfw.x11.xrender.errorBase,
|
&_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_update_x11_keyboard_id(&_glfw.x11.xkb)) return false;
|
||||||
if (!glfw_xkb_compile_keymap(&_glfw.x11.xkb, NULL)) 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
|
// String format atoms
|
||||||
_glfw.x11.NULL_ = XInternAtom(_glfw.x11.display, "NULL", False);
|
_glfw.x11.NULL_ = XInternAtom(_glfw.x11.display, "NULL", False);
|
||||||
_glfw.x11.UTF8_STRING = XInternAtom(_glfw.x11.display, "UTF8_STRING", 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);
|
XInternAtom(_glfw.x11.display, "WM_STATE", False);
|
||||||
_glfw.x11.WM_DELETE_WINDOW =
|
_glfw.x11.WM_DELETE_WINDOW =
|
||||||
XInternAtom(_glfw.x11.display, "WM_DELETE_WINDOW", False);
|
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 =
|
_glfw.x11.NET_WM_ICON =
|
||||||
XInternAtom(_glfw.x11.display, "_NET_WM_ICON", False);
|
XInternAtom(_glfw.x11.display, "_NET_WM_ICON", False);
|
||||||
_glfw.x11.NET_WM_PING =
|
_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);
|
_glfw.x11.NET_WM_CM_Sx = XInternAtom(_glfw.x11.display, name, False);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Detect whether an EWMH-conformant window manager is running
|
||||||
|
detectEWMH();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -536,7 +505,7 @@ static Window createHelperWindow(void)
|
|||||||
|
|
||||||
// X error handler
|
// X error handler
|
||||||
//
|
//
|
||||||
static int errorHandler(Display *display, XErrorEvent* event)
|
static int errorHandler(Display *display UNUSED, XErrorEvent* event)
|
||||||
{
|
{
|
||||||
_glfw.x11.errorCode = event->error_code;
|
_glfw.x11.errorCode = event->error_code;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -611,6 +580,7 @@ Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot)
|
|||||||
return cursor;
|
return cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
////// GLFW platform API //////
|
////// GLFW platform API //////
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
@@ -620,13 +590,6 @@ int _glfwPlatformInit(void)
|
|||||||
XInitThreads();
|
XInitThreads();
|
||||||
XrmInitialize();
|
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);
|
_glfw.x11.display = XOpenDisplay(NULL);
|
||||||
if (!_glfw.x11.display)
|
if (!_glfw.x11.display)
|
||||||
{
|
{
|
||||||
@@ -645,7 +608,10 @@ int _glfwPlatformInit(void)
|
|||||||
return false;
|
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_dbus_init(&_glfw.x11.dbus, &_glfw.x11.eventLoopData);
|
||||||
|
|
||||||
_glfw.x11.screen = DefaultScreen(_glfw.x11.display);
|
_glfw.x11.screen = DefaultScreen(_glfw.x11.display);
|
||||||
@@ -754,7 +720,7 @@ void _glfwPlatformTerminate(void)
|
|||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
_glfwTerminateJoysticksLinux();
|
_glfwTerminateJoysticksLinux();
|
||||||
#endif
|
#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)
|
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
|
// GLFW 3.3 X11 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -24,6 +24,8 @@
|
|||||||
// distribution.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// It is fine to use C99 in this file because it will not be built with VS
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
@@ -54,9 +56,7 @@ static int calculateRefreshRate(const XRRModeInfo* mi)
|
|||||||
//
|
//
|
||||||
static const XRRModeInfo* getModeInfo(const XRRScreenResources* sr, RRMode id)
|
static const XRRModeInfo* getModeInfo(const XRRScreenResources* sr, RRMode id)
|
||||||
{
|
{
|
||||||
int i;
|
for (int i = 0; i < sr->nmode; i++)
|
||||||
|
|
||||||
for (i = 0; i < sr->nmode; i++)
|
|
||||||
{
|
{
|
||||||
if (sr->modes[i].id == id)
|
if (sr->modes[i].id == id)
|
||||||
return sr->modes + i;
|
return sr->modes + i;
|
||||||
@@ -102,7 +102,7 @@ void _glfwPollMonitorsX11(void)
|
|||||||
{
|
{
|
||||||
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
|
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
|
||||||
{
|
{
|
||||||
int i, j, disconnectedCount, screenCount = 0;
|
int disconnectedCount, screenCount = 0;
|
||||||
_GLFWmonitor** disconnected = NULL;
|
_GLFWmonitor** disconnected = NULL;
|
||||||
XineramaScreenInfo* screens = NULL;
|
XineramaScreenInfo* screens = NULL;
|
||||||
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display,
|
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display,
|
||||||
@@ -122,14 +122,11 @@ void _glfwPollMonitorsX11(void)
|
|||||||
_glfw.monitorCount * sizeof(_GLFWmonitor*));
|
_glfw.monitorCount * sizeof(_GLFWmonitor*));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < sr->noutput; i++)
|
for (int i = 0; i < sr->noutput; i++)
|
||||||
{
|
{
|
||||||
int type, widthMM, heightMM;
|
int j, type, widthMM, heightMM;
|
||||||
XRROutputInfo* oi;
|
|
||||||
XRRCrtcInfo* ci;
|
|
||||||
_GLFWmonitor* monitor;
|
|
||||||
|
|
||||||
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)
|
if (oi->connection != RR_Connected || oi->crtc == None)
|
||||||
{
|
{
|
||||||
XRRFreeOutputInfo(oi);
|
XRRFreeOutputInfo(oi);
|
||||||
@@ -152,7 +149,7 @@ void _glfwPollMonitorsX11(void)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, oi->crtc);
|
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, oi->crtc);
|
||||||
if (!ci)
|
if (!ci)
|
||||||
{
|
{
|
||||||
XRRFreeOutputInfo(oi);
|
XRRFreeOutputInfo(oi);
|
||||||
@@ -169,7 +166,7 @@ void _glfwPollMonitorsX11(void)
|
|||||||
heightMM = oi->mm_height;
|
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.output = sr->outputs[i];
|
||||||
monitor->x11.crtc = oi->crtc;
|
monitor->x11.crtc = oi->crtc;
|
||||||
|
|
||||||
@@ -177,8 +174,8 @@ void _glfwPollMonitorsX11(void)
|
|||||||
{
|
{
|
||||||
if (screens[j].x_org == ci->x &&
|
if (screens[j].x_org == ci->x &&
|
||||||
screens[j].y_org == ci->y &&
|
screens[j].y_org == ci->y &&
|
||||||
screens[j].width == ci->width &&
|
screens[j].width == (short int)ci->width &&
|
||||||
screens[j].height == ci->height)
|
screens[j].height == (short int)ci->height)
|
||||||
{
|
{
|
||||||
monitor->x11.index = j;
|
monitor->x11.index = j;
|
||||||
break;
|
break;
|
||||||
@@ -201,7 +198,7 @@ void _glfwPollMonitorsX11(void)
|
|||||||
if (screens)
|
if (screens)
|
||||||
XFree(screens);
|
XFree(screens);
|
||||||
|
|
||||||
for (i = 0; i < disconnectedCount; i++)
|
for (int i = 0; i < disconnectedCount; i++)
|
||||||
{
|
{
|
||||||
if (disconnected[i])
|
if (disconnected[i])
|
||||||
_glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0);
|
_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)
|
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
|
||||||
{
|
{
|
||||||
XRRScreenResources* sr;
|
|
||||||
XRRCrtcInfo* ci;
|
|
||||||
XRROutputInfo* oi;
|
|
||||||
GLFWvidmode current;
|
GLFWvidmode current;
|
||||||
const GLFWvidmode* best;
|
|
||||||
RRMode native = None;
|
RRMode native = None;
|
||||||
int i;
|
|
||||||
|
|
||||||
best = _glfwChooseVideoMode(monitor, desired);
|
const GLFWvidmode* best = _glfwChooseVideoMode(monitor, desired);
|
||||||
_glfwPlatformGetVideoMode(monitor, ¤t);
|
_glfwPlatformGetVideoMode(monitor, ¤t);
|
||||||
if (_glfwCompareVideoModes(¤t, best) == 0)
|
if (_glfwCompareVideoModes(¤t, best) == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
||||||
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
||||||
oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);
|
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]);
|
const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]);
|
||||||
if (!modeIsGood(mi))
|
if (!modeIsGood(mi))
|
||||||
@@ -284,14 +276,11 @@ void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor)
|
|||||||
{
|
{
|
||||||
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
|
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
|
||||||
{
|
{
|
||||||
XRRScreenResources* sr;
|
|
||||||
XRRCrtcInfo* ci;
|
|
||||||
|
|
||||||
if (monitor->x11.oldMode == None)
|
if (monitor->x11.oldMode == None)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
||||||
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
||||||
|
|
||||||
XRRSetCrtcConfig(_glfw.x11.display,
|
XRRSetCrtcConfig(_glfw.x11.display,
|
||||||
sr, monitor->x11.crtc,
|
sr, monitor->x11.crtc,
|
||||||
@@ -314,7 +303,7 @@ void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor)
|
|||||||
////// GLFW platform API //////
|
////// 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)
|
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
|
||||||
{
|
{
|
||||||
XRRScreenResources* sr;
|
|
||||||
XRRCrtcInfo* ci;
|
|
||||||
|
|
||||||
sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
||||||
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
||||||
if (ci)
|
if (ci)
|
||||||
{
|
{
|
||||||
if (xpos)
|
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)
|
float* xscale, float* yscale)
|
||||||
{
|
{
|
||||||
if (xscale)
|
if (xscale)
|
||||||
@@ -349,17 +336,15 @@ void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
|
|||||||
*yscale = _glfw.x11.contentScaleY;
|
*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;
|
int areaX = 0, areaY = 0, areaWidth = 0, areaHeight = 0;
|
||||||
|
|
||||||
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
|
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
|
||||||
{
|
{
|
||||||
XRRScreenResources* sr;
|
|
||||||
XRRCrtcInfo* ci;
|
|
||||||
|
|
||||||
sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
||||||
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
||||||
|
|
||||||
areaX = ci->x;
|
areaX = ci->x;
|
||||||
areaY = ci->y;
|
areaY = ci->y;
|
||||||
@@ -451,24 +436,20 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
|
|||||||
|
|
||||||
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
|
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
|
||||||
{
|
{
|
||||||
int i, j;
|
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
||||||
XRRScreenResources* sr;
|
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
||||||
XRRCrtcInfo* ci;
|
XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);
|
||||||
XRROutputInfo* oi;
|
|
||||||
|
|
||||||
sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
|
||||||
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
|
||||||
oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);
|
|
||||||
|
|
||||||
result = calloc(oi->nmode, sizeof(GLFWvidmode));
|
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]);
|
const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]);
|
||||||
if (!modeIsGood(mi))
|
if (!modeIsGood(mi))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci);
|
const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci);
|
||||||
|
int j;
|
||||||
|
|
||||||
for (j = 0; j < *count; 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)
|
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
|
||||||
{
|
{
|
||||||
XRRScreenResources* sr;
|
|
||||||
XRRCrtcInfo* ci;
|
|
||||||
|
|
||||||
sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
||||||
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
||||||
|
|
||||||
if (ci) {
|
if (ci) {
|
||||||
const XRRModeInfo* mi = getModeInfo(sr, ci->mode);
|
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 (_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,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
"X11: Gamma ramp size must match current ramp size");
|
"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->green,
|
||||||
(unsigned short*) ramp->blue);
|
(unsigned short*) ramp->blue);
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
"X11: Gamma ramp access not supported by server");
|
"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
|
// GLFW 3.3 X11 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -182,11 +182,11 @@ typedef struct _GLFWwindowX11
|
|||||||
Colormap colormap;
|
Colormap colormap;
|
||||||
Window handle;
|
Window handle;
|
||||||
|
|
||||||
bool iconified;
|
bool iconified;
|
||||||
bool maximized;
|
bool maximized;
|
||||||
|
|
||||||
// Whether the visual supports framebuffer transparency
|
// Whether the visual supports framebuffer transparency
|
||||||
bool transparent;
|
bool transparent;
|
||||||
|
|
||||||
// Cached position and size used to filter out duplicate events
|
// Cached position and size used to filter out duplicate events
|
||||||
int width, height;
|
int width, height;
|
||||||
@@ -227,6 +227,8 @@ typedef struct _GLFWlibraryX11
|
|||||||
_GLFWwindow* disabledCursorWindow;
|
_GLFWwindow* disabledCursorWindow;
|
||||||
|
|
||||||
// Window manager atoms
|
// Window manager atoms
|
||||||
|
Atom NET_SUPPORTED;
|
||||||
|
Atom NET_SUPPORTING_WM_CHECK;
|
||||||
Atom WM_PROTOCOLS;
|
Atom WM_PROTOCOLS;
|
||||||
Atom WM_STATE;
|
Atom WM_STATE;
|
||||||
Atom WM_DELETE_WINDOW;
|
Atom WM_DELETE_WINDOW;
|
||||||
@@ -284,14 +286,14 @@ typedef struct _GLFWlibraryX11
|
|||||||
Atom RESOURCE_MANAGER;
|
Atom RESOURCE_MANAGER;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool available;
|
bool available;
|
||||||
void* handle;
|
void* handle;
|
||||||
int eventBase;
|
int eventBase;
|
||||||
int errorBase;
|
int errorBase;
|
||||||
int major;
|
int major;
|
||||||
int minor;
|
int minor;
|
||||||
bool gammaBroken;
|
bool gammaBroken;
|
||||||
bool monitorBroken;
|
bool monitorBroken;
|
||||||
PFN_XRRAllocGamma AllocGamma;
|
PFN_XRRAllocGamma AllocGamma;
|
||||||
PFN_XRRFreeCrtcInfo FreeCrtcInfo;
|
PFN_XRRFreeCrtcInfo FreeCrtcInfo;
|
||||||
PFN_XRRFreeGamma FreeGamma;
|
PFN_XRRFreeGamma FreeGamma;
|
||||||
@@ -336,7 +338,7 @@ typedef struct _GLFWlibraryX11
|
|||||||
} xcursor;
|
} xcursor;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool available;
|
bool available;
|
||||||
void* handle;
|
void* handle;
|
||||||
int major;
|
int major;
|
||||||
int minor;
|
int minor;
|
||||||
@@ -346,7 +348,7 @@ typedef struct _GLFWlibraryX11
|
|||||||
} xinerama;
|
} xinerama;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool available;
|
bool available;
|
||||||
void* handle;
|
void* handle;
|
||||||
int eventBase;
|
int eventBase;
|
||||||
int errorBase;
|
int errorBase;
|
||||||
@@ -357,7 +359,7 @@ typedef struct _GLFWlibraryX11
|
|||||||
} vidmode;
|
} vidmode;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool available;
|
bool available;
|
||||||
void* handle;
|
void* handle;
|
||||||
int majorOpcode;
|
int majorOpcode;
|
||||||
int eventBase;
|
int eventBase;
|
||||||
@@ -369,7 +371,7 @@ typedef struct _GLFWlibraryX11
|
|||||||
} xi;
|
} xi;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool available;
|
bool available;
|
||||||
void* handle;
|
void* handle;
|
||||||
int major;
|
int major;
|
||||||
int minor;
|
int minor;
|
||||||
@@ -406,6 +408,7 @@ typedef struct _GLFWcursorX11
|
|||||||
|
|
||||||
} _GLFWcursorX11;
|
} _GLFWcursorX11;
|
||||||
|
|
||||||
|
|
||||||
void _glfwPollMonitorsX11(void);
|
void _glfwPollMonitorsX11(void);
|
||||||
void _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired);
|
void _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired);
|
||||||
void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor);
|
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
|
// GLFW 3.3 X11 - www.glfw.org
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
// 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
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -24,6 +24,8 @@
|
|||||||
// distribution.
|
// distribution.
|
||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
// It is fine to use C99 in this file because it will not be built with VS
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
@@ -51,6 +53,7 @@
|
|||||||
|
|
||||||
#define _GLFW_XDND_VERSION 5
|
#define _GLFW_XDND_VERSION 5
|
||||||
|
|
||||||
|
|
||||||
// Wait for data to arrive using poll
|
// Wait for data to arrive using poll
|
||||||
// This avoids blocking other threads via the per-display Xlib lock that also
|
// This avoids blocking other threads via the per-display Xlib lock that also
|
||||||
// covers GLX functions
|
// covers GLX functions
|
||||||
@@ -70,6 +73,7 @@ handleEvents(double timeout) {
|
|||||||
glfw_ibus_dispatch(&_glfw.x11.xkb.ibus);
|
glfw_ibus_dispatch(&_glfw.x11.xkb.ibus);
|
||||||
glfw_dbus_session_bus_dispatch();
|
glfw_dbus_session_bus_dispatch();
|
||||||
EVDBG("other dispatch done");
|
EVDBG("other dispatch done");
|
||||||
|
if (_glfw.x11.eventLoopData.wakeup_fd_ready) check_for_wakeup_events(&_glfw.x11.eventLoopData);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@@ -138,7 +142,7 @@ static int getWindowState(_GLFWwindow* window)
|
|||||||
|
|
||||||
// Returns whether the event is a selection event
|
// 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)
|
if (event->xany.window != _glfw.x11.helperWindowHandle)
|
||||||
return False;
|
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
|
// 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;
|
_GLFWwindow* window = (_GLFWwindow*) pointer;
|
||||||
return event->type == PropertyNotify &&
|
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
|
// 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;
|
XEvent* notification = (XEvent*) pointer;
|
||||||
return event->type == PropertyNotify &&
|
return event->type == PropertyNotify &&
|
||||||
@@ -197,10 +201,7 @@ static int translateState(int state)
|
|||||||
static void sendEventToWM(_GLFWwindow* window, Atom type,
|
static void sendEventToWM(_GLFWwindow* window, Atom type,
|
||||||
long a, long b, long c, long d, long e)
|
long a, long b, long c, long d, long e)
|
||||||
{
|
{
|
||||||
XEvent event;
|
XEvent event = { ClientMessage };
|
||||||
memset(&event, 0, sizeof(event));
|
|
||||||
|
|
||||||
event.type = ClientMessage;
|
|
||||||
event.xclient.window = window->x11.handle;
|
event.xclient.window = window->x11.handle;
|
||||||
event.xclient.format = 32; // Data is 32-bit longs
|
event.xclient.format = 32; // Data is 32-bit longs
|
||||||
event.xclient.message_type = type;
|
event.xclient.message_type = type;
|
||||||
@@ -328,8 +329,7 @@ set_fullscreen(_GLFWwindow *window, bool on) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
_glfwPlatformToggleFullscreen(_GLFWwindow *window, unsigned int flags) {
|
_glfwPlatformToggleFullscreen(_GLFWwindow *window, unsigned int flags UNUSED) {
|
||||||
(void) flags;
|
|
||||||
bool already_fullscreen = is_window_fullscreen(window);
|
bool already_fullscreen = is_window_fullscreen(window);
|
||||||
set_fullscreen(window, !already_fullscreen);
|
set_fullscreen(window, !already_fullscreen);
|
||||||
return !already_fullscreen;
|
return !already_fullscreen;
|
||||||
@@ -841,11 +841,8 @@ static void handleSelectionRequest(XEvent* event)
|
|||||||
{
|
{
|
||||||
const XSelectionRequestEvent* request = &event->xselectionrequest;
|
const XSelectionRequestEvent* request = &event->xselectionrequest;
|
||||||
|
|
||||||
XEvent reply;
|
XEvent reply = { SelectionNotify };
|
||||||
memset(&reply, 0, sizeof(reply));
|
|
||||||
|
|
||||||
reply.xselection.property = writeTargetToProperty(request);
|
reply.xselection.property = writeTargetToProperty(request);
|
||||||
reply.xselection.type = SelectionNotify;
|
|
||||||
reply.xselection.display = request->display;
|
reply.xselection.display = request->display;
|
||||||
reply.xselection.requestor = request->requestor;
|
reply.xselection.requestor = request->requestor;
|
||||||
reply.xselection.selection = request->selection;
|
reply.xselection.selection = request->selection;
|
||||||
@@ -857,7 +854,6 @@ static void handleSelectionRequest(XEvent* event)
|
|||||||
|
|
||||||
static const char* getSelectionString(Atom selection)
|
static const char* getSelectionString(Atom selection)
|
||||||
{
|
{
|
||||||
size_t i;
|
|
||||||
char** selectionString = NULL;
|
char** selectionString = NULL;
|
||||||
const Atom targets[] = { _glfw.x11.UTF8_STRING, XA_STRING };
|
const Atom targets[] = { _glfw.x11.UTF8_STRING, XA_STRING };
|
||||||
const size_t targetCount = sizeof(targets) / sizeof(targets[0]);
|
const size_t targetCount = sizeof(targets) / sizeof(targets[0]);
|
||||||
@@ -878,7 +874,7 @@ static const char* getSelectionString(Atom selection)
|
|||||||
free(*selectionString);
|
free(*selectionString);
|
||||||
*selectionString = NULL;
|
*selectionString = NULL;
|
||||||
|
|
||||||
for (i = 0; i < targetCount; i++)
|
for (size_t i = 0; i < targetCount; i++)
|
||||||
{
|
{
|
||||||
char* data;
|
char* data;
|
||||||
Atom actualType;
|
Atom actualType;
|
||||||
@@ -1075,7 +1071,6 @@ static void onConfigChange(void)
|
|||||||
//
|
//
|
||||||
static void processEvent(XEvent *event)
|
static void processEvent(XEvent *event)
|
||||||
{
|
{
|
||||||
_GLFWwindow* window = NULL;
|
|
||||||
static bool keymap_dirty = false;
|
static bool keymap_dirty = false;
|
||||||
#define UPDATE_KEYMAP_IF_NEEDED if (keymap_dirty) { keymap_dirty = false; glfw_xkb_compile_keymap(&_glfw.x11.xkb, NULL); }
|
#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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_GLFWwindow* window = NULL;
|
||||||
if (XFindContext(_glfw.x11.display,
|
if (XFindContext(_glfw.x11.display,
|
||||||
event->xany.window,
|
event->xany.window,
|
||||||
_glfw.x11.context,
|
_glfw.x11.context,
|
||||||
@@ -1487,10 +1483,7 @@ static void processEvent(XEvent *event)
|
|||||||
}
|
}
|
||||||
else if (_glfw.x11.xdnd.version >= 2)
|
else if (_glfw.x11.xdnd.version >= 2)
|
||||||
{
|
{
|
||||||
XEvent reply;
|
XEvent reply = { ClientMessage };
|
||||||
memset(&reply, 0, sizeof(reply));
|
|
||||||
|
|
||||||
reply.type = ClientMessage;
|
|
||||||
reply.xclient.window = _glfw.x11.xdnd.source;
|
reply.xclient.window = _glfw.x11.xdnd.source;
|
||||||
reply.xclient.message_type = _glfw.x11.XdndFinished;
|
reply.xclient.message_type = _glfw.x11.XdndFinished;
|
||||||
reply.xclient.format = 32;
|
reply.xclient.format = 32;
|
||||||
@@ -1523,10 +1516,7 @@ static void processEvent(XEvent *event)
|
|||||||
|
|
||||||
_glfwInputCursorPos(window, xpos, ypos);
|
_glfwInputCursorPos(window, xpos, ypos);
|
||||||
|
|
||||||
XEvent reply;
|
XEvent reply = { ClientMessage };
|
||||||
memset(&reply, 0, sizeof(reply));
|
|
||||||
|
|
||||||
reply.type = ClientMessage;
|
|
||||||
reply.xclient.window = _glfw.x11.xdnd.source;
|
reply.xclient.window = _glfw.x11.xdnd.source;
|
||||||
reply.xclient.message_type = _glfw.x11.XdndStatus;
|
reply.xclient.message_type = _glfw.x11.XdndStatus;
|
||||||
reply.xclient.format = 32;
|
reply.xclient.format = 32;
|
||||||
@@ -1579,10 +1569,7 @@ static void processEvent(XEvent *event)
|
|||||||
|
|
||||||
if (_glfw.x11.xdnd.version >= 2)
|
if (_glfw.x11.xdnd.version >= 2)
|
||||||
{
|
{
|
||||||
XEvent reply;
|
XEvent reply = { ClientMessage };
|
||||||
memset(&reply, 0, sizeof(reply));
|
|
||||||
|
|
||||||
reply.type = ClientMessage;
|
|
||||||
reply.xclient.window = _glfw.x11.xdnd.source;
|
reply.xclient.window = _glfw.x11.xdnd.source;
|
||||||
reply.xclient.message_type = _glfw.x11.XdndFinished;
|
reply.xclient.message_type = _glfw.x11.XdndFinished;
|
||||||
reply.xclient.format = 32;
|
reply.xclient.format = 32;
|
||||||
@@ -1601,9 +1588,6 @@ static void processEvent(XEvent *event)
|
|||||||
|
|
||||||
case FocusIn:
|
case FocusIn:
|
||||||
{
|
{
|
||||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
|
||||||
disableCursor(window);
|
|
||||||
|
|
||||||
if (event->xfocus.mode == NotifyGrab ||
|
if (event->xfocus.mode == NotifyGrab ||
|
||||||
event->xfocus.mode == NotifyUngrab)
|
event->xfocus.mode == NotifyUngrab)
|
||||||
{
|
{
|
||||||
@@ -1612,15 +1596,15 @@ static void processEvent(XEvent *event)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||||
|
disableCursor(window);
|
||||||
|
|
||||||
_glfwInputWindowFocus(window, true);
|
_glfwInputWindowFocus(window, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case FocusOut:
|
case FocusOut:
|
||||||
{
|
{
|
||||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
|
||||||
enableCursor(window);
|
|
||||||
|
|
||||||
if (event->xfocus.mode == NotifyGrab ||
|
if (event->xfocus.mode == NotifyGrab ||
|
||||||
event->xfocus.mode == NotifyUngrab)
|
event->xfocus.mode == NotifyUngrab)
|
||||||
{
|
{
|
||||||
@@ -1629,6 +1613,9 @@ static void processEvent(XEvent *event)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||||
|
enableCursor(window);
|
||||||
|
|
||||||
if (window->monitor && window->autoIconify)
|
if (window->monitor && window->autoIconify)
|
||||||
_glfwPlatformIconifyWindow(window);
|
_glfwPlatformIconifyWindow(window);
|
||||||
|
|
||||||
@@ -2025,8 +2012,8 @@ void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
|
void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
|
||||||
int minwidth, int minheight,
|
int minwidth UNUSED, int minheight UNUSED,
|
||||||
int maxwidth, int maxheight)
|
int maxwidth UNUSED, int maxheight UNUSED)
|
||||||
{
|
{
|
||||||
int width, height;
|
int width, height;
|
||||||
_glfwPlatformGetWindowSize(window, &width, &height);
|
_glfwPlatformGetWindowSize(window, &width, &height);
|
||||||
@@ -2034,7 +2021,7 @@ void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
|
|||||||
XFlush(_glfw.x11.display);
|
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;
|
int width, height;
|
||||||
_glfwPlatformGetWindowSize(window, &width, &height);
|
_glfwPlatformGetWindowSize(window, &width, &height);
|
||||||
@@ -2107,7 +2094,7 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
|||||||
XFree(extents);
|
XFree(extents);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
|
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window UNUSED,
|
||||||
float* xscale, float* yscale)
|
float* xscale, float* yscale)
|
||||||
{
|
{
|
||||||
if (xscale)
|
if (xscale)
|
||||||
@@ -2116,7 +2103,7 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
|
|||||||
*yscale = _glfw.x11.contentScaleY;
|
*yscale = _glfw.x11.contentScaleY;
|
||||||
}
|
}
|
||||||
|
|
||||||
double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window)
|
double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
return 0.5;
|
return 0.5;
|
||||||
}
|
}
|
||||||
@@ -2215,7 +2202,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
|
|||||||
_GLFWmonitor* monitor,
|
_GLFWmonitor* monitor,
|
||||||
int xpos, int ypos,
|
int xpos, int ypos,
|
||||||
int width, int height,
|
int width, int height,
|
||||||
int refreshRate)
|
int refreshRate UNUSED)
|
||||||
{
|
{
|
||||||
if (window->monitor == monitor)
|
if (window->monitor == monitor)
|
||||||
{
|
{
|
||||||
@@ -2245,13 +2232,14 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
|
|||||||
|
|
||||||
if (window->monitor)
|
if (window->monitor)
|
||||||
{
|
{
|
||||||
if (!_glfwPlatformWindowVisible(window))
|
if (!_glfwPlatformWindowVisible(window))
|
||||||
{
|
{
|
||||||
XMapRaised(_glfw.x11.display, window->x11.handle);
|
XMapRaised(_glfw.x11.display, window->x11.handle);
|
||||||
waitForVisibilityNotify(window);
|
waitForVisibilityNotify(window);
|
||||||
}
|
}
|
||||||
updateWindowMode(window);
|
|
||||||
acquireMonitor(window);
|
updateWindowMode(window);
|
||||||
|
acquireMonitor(window);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -2272,7 +2260,7 @@ int _glfwPlatformWindowFocused(_GLFWwindow* window)
|
|||||||
return window->x11.handle == focused;
|
return window->x11.handle == focused;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _glfwPlatformWindowOccluded(_GLFWwindow* window)
|
int _glfwPlatformWindowOccluded(_GLFWwindow* window UNUSED)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2294,10 +2282,13 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window)
|
|||||||
Atom* states;
|
Atom* states;
|
||||||
unsigned long i;
|
unsigned long i;
|
||||||
bool maximized = false;
|
bool maximized = false;
|
||||||
|
|
||||||
if (!_glfw.x11.NET_WM_STATE ||
|
if (!_glfw.x11.NET_WM_STATE ||
|
||||||
!_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT ||
|
!_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT ||
|
||||||
!_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ)
|
!_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ)
|
||||||
|
{
|
||||||
return maximized;
|
return maximized;
|
||||||
|
}
|
||||||
const unsigned long count =
|
const unsigned long count =
|
||||||
_glfwGetWindowPropertyX11(window->x11.handle,
|
_glfwGetWindowPropertyX11(window->x11.handle,
|
||||||
_glfw.x11.NET_WM_STATE,
|
_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;
|
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;
|
int width, height;
|
||||||
_glfwPlatformGetWindowSize(window, &width, &height);
|
_glfwPlatformGetWindowSize(window, &width, &height);
|
||||||
@@ -2485,14 +2476,12 @@ void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned
|
static inline unsigned
|
||||||
dispatch_x11_queued_events(void) {
|
dispatch_x11_queued_events(int num_events) {
|
||||||
unsigned dispatched = 0;
|
unsigned dispatched = num_events > 0 ? num_events : 0;
|
||||||
while (XQLength(_glfw.x11.display) > 0)
|
while (num_events-- > 0) {
|
||||||
{
|
|
||||||
XEvent event;
|
XEvent event;
|
||||||
XNextEvent(_glfw.x11.display, &event);
|
XNextEvent(_glfw.x11.display, &event);
|
||||||
processEvent(&event);
|
processEvent(&event);
|
||||||
dispatched += 1;
|
|
||||||
}
|
}
|
||||||
return dispatched;
|
return dispatched;
|
||||||
}
|
}
|
||||||
@@ -2503,10 +2492,9 @@ _glfwDispatchX11Events(void) {
|
|||||||
unsigned dispatched = 0;
|
unsigned dispatched = 0;
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
_glfwDetectJoystickConnectionLinux();
|
if (_glfw.hints.init.enableJoysticks) _glfwDetectJoystickConnectionLinux();
|
||||||
#endif
|
#endif
|
||||||
XPending(_glfw.x11.display);
|
dispatched += dispatch_x11_queued_events(XEventsQueued(_glfw.x11.display, QueuedAfterFlush));
|
||||||
dispatched += dispatch_x11_queued_events();
|
|
||||||
|
|
||||||
window = _glfw.x11.disabledCursorWindow;
|
window = _glfw.x11.disabledCursorWindow;
|
||||||
if (window)
|
if (window)
|
||||||
@@ -2524,8 +2512,10 @@ _glfwDispatchX11Events(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
XFlush(_glfw.x11.display);
|
XFlush(_glfw.x11.display);
|
||||||
// XFlush can cause events to be queued
|
// XFlush can cause events to be queued, we dont use QueuedAfterFlush here
|
||||||
dispatched += dispatch_x11_queued_events();
|
// 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;
|
return dispatched;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2549,7 +2539,7 @@ void _glfwPlatformWaitEventsTimeout(double timeout)
|
|||||||
|
|
||||||
void _glfwPlatformPostEmptyEvent(void)
|
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)
|
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
|
||||||
@@ -2608,7 +2598,7 @@ int _glfwPlatformGetKeyScancode(int key)
|
|||||||
|
|
||||||
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||||
const GLFWimage* image,
|
const GLFWimage* image,
|
||||||
int xhot, int yhot, int count)
|
int xhot, int yhot, int count UNUSED)
|
||||||
{
|
{
|
||||||
cursor->x11.handle = _glfwCreateCursorX11(image, xhot, yhot);
|
cursor->x11.handle = _glfwCreateCursorX11(image, xhot, yhot);
|
||||||
if (!cursor->x11.handle)
|
if (!cursor->x11.handle)
|
||||||
@@ -2654,7 +2644,7 @@ void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
|
|||||||
XFreeCursor(_glfw.x11.display, cursor->x11.handle);
|
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)
|
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 <stdlib.h>
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "xkb_glfw.h"
|
#include "xkb_glfw.h"
|
||||||
|
START_ALLOW_CASE_RANGE
|
||||||
|
|
||||||
#define debug(...) if (_glfw.hints.init.debugKeyboard) printf(__VA_ARGS__);
|
#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 S(f, t) case XKB_KEY_##f: return GLFW_KEY_##t
|
||||||
#define F(f, t) S(f, 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 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)
|
map_key(key)
|
||||||
S(KP_Up, UP);
|
S(KP_Up, UP);
|
||||||
S(KP_Down, DOWN);
|
S(KP_Down, DOWN);
|
||||||
@@ -115,7 +116,7 @@ glfw_key_for_sym(xkb_keysym_t key) {
|
|||||||
#undef D
|
#undef D
|
||||||
#undef R
|
#undef R
|
||||||
#undef S
|
#undef S
|
||||||
};
|
}
|
||||||
|
|
||||||
xkb_keysym_t
|
xkb_keysym_t
|
||||||
glfw_xkb_sym_for_key(int key) {
|
glfw_xkb_sym_for_key(int key) {
|
||||||
@@ -133,6 +134,7 @@ glfw_xkb_sym_for_key(int key) {
|
|||||||
#undef R
|
#undef R
|
||||||
#undef S
|
#undef S
|
||||||
}
|
}
|
||||||
|
END_ALLOW_CASE_RANGE
|
||||||
|
|
||||||
#ifdef _GLFW_X11
|
#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); \
|
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); \
|
xcb_connection_t* conn = XGetXCBConnection(_glfw.x11.display); \
|
||||||
if (conn) state = xkb_x11_state_new_from_device(keymap, conn, xkb->keyboard_device_id); \
|
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
|
#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_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
|
#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
|
static inline xkb_keysym_t
|
||||||
compose_symbol(struct xkb_compose_state *composeState, xkb_keysym_t sym, int *compose_completed) {
|
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
|
static inline bool
|
||||||
ensure_space(GlobalData *global, size_t sz) {
|
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;
|
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);
|
global->output = realloc(global->output, sizeof(text_t) * global->output_sz);
|
||||||
if (!global->output) {
|
if (!global->output) {
|
||||||
global->output_sz = before;
|
global->output_sz = before;
|
||||||
|
|||||||
@@ -350,7 +350,9 @@ default=(?m)^\s*(.+)\s*$
|
|||||||
The regular expression to use when :option:`kitty +kitten hints --type`=regex.
|
The regular expression to use when :option:`kitty +kitten hints --type`=regex.
|
||||||
If you specify a group in the regular expression only the group
|
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
|
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
|
--url-prefixes
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
import importlib
|
import importlib
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
from contextlib import suppress
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
aliases = {'url_hints': 'hints'}
|
aliases = {'url_hints': 'hints'}
|
||||||
@@ -15,13 +16,18 @@ def resolved_kitten(k):
|
|||||||
return aliases.get(k, k).replace('-', '_')
|
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):
|
def import_kitten_main_module(config_dir, kitten):
|
||||||
if kitten.endswith('.py'):
|
if kitten.endswith('.py'):
|
||||||
path_modified = False
|
path_modified = False
|
||||||
path = os.path.expanduser(kitten)
|
path = path_to_custom_kitten(config_dir, kitten)
|
||||||
if not os.path.isabs(path):
|
|
||||||
path = os.path.join(config_dir, path)
|
|
||||||
path = os.path.abspath(path)
|
|
||||||
if os.path.dirname(path):
|
if os.path.dirname(path):
|
||||||
sys.path.insert(0, os.path.dirname(path))
|
sys.path.insert(0, os.path.dirname(path))
|
||||||
path_modified = True
|
path_modified = True
|
||||||
@@ -90,12 +96,24 @@ def deserialize(output):
|
|||||||
|
|
||||||
def run_kitten(kitten, run_name='__main__'):
|
def run_kitten(kitten, run_name='__main__'):
|
||||||
import runpy
|
import runpy
|
||||||
|
original_kitten_name = kitten
|
||||||
kitten = resolved_kitten(kitten)
|
kitten = resolved_kitten(kitten)
|
||||||
set_debug(kitten)
|
set_debug(kitten)
|
||||||
try:
|
with suppress(ImportError):
|
||||||
runpy.run_module('kittens.{}.main'.format(kitten), run_name=run_name)
|
runpy.run_module('kittens.{}.main'.format(kitten), run_name=run_name)
|
||||||
except ImportError:
|
return
|
||||||
raise SystemExit('No kitten named {}'.format(kitten))
|
# 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():
|
def all_kitten_names():
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import shlex
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@@ -93,6 +94,18 @@ def parse_ssh_args(args):
|
|||||||
return ssh_args, server_args, passthrough
|
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):
|
def main(args):
|
||||||
ssh_args, server_args, passthrough = parse_ssh_args(args[1:])
|
ssh_args, server_args, passthrough = parse_ssh_args(args[1:])
|
||||||
if passthrough:
|
if passthrough:
|
||||||
@@ -101,7 +114,7 @@ def main(args):
|
|||||||
terminfo = subprocess.check_output(['infocmp']).decode('utf-8')
|
terminfo = subprocess.check_output(['infocmp']).decode('utf-8')
|
||||||
sh_script = SHELL_SCRIPT.replace('TERMINFO', terminfo, 1)
|
sh_script = SHELL_SCRIPT.replace('TERMINFO', terminfo, 1)
|
||||||
if len(server_args) > 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)
|
command_to_execute = 'exec ' + ' '.join(command_to_execute)
|
||||||
else:
|
else:
|
||||||
command_to_execute = ''
|
command_to_execute = ''
|
||||||
|
|||||||
@@ -240,11 +240,10 @@ class Table:
|
|||||||
|
|
||||||
|
|
||||||
def is_index(w):
|
def is_index(w):
|
||||||
try:
|
with suppress(Exception):
|
||||||
int(w.lstrip(INDEX_CHAR), 16)
|
int(w.lstrip(INDEX_CHAR), 16)
|
||||||
return True
|
return True
|
||||||
except Exception:
|
return False
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
class UnicodeInput(Handler):
|
class UnicodeInput(Handler):
|
||||||
@@ -295,9 +294,10 @@ class UnicodeInput(Handler):
|
|||||||
self.current_char = None
|
self.current_char = None
|
||||||
if self.mode is HEX:
|
if self.mode is HEX:
|
||||||
with suppress(Exception):
|
with suppress(Exception):
|
||||||
if self.line_edit.current_input.startswith(INDEX_CHAR) and len(self.line_edit.current_input) > 1:
|
if self.line_edit.current_input.startswith(INDEX_CHAR):
|
||||||
self.current_char = chr(self.table.codepoint_at_hint(self.line_edit.current_input[1:]))
|
if len(self.line_edit.current_input) > 1:
|
||||||
else:
|
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)
|
code = int(self.line_edit.current_input, 16)
|
||||||
self.current_char = chr(code)
|
self.current_char = chr(code)
|
||||||
elif self.mode is NAME:
|
elif self.mode is NAME:
|
||||||
@@ -392,19 +392,20 @@ class UnicodeInput(Handler):
|
|||||||
try:
|
try:
|
||||||
val = int(self.line_edit.current_input, 16)
|
val = int(self.line_edit.current_input, 16)
|
||||||
except Exception:
|
except Exception:
|
||||||
return
|
pass
|
||||||
if key_event.key is TAB:
|
else:
|
||||||
self.line_edit.current_input = hex(val + 0x10)[2:]
|
if key_event.key is TAB:
|
||||||
self.refresh()
|
self.line_edit.current_input = hex(val + 0x10)[2:]
|
||||||
return
|
self.refresh()
|
||||||
if key_event.key is UP:
|
return
|
||||||
self.line_edit.current_input = hex(val + 1)[2:]
|
if key_event.key is UP:
|
||||||
self.refresh()
|
self.line_edit.current_input = hex(val + 1)[2:]
|
||||||
return
|
self.refresh()
|
||||||
if key_event.key is DOWN:
|
return
|
||||||
self.line_edit.current_input = hex(val - 1)[2:]
|
if key_event.key is DOWN:
|
||||||
self.refresh()
|
self.line_edit.current_input = hex(val - 1)[2:]
|
||||||
return
|
self.refresh()
|
||||||
|
return
|
||||||
if self.mode is NAME and key_event.type is not RELEASE and not key_event.mods:
|
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.key is TAB:
|
||||||
if key_event.mods == SHIFT:
|
if key_event.mods == SHIFT:
|
||||||
|
|||||||
@@ -7,5 +7,5 @@ out vec4 color;
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
color = texture(image, texcoord);
|
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
|
bw, pw = self.border_width, self.padding_width
|
||||||
if bw + pw <= 0:
|
if bw + pw <= 0:
|
||||||
return
|
return
|
||||||
draw_borders = bw > 0 and draw_window_borders and len(windows) > 1
|
draw_borders = bw > 0 and draw_window_borders
|
||||||
if draw_borders:
|
if draw_borders:
|
||||||
border_data = current_layout.resolve_borders(windows, active_window)
|
border_data = current_layout.resolve_borders(windows, active_window)
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ import atexit
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
from contextlib import suppress
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
from weakref import WeakValueDictionary
|
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 .cli import create_opts, parse_args
|
||||||
from .conf.utils import to_cmdline
|
from .conf.utils import to_cmdline
|
||||||
from .config import initial_window_size_func, prepare_config_file_for_editing
|
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,
|
change_os_window_state, create_os_window, current_os_window,
|
||||||
destroy_global_data, get_clipboard_string, global_font_size,
|
destroy_global_data, get_clipboard_string, global_font_size,
|
||||||
mark_os_window_for_close, os_window_font_size, patch_global_colors,
|
mark_os_window_for_close, os_window_font_size, patch_global_colors,
|
||||||
set_clipboard_string, set_in_sequence_mode, toggle_fullscreen,
|
safe_pipe, set_clipboard_string, set_in_sequence_mode, thread_write,
|
||||||
toggle_maximized
|
toggle_fullscreen, toggle_maximized
|
||||||
)
|
)
|
||||||
from .keys import get_shortcut, shortcut_matches
|
from .keys import get_shortcut, shortcut_matches
|
||||||
from .layout import set_layout_options
|
from .layout import set_layout_options
|
||||||
@@ -846,7 +846,8 @@ class Boss:
|
|||||||
def set_active_tab(self, tab):
|
def set_active_tab(self, tab):
|
||||||
tm = self.active_tab_manager
|
tm = self.active_tab_manager
|
||||||
if tm is not None:
|
if tm is not None:
|
||||||
tm.set_active_tab(tab)
|
return tm.set_active_tab(tab)
|
||||||
|
return False
|
||||||
|
|
||||||
def next_tab(self):
|
def next_tab(self):
|
||||||
tm = self.active_tab_manager
|
tm = self.active_tab_manager
|
||||||
@@ -918,11 +919,22 @@ class Boss:
|
|||||||
else:
|
else:
|
||||||
import subprocess
|
import subprocess
|
||||||
env, stdin = self.process_stdin_source(stdin=source, window=window)
|
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:
|
if stdin:
|
||||||
p = subprocess.Popen(cmd, env=env, stdin=subprocess.PIPE)
|
r, w = safe_pipe(False)
|
||||||
p.communicate(stdin)
|
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:
|
else:
|
||||||
subprocess.Popen(cmd)
|
subprocess.Popen(cmd, env=env, cwd=cwd)
|
||||||
|
|
||||||
def args_to_special_window(self, args, cwd_from=None):
|
def args_to_special_window(self, args, cwd_from=None):
|
||||||
args = list(args)
|
args = list(args)
|
||||||
@@ -977,10 +989,14 @@ class Boss:
|
|||||||
def _new_window(self, args, cwd_from=None):
|
def _new_window(self, args, cwd_from=None):
|
||||||
tab = self.active_tab
|
tab = self.active_tab
|
||||||
if tab is not None:
|
if tab is not None:
|
||||||
|
location = None
|
||||||
|
if args and args[0].startswith('!'):
|
||||||
|
location = args[0][1:].lower()
|
||||||
|
args = args[1:]
|
||||||
if args:
|
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:
|
else:
|
||||||
return tab.new_window(cwd_from=cwd_from)
|
return tab.new_window(cwd_from=cwd_from, location=location)
|
||||||
|
|
||||||
def new_window(self, *args):
|
def new_window(self, *args):
|
||||||
self._new_window(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);
|
float alpha = mix(under_alpha, 1.0f, over_alpha);
|
||||||
return vec4(premul_blend(over, over_alpha, under), 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
|
#ifdef NEEDS_FOREGROUND
|
||||||
vec4 calculate_foreground() {
|
vec4 calculate_foreground() {
|
||||||
|
// returns the effective foreground color in pre-multiplied form
|
||||||
vec4 text_fg = texture(sprites, sprite_pos);
|
vec4 text_fg = texture(sprites, sprite_pos);
|
||||||
vec3 fg = mix(foreground, text_fg.rgb, colored_sprite);
|
vec3 fg = mix(foreground, text_fg.rgb, colored_sprite);
|
||||||
float text_alpha = text_fg.a;
|
float text_alpha = text_fg.a;
|
||||||
@@ -70,15 +108,12 @@ vec4 calculate_foreground() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
#ifdef BACKGROUND
|
#ifdef SIMPLE
|
||||||
|
vec4 fg = calculate_foreground();
|
||||||
#ifdef TRANSPARENT
|
#ifdef TRANSPARENT
|
||||||
// bg_alpha is doubled to match rendering in the SIMPLE case
|
final_color = alpha_blend_premul(fg.rgb, fg.a, background.rgb * bg_alpha, bg_alpha);
|
||||||
// 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);
|
|
||||||
#else
|
#else
|
||||||
final_color = vec4(background.rgb, 1.0f);
|
final_color = blend_onto_opaque_premul(fg.rgb, fg.a, background.rgb);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -90,29 +125,22 @@ void main() {
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(FOREGROUND) || defined(SIMPLE)
|
#ifdef BACKGROUND
|
||||||
// FOREGROUND or SIMPLE
|
#ifdef TRANSPARENT
|
||||||
vec4 fg = calculate_foreground(); // pre-multiplied foreground
|
final_color = vec4(background.rgb * bg_alpha, bg_alpha);
|
||||||
|
#else
|
||||||
|
final_color = vec4(background.rgb, 1.0f);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef FOREGROUND
|
#ifdef FOREGROUND
|
||||||
// FOREGROUND
|
vec4 fg = calculate_foreground(); // pre-multiplied foreground
|
||||||
#ifdef TRANSPARENT
|
#ifdef TRANSPARENT
|
||||||
final_color = fg;
|
final_color = fg;
|
||||||
#else
|
#else
|
||||||
final_color = vec4(fg.rgb / fg.a, fg.a);
|
final_color = vec4(fg.rgb / fg.a, fg.a);
|
||||||
#endif
|
#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
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
* Distributed under terms of the GPL3 license.
|
* Distributed under terms of the GPL3 license.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "loop-utils.h"
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
#include "threading.h"
|
#include "threading.h"
|
||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
@@ -16,10 +17,16 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <signal.h>
|
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <signal.h>
|
||||||
extern PyTypeObject Screen_Type;
|
extern PyTypeObject Screen_Type;
|
||||||
|
|
||||||
|
#ifdef DEBUG_EVENT_LOOP
|
||||||
|
#define EVDBG(...) log_event(__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define EVDBG(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define EXTRA_FDS 2
|
#define EXTRA_FDS 2
|
||||||
#ifndef MSG_NOSIGNAL
|
#ifndef MSG_NOSIGNAL
|
||||||
// Apple does not implement MSG_NOSIGNAL
|
// Apple does not implement MSG_NOSIGNAL
|
||||||
@@ -46,6 +53,7 @@ typedef struct {
|
|||||||
int talk_fd, listen_fd;
|
int talk_fd, listen_fd;
|
||||||
Message *messages;
|
Message *messages;
|
||||||
size_t messages_capacity, messages_count;
|
size_t messages_capacity, messages_count;
|
||||||
|
LoopData io_loop_data;
|
||||||
} ChildMonitor;
|
} ChildMonitor;
|
||||||
|
|
||||||
|
|
||||||
@@ -77,7 +85,6 @@ static pthread_mutex_t children_lock;
|
|||||||
static bool kill_signal_received = false;
|
static bool kill_signal_received = false;
|
||||||
static ChildMonitor *the_monitor = NULL;
|
static ChildMonitor *the_monitor = NULL;
|
||||||
static uint8_t drain_buf[1024];
|
static uint8_t drain_buf[1024];
|
||||||
static int signal_fds[2], wakeup_fds[2];
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -110,39 +117,6 @@ set_maximum_wait(double val) {
|
|||||||
if (val >= 0 && (val < maximum_wait || maximum_wait < 0)) maximum_wait = 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 *
|
static PyObject *
|
||||||
new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
||||||
ChildMonitor *self;
|
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));
|
PyErr_Format(PyExc_RuntimeError, "Failed to create children_lock mutex: %s", strerror(ret));
|
||||||
return NULL;
|
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);
|
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->talk_fd = talk_fd;
|
||||||
self->listen_fd = listen_fd;
|
self->listen_fd = listen_fd;
|
||||||
if (self == NULL) return PyErr_NoMemory();
|
if (self == NULL) return PyErr_NoMemory();
|
||||||
@@ -172,7 +142,7 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
|||||||
parse_func = parse_worker_dump;
|
parse_func = parse_worker_dump;
|
||||||
} else parse_func = parse_worker;
|
} else parse_func = parse_worker;
|
||||||
self->count = 0;
|
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;
|
fds[0].events = POLLIN; fds[1].events = POLLIN;
|
||||||
the_monitor = self;
|
the_monitor = self;
|
||||||
|
|
||||||
@@ -193,22 +163,12 @@ dealloc(ChildMonitor* self) {
|
|||||||
add_queue_count--;
|
add_queue_count--;
|
||||||
FREE_CHILD(add_queue[add_queue_count]);
|
FREE_CHILD(add_queue[add_queue_count]);
|
||||||
}
|
}
|
||||||
close(wakeup_fds[0]);
|
free_loop_data(&self->io_loop_data);
|
||||||
close(wakeup_fds[1]);
|
|
||||||
close(signal_fds[0]);
|
|
||||||
close(signal_fds[1]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
wakeup_io_loop(bool in_signal_handler) {
|
wakeup_io_loop(ChildMonitor *self, bool in_signal_handler) {
|
||||||
while(true) {
|
wakeup_loop(&self->io_loop_data, in_signal_handler);
|
||||||
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* io_loop(void *data);
|
static void* io_loop(void *data);
|
||||||
@@ -231,11 +191,10 @@ start(PyObject *s, PyObject *a UNUSED) {
|
|||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static PyObject *
|
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."
|
#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;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,7 +213,7 @@ add_child(ChildMonitor *self, PyObject *args) {
|
|||||||
INCREF_CHILD(add_queue[add_queue_count]);
|
INCREF_CHILD(add_queue[add_queue_count]);
|
||||||
add_queue_count++;
|
add_queue_count++;
|
||||||
children_mutex(unlock);
|
children_mutex(unlock);
|
||||||
wakeup_io_loop(false);
|
wakeup_io_loop(self, false);
|
||||||
Py_RETURN_NONE;
|
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);
|
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 == 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);
|
screen_mutex(unlock, write);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -323,12 +282,9 @@ needs_write(ChildMonitor UNUSED *self, PyObject *args) {
|
|||||||
static PyObject *
|
static PyObject *
|
||||||
shutdown_monitor(ChildMonitor *self, PyObject *a UNUSED) {
|
shutdown_monitor(ChildMonitor *self, PyObject *a UNUSED) {
|
||||||
#define shutdown_monitor_doc "shutdown_monitor() -> Shutdown the monitor loop."
|
#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;
|
self->shutting_down = true;
|
||||||
wakeup_talk_loop(false);
|
wakeup_talk_loop(false);
|
||||||
wakeup_io_loop(false);
|
wakeup_io_loop(self, false);
|
||||||
int ret = pthread_join(self->io_thread, NULL);
|
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 (ret != 0) return PyErr_Format(PyExc_OSError, "Failed to join() I/O thread with error: %s", strerror(ret));
|
||||||
if (talk_thread_started) {
|
if (talk_thread_started) {
|
||||||
@@ -339,15 +295,17 @@ shutdown_monitor(ChildMonitor *self, PyObject *a UNUSED) {
|
|||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline bool
|
||||||
do_parse(ChildMonitor *self, Screen *screen, double now) {
|
do_parse(ChildMonitor *self, Screen *screen, double now) {
|
||||||
|
bool input_read = false;
|
||||||
screen_mutex(lock, read);
|
screen_mutex(lock, read);
|
||||||
if (screen->read_buf_sz || screen->pending_mode.used) {
|
if (screen->read_buf_sz || screen->pending_mode.used) {
|
||||||
double time_since_new_input = now - screen->new_input_at;
|
double time_since_new_input = now - screen->new_input_at;
|
||||||
if (time_since_new_input >= OPT(input_delay)) {
|
if (time_since_new_input >= OPT(input_delay)) {
|
||||||
bool read_buf_full = screen->read_buf_sz >= READ_BUF_SZ;
|
bool read_buf_full = screen->read_buf_sz >= READ_BUF_SZ;
|
||||||
|
input_read = true;
|
||||||
parse_func(screen, self->dump_callback, now);
|
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;
|
screen->new_input_at = 0;
|
||||||
if (screen->pending_mode.activated_at) {
|
if (screen->pending_mode.activated_at) {
|
||||||
double time_since_pending = MAX(0, now - 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);
|
} else set_maximum_wait(OPT(input_delay) - time_since_new_input);
|
||||||
}
|
}
|
||||||
screen_mutex(unlock, read);
|
screen_mutex(unlock, read);
|
||||||
|
return input_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static bool
|
||||||
parse_input(ChildMonitor *self) {
|
parse_input(ChildMonitor *self) {
|
||||||
// Parse all available input that was read in the I/O thread.
|
// Parse all available input that was read in the I/O thread.
|
||||||
size_t count = 0, remove_count = 0;
|
size_t count = 0, remove_count = 0;
|
||||||
|
bool input_read = false;
|
||||||
double now = monotonic();
|
double now = monotonic();
|
||||||
PyObject *msg = NULL;
|
PyObject *msg = NULL;
|
||||||
children_mutex(lock);
|
children_mutex(lock);
|
||||||
@@ -416,10 +376,11 @@ parse_input(ChildMonitor *self) {
|
|||||||
|
|
||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
if (!scratch[i].needs_removal) {
|
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]);
|
DECREF_CHILD(scratch[i]);
|
||||||
}
|
}
|
||||||
|
return input_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
@@ -432,7 +393,7 @@ mark_child_for_close(ChildMonitor *self, id_type window_id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
children_mutex(unlock);
|
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 INCREF_CHILD
|
||||||
#undef DECREF_CHILD
|
#undef DECREF_CHILD
|
||||||
|
|
||||||
static double last_render_at = -DBL_MAX;
|
extern void cocoa_update_menu_bar_title(PyObject*);
|
||||||
|
|
||||||
extern void cocoa_update_title(PyObject*);
|
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
collect_cursor_info(CursorRenderInfo *ans, Window *w, double now, OSWindow *os_window) {
|
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);
|
Py_INCREF(os_window->window_title);
|
||||||
set_os_window_title(os_window, PyUnicode_AsUTF8(w->title));
|
set_os_window_title(os_window, PyUnicode_AsUTF8(w->title));
|
||||||
#ifdef __APPLE__
|
#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
|
#endif
|
||||||
return true;
|
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
|
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;
|
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);
|
set_maximum_wait(OPT(repaint_delay) - time_since_last_render);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -688,7 +656,7 @@ render(double now) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (USE_RENDER_FRAMES && w->render_state != RENDER_FRAME_READY) {
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
make_os_window_context_current(w);
|
make_os_window_context_current(w);
|
||||||
@@ -723,7 +691,7 @@ typedef struct { int fd; uint8_t *buf; size_t sz; } ThreadWriteData;
|
|||||||
|
|
||||||
static inline ThreadWriteData*
|
static inline ThreadWriteData*
|
||||||
alloc_twd(size_t sz) {
|
alloc_twd(size_t sz) {
|
||||||
ThreadWriteData *data = malloc(sizeof(ThreadWriteData));
|
ThreadWriteData *data = calloc(1, sizeof(ThreadWriteData));
|
||||||
if (data != NULL) {
|
if (data != NULL) {
|
||||||
data->sz = sz;
|
data->sz = sz;
|
||||||
data->buf = malloc(sz);
|
data->buf = malloc(sz);
|
||||||
@@ -771,11 +739,25 @@ static void*
|
|||||||
thread_write(void *x) {
|
thread_write(void *x) {
|
||||||
ThreadWriteData *data = (ThreadWriteData*)x;
|
ThreadWriteData *data = (ThreadWriteData*)x;
|
||||||
set_thread_name("KittyWriteStdin");
|
set_thread_name("KittyWriteStdin");
|
||||||
FILE *f = fdopen(data->fd, "w");
|
int flags = fcntl(data->fd, F_GETFL, 0);
|
||||||
if (fwrite(data->buf, 1, data->sz, f) != data->sz) {
|
if (flags == -1) { free_twd(data); return 0; }
|
||||||
log_error("Failed to write all data");
|
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);
|
free_twd(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -792,7 +774,8 @@ cm_thread_write(PyObject UNUSED *self, PyObject *args) {
|
|||||||
data->fd = fd;
|
data->fd = fd;
|
||||||
memcpy(data->buf, buf, data->sz);
|
memcpy(data->buf, buf, data->sz);
|
||||||
int ret = pthread_create(&thread, NULL, thread_write, data);
|
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;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -913,21 +896,23 @@ static void process_global_state(void *data);
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
do_state_check(id_type timer_id UNUSED, void *data) {
|
do_state_check(id_type timer_id UNUSED, void *data) {
|
||||||
ChildMonitor *self = data;
|
EVDBG("State check timer fired");
|
||||||
process_global_state(self);
|
process_global_state(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static id_type state_check_timer = 0;
|
static id_type state_check_timer = 0;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
process_global_state(void *data) {
|
process_global_state(void *data) {
|
||||||
|
EVDBG("Processing global state");
|
||||||
ChildMonitor *self = data;
|
ChildMonitor *self = data;
|
||||||
maximum_wait = -1;
|
maximum_wait = -1;
|
||||||
bool state_check_timer_enabled = false;
|
bool state_check_timer_enabled = false;
|
||||||
|
|
||||||
double now = monotonic();
|
double now = monotonic();
|
||||||
if (global_state.has_pending_resizes) process_pending_resizes(now);
|
if (global_state.has_pending_resizes) process_pending_resizes(now);
|
||||||
render(now);
|
bool input_read = parse_input(self);
|
||||||
|
render(now, input_read);
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
if (cocoa_pending_actions) {
|
if (cocoa_pending_actions) {
|
||||||
if (cocoa_pending_actions & PREFERENCES_WINDOW) { call_boss(edit_config_file, NULL); }
|
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;
|
cocoa_pending_actions = 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
parse_input(self);
|
|
||||||
if (global_state.terminate) {
|
if (global_state.terminate) {
|
||||||
global_state.terminate = false;
|
global_state.terminate = false;
|
||||||
close_all_windows();
|
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 (global_state.has_pending_closes) has_open_windows = process_pending_closes(self);
|
||||||
if (has_open_windows) {
|
if (has_open_windows) {
|
||||||
if (maximum_wait >= 0) {
|
if (maximum_wait >= 0) {
|
||||||
state_check_timer_enabled = true;
|
if (maximum_wait == 0) request_tick_callback();
|
||||||
|
else state_check_timer_enabled = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
stop_main_loop();
|
stop_main_loop();
|
||||||
@@ -1005,7 +990,7 @@ hangup(pid_t pid) {
|
|||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
cleanup_child(ssize_t i) {
|
cleanup_child(ssize_t i) {
|
||||||
close(children[i].fd);
|
safe_close(children[i].fd);
|
||||||
hangup(children[i].pid);
|
hangup(children[i].pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1074,35 +1059,28 @@ drain_fd(int fd) {
|
|||||||
ssize_t len = read(fd, drain_buf, sizeof(drain_buf));
|
ssize_t len = read(fd, drain_buf, sizeof(drain_buf));
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
if (errno == EINTR) continue;
|
if (errno == EINTR) continue;
|
||||||
if (errno != EIO) perror("Call to read() from drain fd failed");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (len > 0) continue;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
typedef struct { bool kill_signal, child_died; } SignalSet;
|
||||||
read_signals(int fd, bool *kill_signal, bool *child_died) {
|
|
||||||
static char buf[256];
|
static void
|
||||||
while(true) {
|
handle_signal(int signum, void *data) {
|
||||||
ssize_t len = read(fd, buf, sizeof(buf));
|
SignalSet *ss = data;
|
||||||
if (len < 0) {
|
switch(signum) {
|
||||||
if (errno == EINTR) continue;
|
case SIGINT:
|
||||||
if (errno != EIO) perror("Call to read() from read_signals() failed");
|
case SIGTERM:
|
||||||
|
ss->kill_signal = true;
|
||||||
|
break;
|
||||||
|
case SIGCHLD:
|
||||||
|
ss->child_died = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
break;
|
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 (ret > 0) {
|
||||||
if (fds[0].revents && POLLIN) drain_fd(fds[0].fd); // wakeup
|
if (fds[0].revents && POLLIN) drain_fd(fds[0].fd); // wakeup
|
||||||
if (fds[1].revents && POLLIN) {
|
if (fds[1].revents && POLLIN) {
|
||||||
|
SignalSet ss = {0};
|
||||||
data_received = true;
|
data_received = true;
|
||||||
bool kill_signal = false, child_died = false;
|
read_signals(fds[1].fd, handle_signal, &ss);
|
||||||
read_signals(fds[1].fd, &kill_signal, &child_died);
|
if (ss.kill_signal) { children_mutex(lock); kill_signal_received = true; children_mutex(unlock); }
|
||||||
if (kill_signal) { children_mutex(lock); kill_signal_received = true; children_mutex(unlock); }
|
if (ss.child_died) reap_children(self, OPT(close_on_child_death));
|
||||||
if (child_died) reap_children(self, OPT(close_on_child_death));
|
|
||||||
}
|
}
|
||||||
for (i = 0; i < self->count; i++) {
|
for (i = 0; i < self->count; i++) {
|
||||||
if (fds[EXTRA_FDS + i].revents & (POLLIN | POLLHUP)) {
|
if (fds[EXTRA_FDS + i].revents & (POLLIN | POLLHUP)) {
|
||||||
@@ -1296,14 +1274,14 @@ typedef struct {
|
|||||||
PeerReadData *reads;
|
PeerReadData *reads;
|
||||||
PeerWriteData *writes;
|
PeerWriteData *writes;
|
||||||
PeerWriteData *queued_writes;
|
PeerWriteData *queued_writes;
|
||||||
int wakeup_fds[2];
|
LoopData loop_data;
|
||||||
pthread_mutex_t peer_lock;
|
pthread_mutex_t peer_lock;
|
||||||
} TalkData;
|
} TalkData;
|
||||||
|
|
||||||
static TalkData talk_data = {0};
|
static TalkData talk_data = {0};
|
||||||
typedef struct pollfd PollFD;
|
typedef struct pollfd PollFD;
|
||||||
#define PEER_LIMIT 256
|
#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
|
static inline bool
|
||||||
accept_peer(int listen_fd, bool shutting_down) {
|
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->fd == s) {
|
||||||
if (rd->used >= rd->capacity) {
|
if (rd->used >= rd->capacity) {
|
||||||
if (rd->capacity >= 1024 * 1024) failed("Ignoring too large message from peer");
|
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);
|
rd->data = realloc(rd->data, rd->capacity);
|
||||||
if (!rd->data) failed("Out of memory");
|
if (!rd->data) failed("Out of memory");
|
||||||
}
|
}
|
||||||
@@ -1424,7 +1402,7 @@ prune_finished_writes(void) {
|
|||||||
PeerWriteData *wd = talk_data.writes + i;
|
PeerWriteData *wd = talk_data.writes + i;
|
||||||
if (wd->finished) {
|
if (wd->finished) {
|
||||||
remove_poll_fd(wd->fd);
|
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);
|
free(wd->data);
|
||||||
ssize_t num_to_right = talk_data.num_writes - 1 - i;
|
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));
|
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
|
static void
|
||||||
wakeup_talk_loop(bool in_signal_handler) {
|
wakeup_talk_loop(bool in_signal_handler) {
|
||||||
if (talk_data.wakeup_fds[1] <= 0) return;
|
wakeup_loop(&talk_data.loop_data, in_signal_handler);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
@@ -1473,7 +1443,7 @@ talk_loop(void *data) {
|
|||||||
ChildMonitor *self = (ChildMonitor*)data;
|
ChildMonitor *self = (ChildMonitor*)data;
|
||||||
set_thread_name("KittyPeerMon");
|
set_thread_name("KittyPeerMon");
|
||||||
if ((pthread_mutex_init(&talk_data.peer_lock, NULL)) != 0) { perror("Failed to create peer mutex"); return 0; }
|
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);
|
ensure_space_for(&talk_data, fds, PollFD, 8, fds_capacity, 8, false);
|
||||||
#define add_listener(which) \
|
#define add_listener(which) \
|
||||||
if (self->which > -1) { \
|
if (self->which > -1) { \
|
||||||
@@ -1481,7 +1451,7 @@ talk_loop(void *data) {
|
|||||||
}
|
}
|
||||||
add_listener(talk_fd); add_listener(listen_fd);
|
add_listener(talk_fd); add_listener(listen_fd);
|
||||||
#undef add_listener
|
#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)) {
|
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; }
|
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"); }
|
} else if (ret < 0) { if (errno != EAGAIN && errno != EINTR) perror("poll() on talk fds failed"); }
|
||||||
}
|
}
|
||||||
end:
|
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);
|
free(talk_data.fds); free(talk_data.reads); free(talk_data.writes); free(talk_data.queued_writes);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1530,8 +1500,8 @@ add_peer_writer(int fd, const char* msg, size_t msg_sz) {
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
send_response(int fd, const char *msg, size_t msg_sz) {
|
send_response(int fd, const char *msg, size_t msg_sz) {
|
||||||
if (msg == NULL) { shutdown(fd, SHUT_WR); close(fd); return; }
|
if (msg == NULL) { shutdown(fd, SHUT_WR); safe_close(fd); return; }
|
||||||
if (!add_peer_writer(fd, msg, msg_sz)) { shutdown(fd, SHUT_WR); close(fd); }
|
if (!add_peer_writer(fd, msg, msg_sz)) { shutdown(fd, SHUT_WR); safe_close(fd); }
|
||||||
else wakeup_talk_loop(false);
|
else wakeup_talk_loop(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1565,18 +1535,20 @@ PyTypeObject ChildMonitor_Type = {
|
|||||||
|
|
||||||
|
|
||||||
static PyObject*
|
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};
|
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]);
|
return Py_BuildValue("ii", fds[0], fds[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyMethodDef module_methods[] = {
|
static PyMethodDef module_methods[] = {
|
||||||
METHODB(safe_pipe, METH_NOARGS),
|
METHODB(safe_pipe, METH_VARARGS),
|
||||||
{"add_timer", (PyCFunction)add_python_timer, METH_VARARGS, ""},
|
{"add_timer", (PyCFunction)add_python_timer, METH_VARARGS, ""},
|
||||||
{"remove_timer", (PyCFunction)remove_python_timer, METH_VARARGS, ""},
|
{"remove_timer", (PyCFunction)remove_python_timer, METH_VARARGS, ""},
|
||||||
METHODB(monitor_pid, METH_VARARGS),
|
METHODB(monitor_pid, METH_VARARGS),
|
||||||
{"set_iutf8", (PyCFunction)pyset_iutf8, METH_VARARGS, ""},
|
{"set_iutf8_winid", (PyCFunction)pyset_iutf8, METH_VARARGS, ""},
|
||||||
{NULL} /* Sentinel */
|
{NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -78,8 +78,14 @@ spawn(PyObject *self UNUSED, PyObject *args) {
|
|||||||
|
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
switch(pid) {
|
switch(pid) {
|
||||||
case 0:
|
case 0: {
|
||||||
// child
|
// 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)
|
// Use only signal-safe functions (man 7 signal-safety)
|
||||||
if (chdir(cwd) != 0) { if (chdir("/") != 0) {} }; // ignore failure to chdir to /
|
if (chdir(cwd) != 0) { if (chdir("/") != 0) {} }; // ignore failure to chdir to /
|
||||||
if (setsid() == -1) exit_on_err("setsid() in child process failed");
|
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
|
// 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");
|
if (ioctl(tfd, TIOCSCTTY, 0) == -1) exit_on_err("Failed to set controlling terminal with TIOCSCTTY");
|
||||||
#endif
|
#endif
|
||||||
close(tfd);
|
safe_close(tfd);
|
||||||
|
|
||||||
// Redirect stdin/stdout/stderr to the pty
|
// Redirect stdin/stdout/stderr to the pty
|
||||||
if (dup2(slave, 1) == -1) exit_on_err("dup2() failed for fd number 1");
|
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 (dup2(slave, 2) == -1) exit_on_err("dup2() failed for fd number 2");
|
||||||
if (stdin_read_fd > -1) {
|
if (stdin_read_fd > -1) {
|
||||||
if (dup2(stdin_read_fd, 0) == -1) exit_on_err("dup2() failed for fd number 0");
|
if (dup2(stdin_read_fd, 0) == -1) exit_on_err("dup2() failed for fd number 0");
|
||||||
close(stdin_read_fd);
|
safe_close(stdin_read_fd);
|
||||||
close(stdin_write_fd);
|
safe_close(stdin_write_fd);
|
||||||
} else {
|
} else {
|
||||||
if (dup2(slave, 0) == -1) exit_on_err("dup2() failed for fd number 0");
|
if (dup2(slave, 0) == -1) exit_on_err("dup2() failed for fd number 0");
|
||||||
}
|
}
|
||||||
close(slave);
|
safe_close(slave);
|
||||||
close(master);
|
safe_close(master);
|
||||||
|
|
||||||
// Wait for READY_SIGNAL which indicates kitty has setup the screen object
|
// 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);
|
wait_for_terminal_ready(ready_read_fd);
|
||||||
close(ready_read_fd);
|
safe_close(ready_read_fd);
|
||||||
|
|
||||||
// Close any extra fds inherited from parent
|
// 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;
|
environ = env;
|
||||||
// for some reason SIGPIPE is set to SIG_IGN, so reset it, needed by bash,
|
// 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);
|
execlp("sh", "sh", "-c", "read w", NULL);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case -1:
|
case -1:
|
||||||
PyErr_SetFromErrno(PyExc_OSError);
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ class Child:
|
|||||||
self.forked = True
|
self.forked = True
|
||||||
master, slave = os.openpty() # Note that master and slave are in blocking mode
|
master, slave = os.openpty() # Note that master and slave are in blocking mode
|
||||||
remove_cloexec(slave)
|
remove_cloexec(slave)
|
||||||
fast_data_types.set_iutf8(master, True)
|
fast_data_types.set_iutf8_fd(master, True)
|
||||||
stdin, self.stdin = self.stdin, None
|
stdin, self.stdin = self.stdin, None
|
||||||
ready_read_fd, ready_write_fd = os.pipe()
|
ready_read_fd, ready_write_fd = os.pipe()
|
||||||
remove_cloexec(ready_read_fd)
|
remove_cloexec(ready_read_fd)
|
||||||
|
|||||||
@@ -212,6 +212,14 @@ def wrap(text, limit=80):
|
|||||||
return reversed(lines)
|
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 = ('''\
|
default_msg = ('''\
|
||||||
Run the :italic:`{appname}` terminal emulator. You can also specify the :italic:`program`
|
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`.
|
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
|
import sys
|
||||||
from contextlib import suppress
|
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 .config import parse_config, parse_send_text_bytes
|
||||||
from .constants import appname
|
from .constants import appname
|
||||||
from .fast_data_types import focus_os_window
|
from .fast_data_types import focus_os_window
|
||||||
@@ -36,7 +36,33 @@ class UnknownLayout(ValueError):
|
|||||||
cmap = {}
|
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):
|
def w(func):
|
||||||
func.short_desc = short_desc
|
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.no_response = no_response
|
||||||
func.string_return_is_error = string_return_is_error
|
func.string_return_is_error = string_return_is_error
|
||||||
func.args_count = 0 if not argspec else args_count
|
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
|
cmap[func.name] = func
|
||||||
return func
|
return func
|
||||||
return w
|
return w
|
||||||
@@ -109,6 +137,9 @@ def windows_for_payload(boss, window, payload):
|
|||||||
argspec=''
|
argspec=''
|
||||||
)
|
)
|
||||||
def cmd_ls(global_opts, opts, args):
|
def cmd_ls(global_opts, opts, args):
|
||||||
|
'''
|
||||||
|
No payload
|
||||||
|
'''
|
||||||
pass
|
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.
|
this option will cause it to be changed in all OS windows.
|
||||||
''')
|
''')
|
||||||
def cmd_set_font_size(global_opts, opts, args):
|
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:
|
if not args:
|
||||||
raise SystemExit('No font size specified')
|
raise SystemExit('No font size specified')
|
||||||
fs = args[0]
|
fs = args[0]
|
||||||
@@ -143,7 +179,9 @@ def cmd_set_font_size(global_opts, opts, args):
|
|||||||
|
|
||||||
|
|
||||||
def set_font_size(boss, window, payload):
|
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]'
|
argspec='[TEXT TO SEND]'
|
||||||
)
|
)
|
||||||
def cmd_send_text(global_opts, opts, args):
|
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
|
limit = 1024
|
||||||
ret = {'match': opts.match, 'is_binary': False, 'match_tab': opts.match_tab}
|
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):
|
def send_text(boss, window, payload):
|
||||||
windows = [boss.active_window]
|
windows = [boss.active_window]
|
||||||
match = payload['match']
|
pg = cmd_send_text.payload_get
|
||||||
|
match = pg(payload, 'match')
|
||||||
if match:
|
if match:
|
||||||
windows = tuple(boss.match_windows(match))
|
windows = tuple(boss.match_windows(match))
|
||||||
if payload['match_tab']:
|
mt = pg(payload, 'match_tab')
|
||||||
|
if mt:
|
||||||
windows = []
|
windows = []
|
||||||
tabs = tuple(boss.match_tabs(payload['match_tab']))
|
tabs = tuple(boss.match_tabs(mt))
|
||||||
if not tabs:
|
if not tabs:
|
||||||
raise MatchError(payload['match_tab'], 'tabs')
|
raise MatchError(payload['match_tab'], 'tabs')
|
||||||
for tab in tabs:
|
for tab in tabs:
|
||||||
@@ -269,19 +315,25 @@ want to allow other programs to change it afterwards, use this option.
|
|||||||
argspec='TITLE ...'
|
argspec='TITLE ...'
|
||||||
)
|
)
|
||||||
def cmd_set_window_title(global_opts, opts, args):
|
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}
|
return {'title': ' '.join(args), 'match': opts.match, 'temporary': opts.temporary}
|
||||||
|
|
||||||
|
|
||||||
def set_window_title(boss, window, payload):
|
def set_window_title(boss, window, payload):
|
||||||
windows = [window or boss.active_window]
|
windows = [window or boss.active_window]
|
||||||
match = payload['match']
|
pg = cmd_set_window_title.payload_get
|
||||||
|
match = pg(payload, 'match')
|
||||||
if match:
|
if match:
|
||||||
windows = tuple(boss.match_windows(match))
|
windows = tuple(boss.match_windows(match))
|
||||||
if not windows:
|
if not windows:
|
||||||
raise MatchError(match)
|
raise MatchError(match)
|
||||||
for window in windows:
|
for window in windows:
|
||||||
if window:
|
if window:
|
||||||
if payload['temporary']:
|
if pg(payload, 'temporary'):
|
||||||
window.override_title = None
|
window.override_title = None
|
||||||
window.title_changed(payload['title'])
|
window.title_changed(payload['title'])
|
||||||
else:
|
else:
|
||||||
@@ -301,11 +353,16 @@ def set_window_title(boss, window, payload):
|
|||||||
argspec='TITLE ...'
|
argspec='TITLE ...'
|
||||||
)
|
)
|
||||||
def cmd_set_tab_title(global_opts, opts, args):
|
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}
|
return {'title': ' '.join(args), 'match': opts.match}
|
||||||
|
|
||||||
|
|
||||||
def set_tab_title(boss, window, payload):
|
def set_tab_title(boss, window, payload):
|
||||||
match = payload['match']
|
pg = cmd_set_tab_title.payload_get
|
||||||
|
match = pg(payload, 'match')
|
||||||
if match:
|
if match:
|
||||||
tabs = tuple(boss.match_tabs(match))
|
tabs = tuple(boss.match_tabs(match))
|
||||||
if not tabs:
|
if not tabs:
|
||||||
@@ -327,6 +384,10 @@ def set_tab_title(boss, window, payload):
|
|||||||
argspec='LAYOUT_NAME'
|
argspec='LAYOUT_NAME'
|
||||||
)
|
)
|
||||||
def cmd_goto_layout(global_opts, opts, args):
|
def cmd_goto_layout(global_opts, opts, args):
|
||||||
|
'''
|
||||||
|
layout+: The new layout name
|
||||||
|
match: Which tab to change the layout of
|
||||||
|
'''
|
||||||
try:
|
try:
|
||||||
return {'layout': args[0], 'match': opts.match}
|
return {'layout': args[0], 'match': opts.match}
|
||||||
except IndexError:
|
except IndexError:
|
||||||
@@ -334,7 +395,8 @@ def cmd_goto_layout(global_opts, opts, args):
|
|||||||
|
|
||||||
|
|
||||||
def goto_layout(boss, window, payload):
|
def goto_layout(boss, window, payload):
|
||||||
match = payload['match']
|
pg = cmd_goto_layout.payload_get
|
||||||
|
match = pg(payload, 'match')
|
||||||
if match:
|
if match:
|
||||||
if match == 'all':
|
if match == 'all':
|
||||||
tabs = tuple(boss.all_tabs)
|
tabs = tuple(boss.all_tabs)
|
||||||
@@ -361,11 +423,15 @@ def goto_layout(boss, window, payload):
|
|||||||
options_spec=MATCH_TAB_OPTION,
|
options_spec=MATCH_TAB_OPTION,
|
||||||
)
|
)
|
||||||
def cmd_last_used_layout(global_opts, opts, args):
|
def cmd_last_used_layout(global_opts, opts, args):
|
||||||
|
'''
|
||||||
|
match: Which tab to change the layout of
|
||||||
|
'''
|
||||||
return {'match': opts.match}
|
return {'match': opts.match}
|
||||||
|
|
||||||
|
|
||||||
def last_used_layout(boss, window, payload):
|
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:
|
||||||
if match == 'all':
|
if match == 'all':
|
||||||
tabs = tuple(boss.all_tabs)
|
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=''
|
argspec=''
|
||||||
)
|
)
|
||||||
def cmd_close_window(global_opts, opts, args):
|
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}
|
return {'match': opts.match, 'self': opts.self}
|
||||||
|
|
||||||
|
|
||||||
def close_window(boss, window, payload):
|
def close_window(boss, window, payload):
|
||||||
match = payload['match']
|
pg = cmd_close_window.payload_get
|
||||||
|
match = pg(payload, 'match')
|
||||||
if match:
|
if match:
|
||||||
windows = tuple(boss.match_windows(match))
|
windows = tuple(boss.match_windows(match))
|
||||||
if not windows:
|
if not windows:
|
||||||
raise MatchError(match)
|
raise MatchError(match)
|
||||||
else:
|
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:
|
for window in windows:
|
||||||
if window:
|
if window:
|
||||||
boss.close_window(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
|
string_return_is_error=True
|
||||||
)
|
)
|
||||||
def cmd_resize_window(global_opts, opts, args):
|
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}
|
return {'match': opts.match, 'increment': opts.increment, 'axis': opts.axis, 'self': opts.self}
|
||||||
|
|
||||||
|
|
||||||
def resize_window(boss, window, payload):
|
def resize_window(boss, window, payload):
|
||||||
match = payload['match']
|
pg = cmd_resize_window.payload_get
|
||||||
|
match = pg(payload, 'match')
|
||||||
if match:
|
if match:
|
||||||
windows = tuple(boss.match_windows(match))
|
windows = tuple(boss.match_windows(match))
|
||||||
if not windows:
|
if not windows:
|
||||||
raise MatchError(match)
|
raise MatchError(match)
|
||||||
else:
|
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
|
resized = False
|
||||||
if windows and windows[0]:
|
if windows and windows[0]:
|
||||||
resized = boss.resize_layout_window(
|
resized = boss.resize_layout_window(
|
||||||
windows[0], increment=payload['increment'], is_horizontal=payload['axis'] == 'horizontal',
|
windows[0], increment=pg(payload, 'increment'), is_horizontal=pg(payload, 'axis') == 'horizontal',
|
||||||
reset=payload['axis'] == 'reset'
|
reset=pg(payload, 'axis') == 'reset'
|
||||||
)
|
)
|
||||||
return resized
|
return resized
|
||||||
# }}}
|
# }}}
|
||||||
@@ -469,17 +547,22 @@ If specified close the tab this command is run in, rather than the active tab.
|
|||||||
argspec=''
|
argspec=''
|
||||||
)
|
)
|
||||||
def cmd_close_tab(global_opts, opts, args):
|
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}
|
return {'match': opts.match, 'self': opts.self}
|
||||||
|
|
||||||
|
|
||||||
def close_tab(boss, window, payload):
|
def close_tab(boss, window, payload):
|
||||||
match = payload['match']
|
pg = cmd_close_tab.payload_get
|
||||||
|
match = pg(payload, 'match')
|
||||||
if match:
|
if match:
|
||||||
tabs = tuple(boss.match_tabs(match))
|
tabs = tuple(boss.match_tabs(match))
|
||||||
if not tabs:
|
if not tabs:
|
||||||
raise MatchError(match, 'tabs')
|
raise MatchError(match, 'tabs')
|
||||||
else:
|
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:
|
for tab in tabs:
|
||||||
if window:
|
if window:
|
||||||
if tab:
|
if tab:
|
||||||
@@ -537,6 +620,15 @@ the id of the new window will not be printed out.
|
|||||||
argspec='[CMD ...]'
|
argspec='[CMD ...]'
|
||||||
)
|
)
|
||||||
def cmd_new_window(global_opts, opts, args):
|
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:
|
if opts.no_response:
|
||||||
global_opts.no_command_response = True
|
global_opts.no_command_response = True
|
||||||
return {'match': opts.match, 'title': opts.title, 'cwd': opts.cwd,
|
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):
|
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
|
old_window = boss.active_window
|
||||||
if payload['new_tab']:
|
if pg(payload, 'new_tab'):
|
||||||
boss._new_tab(w)
|
boss._new_tab(w)
|
||||||
tab = boss.active_tab
|
tab = boss.active_tab
|
||||||
if payload['tab_title']:
|
if pg(payload, 'tab_title'):
|
||||||
tab.set_title(payload['tab_title'])
|
tab.set_title(pg(payload, 'tab_title'))
|
||||||
wid = boss.active_window.id
|
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)
|
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)
|
boss._new_os_window(w)
|
||||||
wid = boss.active_window.id
|
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)
|
os_window_id = boss.set_active_window(old_window)
|
||||||
if os_window_id:
|
if os_window_id:
|
||||||
focus_os_window(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:
|
if match:
|
||||||
tabs = tuple(boss.match_tabs(match))
|
tabs = tuple(boss.match_tabs(match))
|
||||||
if not tabs:
|
if not tabs:
|
||||||
@@ -576,9 +669,9 @@ def new_window(boss, window, payload):
|
|||||||
tabs = [boss.active_tab]
|
tabs = [boss.active_tab]
|
||||||
tab = tabs[0]
|
tab = tabs[0]
|
||||||
w = tab.new_special_window(w)
|
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)
|
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):
|
def cmd_focus_window(global_opts, opts, args):
|
||||||
|
'''
|
||||||
|
match: The window to focus
|
||||||
|
'''
|
||||||
if opts.no_response:
|
if opts.no_response:
|
||||||
global_opts.no_command_response = True
|
global_opts.no_command_response = True
|
||||||
return {'match': opts.match, 'no_response': opts.no_response}
|
return {'match': opts.match, 'no_response': opts.no_response}
|
||||||
|
|
||||||
|
|
||||||
def focus_window(boss, window, payload):
|
def focus_window(boss, window, payload):
|
||||||
|
pg = cmd_focus_window.payload_get
|
||||||
windows = [window or boss.active_window]
|
windows = [window or boss.active_window]
|
||||||
match = payload['match']
|
match = pg(payload, 'match')
|
||||||
if match:
|
if match:
|
||||||
windows = tuple(boss.match_windows(match))
|
windows = tuple(boss.match_windows(match))
|
||||||
if not windows:
|
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 {{{
|
# focus_tab {{{
|
||||||
@cmd(
|
@cmd(
|
||||||
'Focus the specified tab',
|
'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.
|
using this option means that you will not be notified of failures.
|
||||||
''',
|
''',
|
||||||
argspec='',
|
argspec='',
|
||||||
no_response=True,
|
|
||||||
)
|
)
|
||||||
def cmd_focus_tab(global_opts, opts, args):
|
def cmd_focus_tab(global_opts, opts, args):
|
||||||
|
'''
|
||||||
|
match: The tab to focus
|
||||||
|
'''
|
||||||
if opts.no_response:
|
if opts.no_response:
|
||||||
global_opts.no_command_response = True
|
global_opts.no_command_response = True
|
||||||
return {'match': opts.match}
|
return {'match': opts.match}
|
||||||
|
|
||||||
|
|
||||||
def focus_tab(boss, window, payload):
|
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))
|
tabs = tuple(boss.match_tabs(match))
|
||||||
if not tabs:
|
if not tabs:
|
||||||
raise MatchError(match, '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=''
|
argspec=''
|
||||||
)
|
)
|
||||||
def cmd_get_text(global_opts, opts, args):
|
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}
|
return {'match': opts.match, 'extent': opts.extent, 'ansi': opts.ansi, 'self': opts.self}
|
||||||
|
|
||||||
|
|
||||||
def get_text(boss, window, payload):
|
def get_text(boss, window, payload):
|
||||||
match = payload['match']
|
pg = cmd_get_text.payload_get
|
||||||
|
match = pg(payload, 'match')
|
||||||
if match:
|
if match:
|
||||||
windows = tuple(boss.match_windows(match))
|
windows = tuple(boss.match_windows(match))
|
||||||
if not windows:
|
if not windows:
|
||||||
raise MatchError(match)
|
raise MatchError(match)
|
||||||
else:
|
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]
|
window = windows[0]
|
||||||
if payload['extent'] == 'selection':
|
if pg(payload, 'extent') == 'selection':
|
||||||
ans = window.text_for_selection()
|
ans = window.text_for_selection()
|
||||||
else:
|
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
|
return ans
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
@@ -720,6 +880,15 @@ this option, any color arguments are ignored and --configured and --all are impl
|
|||||||
argspec='COLOR_OR_FILE ...'
|
argspec='COLOR_OR_FILE ...'
|
||||||
)
|
)
|
||||||
def cmd_set_colors(global_opts, opts, args):
|
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
|
from .rgb import color_as_int, Color
|
||||||
colors, cursor_text_color = {}, False
|
colors, cursor_text_color = {}, False
|
||||||
if not opts.reset:
|
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)
|
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)}
|
colors = {k: color_as_int(v) for k, v in colors.items() if isinstance(v, Color)}
|
||||||
return {
|
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,
|
'all': opts.all or opts.reset, 'configured': opts.configured or opts.reset,
|
||||||
'colors': colors, 'reset': opts.reset, 'cursor_text_color': cursor_text_color
|
'colors': colors, 'reset': opts.reset, 'cursor_text_color': cursor_text_color
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def set_colors(boss, window, payload):
|
def set_colors(boss, window, payload):
|
||||||
|
pg = cmd_set_colors.payload_get
|
||||||
from .rgb import color_as_int, Color
|
from .rgb import color_as_int, Color
|
||||||
windows = windows_for_payload(boss, window, payload)
|
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['colors'] = {k: color_as_int(v) for k, v in boss.startup_colors.items()}
|
||||||
payload['cursor_text_color'] = boss.startup_cursor_text_color
|
payload['cursor_text_color'] = boss.startup_cursor_text_color
|
||||||
profiles = tuple(w.screen.color_profile for w in windows)
|
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)
|
cursor_text_color = payload.get('cursor_text_color', False)
|
||||||
if isinstance(cursor_text_color, (tuple, list, Color)):
|
if isinstance(cursor_text_color, (tuple, list, Color)):
|
||||||
cursor_text_color = color_as_int(Color(*cursor_text_color))
|
cursor_text_color = color_as_int(Color(*cursor_text_color))
|
||||||
patch_color_profiles(payload['colors'], cursor_text_color, profiles, payload['configured'])
|
patch_color_profiles(payload['colors'], cursor_text_color, profiles, pg(payload, 'configured'))
|
||||||
boss.patch_colors(payload['colors'], cursor_text_color, payload['configured'])
|
boss.patch_colors(payload['colors'], cursor_text_color, pg(payload, 'configured'))
|
||||||
default_bg_changed = 'background' in payload['colors']
|
default_bg_changed = 'background' in payload['colors']
|
||||||
for w in windows:
|
for w in windows:
|
||||||
if default_bg_changed:
|
if default_bg_changed:
|
||||||
@@ -772,18 +942,23 @@ configured colors.
|
|||||||
''' + '\n\n' + MATCH_WINDOW_OPTION
|
''' + '\n\n' + MATCH_WINDOW_OPTION
|
||||||
)
|
)
|
||||||
def cmd_get_colors(global_opts, opts, args):
|
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}
|
return {'configured': opts.configured, 'match': opts.match}
|
||||||
|
|
||||||
|
|
||||||
def get_colors(boss, window, payload):
|
def get_colors(boss, window, payload):
|
||||||
from .rgb import Color, color_as_sharp, color_from_int
|
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)}
|
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,)
|
windows = (window or boss.active_window,)
|
||||||
if payload['match']:
|
if pg(payload, 'match'):
|
||||||
windows = tuple(boss.match_windows(payload['match']))
|
windows = tuple(boss.match_windows(pg(payload, 'match')))
|
||||||
if not windows:
|
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()})
|
ans.update({k: color_from_int(v) for k, v in windows[0].current_colors.items()})
|
||||||
all_keys = natsort_ints(ans)
|
all_keys = natsort_ints(ans)
|
||||||
maxlen = max(map(len, all_keys))
|
maxlen = max(map(len, all_keys))
|
||||||
@@ -808,24 +983,23 @@ cause colors to be changed in all windows.
|
|||||||
args_count=1
|
args_count=1
|
||||||
)
|
)
|
||||||
def cmd_set_background_opacity(global_opts, opts, args):
|
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))
|
opacity = max(0.1, min(float(args[0]), 1.0))
|
||||||
return {
|
return {
|
||||||
'opacity': opacity, 'match_window': opts.match,
|
'opacity': opacity, 'match_window': opts.match,
|
||||||
'all': opts.all,
|
'all': opts.all, 'match_tab': opts.match_tab
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def set_background_opacity(boss, window, payload):
|
def set_background_opacity(boss, window, payload):
|
||||||
if not boss.opts.dynamic_background_opacity:
|
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')
|
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 = windows_for_payload(payload)
|
||||||
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'])
|
|
||||||
for os_window_id in {w.os_window_id for w in windows}:
|
for os_window_id in {w.os_window_id for w in windows}:
|
||||||
boss._set_os_window_background_opacity(os_window_id, payload['opacity'])
|
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'
|
argspec='STRATEGY'
|
||||||
)
|
)
|
||||||
def cmd_disable_ligatures(global_opts, opts, args):
|
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]
|
strategy = args[0]
|
||||||
if strategy not in ('never', 'always', 'cursor'):
|
if strategy not in ('never', 'always', 'cursor'):
|
||||||
raise ValueError('{} is not a valid disable_ligatures strategy'.format('strategy'))
|
raise ValueError('{} is not a valid disable_ligatures strategy'.format('strategy'))
|
||||||
@@ -872,6 +1052,11 @@ def disable_ligatures(boss, window, payload):
|
|||||||
argspec='kitten_name',
|
argspec='kitten_name',
|
||||||
)
|
)
|
||||||
def cmd_kitten(global_opts, opts, args):
|
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:
|
if len(args) < 1:
|
||||||
raise SystemExit('Must specify kitten name')
|
raise SystemExit('Must specify kitten name')
|
||||||
return {'match': opts.match, 'args': list(args)[1:], 'kitten': args[0]}
|
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):
|
def kitten(boss, window, payload):
|
||||||
windows = [window or boss.active_window]
|
windows = [window or boss.active_window]
|
||||||
match = payload['match']
|
pg = cmd_kitten.payload_get
|
||||||
|
match = pg(payload, 'match')
|
||||||
if match:
|
if match:
|
||||||
windows = tuple(boss.match_windows(match))
|
windows = tuple(boss.match_windows(match))
|
||||||
if not windows:
|
if not windows:
|
||||||
raise MatchError(match)
|
raise MatchError(match)
|
||||||
for window in windows:
|
for window in windows:
|
||||||
if window:
|
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
|
break
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ find_app_name(void) {
|
|||||||
|
|
||||||
for (i = 0; i < sizeof(name_keys) / sizeof(name_keys[0]); i++)
|
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 &&
|
if (name &&
|
||||||
[name isKindOfClass:[NSString class]] &&
|
[name isKindOfClass:[NSString class]] &&
|
||||||
![name isEqualToString:@""])
|
![name isEqualToString:@""])
|
||||||
@@ -60,7 +60,7 @@ find_app_name(void) {
|
|||||||
|
|
||||||
char** progname = _NSGetProgname();
|
char** progname = _NSGetProgname();
|
||||||
if (progname && *progname)
|
if (progname && *progname)
|
||||||
return [NSString stringWithUTF8String:*progname];
|
return @(*progname);
|
||||||
|
|
||||||
// Really shouldn't get here
|
// Really shouldn't get here
|
||||||
return @"kitty";
|
return @"kitty";
|
||||||
@@ -132,7 +132,6 @@ set_notification_activated_callback(PyObject *self UNUSED, PyObject *callback) {
|
|||||||
notification_activated_callback = callback;
|
notification_activated_callback = callback;
|
||||||
Py_INCREF(callback);
|
Py_INCREF(callback);
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@interface NotificationDelegate : NSObject <NSUserNotificationCenterDelegate>
|
@interface NotificationDelegate : NSObject <NSUserNotificationCenterDelegate>
|
||||||
@@ -172,7 +171,7 @@ cocoa_send_notification(PyObject *self UNUSED, PyObject *args) {
|
|||||||
NSUserNotification *n = [NSUserNotification new];
|
NSUserNotification *n = [NSUserNotification new];
|
||||||
NSImage *img = nil;
|
NSImage *img = nil;
|
||||||
if (path_to_image) {
|
if (path_to_image) {
|
||||||
NSString *p = [NSString stringWithUTF8String:path_to_image];
|
NSString *p = @(path_to_image);
|
||||||
NSURL *url = [NSURL fileURLWithPath:p];
|
NSURL *url = [NSURL fileURLWithPath:p];
|
||||||
img = [[NSImage alloc] initWithContentsOfURL:url];
|
img = [[NSImage alloc] initWithContentsOfURL:url];
|
||||||
[url release]; [p release];
|
[url release]; [p release];
|
||||||
@@ -184,14 +183,14 @@ cocoa_send_notification(PyObject *self UNUSED, PyObject *args) {
|
|||||||
}
|
}
|
||||||
#define SET(x) { \
|
#define SET(x) { \
|
||||||
if (x) { \
|
if (x) { \
|
||||||
NSString *t = [NSString stringWithUTF8String:x]; \
|
NSString *t = @(x); \
|
||||||
n.x = t; \
|
n.x = t; \
|
||||||
[t release]; \
|
[t release]; \
|
||||||
}}
|
}}
|
||||||
SET(title); SET(subtitle); SET(informativeText);
|
SET(title); SET(subtitle); SET(informativeText);
|
||||||
#undef SET
|
#undef SET
|
||||||
if (identifier) {
|
if (identifier) {
|
||||||
n.userInfo = @{@"user_id": [NSString stringWithUTF8String:identifier]};
|
n.userInfo = @{@"user_id": @(identifier)};
|
||||||
}
|
}
|
||||||
[center deliverNotification:n];
|
[center deliverNotification:n];
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
@@ -233,6 +232,7 @@ cocoa_send_notification(PyObject *self UNUSED, PyObject *args) {
|
|||||||
void
|
void
|
||||||
cocoa_create_global_menu(void) {
|
cocoa_create_global_menu(void) {
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
|
|
||||||
NSString* app_name = find_app_name();
|
NSString* app_name = find_app_name();
|
||||||
NSMenu* bar = [[NSMenu alloc] init];
|
NSMenu* bar = [[NSMenu alloc] init];
|
||||||
GlobalMenuTarget *global_menu_target = [GlobalMenuTarget shared_instance];
|
GlobalMenuTarget *global_menu_target = [GlobalMenuTarget shared_instance];
|
||||||
@@ -324,11 +324,12 @@ cocoa_create_global_menu(void) {
|
|||||||
|
|
||||||
|
|
||||||
[NSApp setServicesProvider:[[[ServiceProvider alloc] init] autorelease]];
|
[NSApp setServicesProvider:[[[ServiceProvider alloc] init] autorelease]];
|
||||||
}
|
|
||||||
|
} // autoreleasepool
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
cocoa_update_title(PyObject *pytitle) {
|
cocoa_update_menu_bar_title(PyObject *pytitle) {
|
||||||
NSString *title = [[NSString alloc] initWithUTF8String:PyUnicode_AsUTF8(pytitle)];
|
NSString *title = [[NSString alloc] initWithUTF8String:PyUnicode_AsUTF8(pytitle)];
|
||||||
NSMenu *bar = [NSApp mainMenu];
|
NSMenu *bar = [NSApp mainMenu];
|
||||||
if (title_menu != NULL) {
|
if (title_menu != NULL) {
|
||||||
@@ -395,6 +396,7 @@ cocoa_get_workspace_ids(void *w, size_t *workspace_ids, size_t array_sz) {
|
|||||||
static PyObject*
|
static PyObject*
|
||||||
cocoa_get_lang(PyObject UNUSED *self) {
|
cocoa_get_lang(PyObject UNUSED *self) {
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
|
|
||||||
NSString* locale = nil;
|
NSString* locale = nil;
|
||||||
NSString* lang_code = [[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode];
|
NSString* lang_code = [[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode];
|
||||||
NSString* country_code = [[NSLocale currentLocale] objectForKey:NSLocaleCountryCode];
|
NSString* country_code = [[NSLocale currentLocale] objectForKey:NSLocaleCountryCode];
|
||||||
@@ -405,12 +407,14 @@ cocoa_get_lang(PyObject UNUSED *self) {
|
|||||||
}
|
}
|
||||||
if (!locale) { Py_RETURN_NONE; }
|
if (!locale) { Py_RETURN_NONE; }
|
||||||
return Py_BuildValue("s", [locale UTF8String]);
|
return Py_BuildValue("s", [locale UTF8String]);
|
||||||
}
|
|
||||||
|
} // autoreleasepool
|
||||||
}
|
}
|
||||||
|
|
||||||
double
|
double
|
||||||
cocoa_cursor_blink_interval(void) {
|
cocoa_cursor_blink_interval(void) {
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
|
|
||||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
double on_period_ms = [defaults doubleForKey:@"NSTextInsertionPointBlinkPeriodOn"];
|
double on_period_ms = [defaults doubleForKey:@"NSTextInsertionPointBlinkPeriodOn"];
|
||||||
double off_period_ms = [defaults doubleForKey:@"NSTextInsertionPointBlinkPeriodOff"];
|
double off_period_ms = [defaults doubleForKey:@"NSTextInsertionPointBlinkPeriodOff"];
|
||||||
@@ -422,19 +426,21 @@ cocoa_cursor_blink_interval(void) {
|
|||||||
ans = period_ms;
|
ans = period_ms;
|
||||||
}
|
}
|
||||||
return ans > max_value ? 0.0 : ans;
|
return ans > max_value ? 0.0 : ans;
|
||||||
}
|
|
||||||
|
} // autoreleasepool
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
cocoa_set_hide_from_tasks(void) {
|
cocoa_set_activation_policy(bool hide_from_tasks) {
|
||||||
[NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];
|
[NSApp setActivationPolicy:(hide_from_tasks ? NSApplicationActivationPolicyAccessory : NSApplicationActivationPolicyRegular)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
cocoa_set_titlebar_color(void *w, color_type titlebar_color)
|
cocoa_set_titlebar_color(void *w, color_type titlebar_color)
|
||||||
{
|
{
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
NSWindow *window = (NSWindow *)w;
|
|
||||||
|
NSWindow *window = (NSWindow*)w;
|
||||||
|
|
||||||
double red = ((titlebar_color >> 16) & 0xFF) / 255.0;
|
double red = ((titlebar_color >> 16) & 0xFF) / 255.0;
|
||||||
double green = ((titlebar_color >> 8) & 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 {
|
} else {
|
||||||
[window setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameVibrantLight]];
|
[window setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameVibrantLight]];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
} // autoreleasepool
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cleanup() {
|
cleanup() {
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
|
|
||||||
if (dockMenu) [dockMenu release];
|
if (dockMenu) [dockMenu release];
|
||||||
dockMenu = nil;
|
dockMenu = nil;
|
||||||
if (notification_activated_callback) Py_DECREF(notification_activated_callback);
|
if (notification_activated_callback) Py_DECREF(notification_activated_callback);
|
||||||
notification_activated_callback = NULL;
|
notification_activated_callback = NULL;
|
||||||
}
|
|
||||||
|
} // autoreleasepool
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyMethodDef module_methods[] = {
|
static PyMethodDef module_methods[] = {
|
||||||
|
|||||||
@@ -272,7 +272,7 @@ set_configured_colors(ColorProfile *self, PyObject *args) {
|
|||||||
void
|
void
|
||||||
copy_color_table_to_buffer(ColorProfile *self, color_type *buf, int offset, size_t stride) {
|
copy_color_table_to_buffer(ColorProfile *self, color_type *buf, int offset, size_t stride) {
|
||||||
size_t i;
|
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) {
|
for (i = 0, buf = buf + offset; i < sizeof(self->color_table)/sizeof(self->color_table[0]); i++, buf += stride) {
|
||||||
*buf = self->color_table[i];
|
*buf = self->color_table[i];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,25 @@ from .cli import options_for_completion, parse_option_spec
|
|||||||
from .cmds import cmap
|
from .cmds import cmap
|
||||||
from .shell import options_for_cmd
|
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 = {}, {}
|
parsers, serializers = {}, {}
|
||||||
|
|
||||||
|
|
||||||
@@ -131,7 +150,6 @@ def bash_output_serializer(ans):
|
|||||||
lines.append('COMPREPLY+=({})'.format(shlex.quote(word)))
|
lines.append('COMPREPLY+=({})'.format(shlex.quote(word)))
|
||||||
# debug('\n'.join(lines))
|
# debug('\n'.join(lines))
|
||||||
return '\n'.join(lines)
|
return '\n'.join(lines)
|
||||||
# }}}
|
|
||||||
|
|
||||||
|
|
||||||
@output_serializer
|
@output_serializer
|
||||||
@@ -142,6 +160,7 @@ def fish_output_serializer(ans):
|
|||||||
lines.append(shlex.quote(word))
|
lines.append(shlex.quote(word))
|
||||||
# debug('\n'.join(lines))
|
# debug('\n'.join(lines))
|
||||||
return '\n'.join(lines)
|
return '\n'.join(lines)
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
def completions_for_first_word(ans, prefix, entry_points, namespaced_entry_points):
|
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
|
handle_deprecated_hide_window_decorations_aliases.key = True
|
||||||
log_error('The option {} is deprecated. Use hide_window_decorations instead.'.format(key))
|
log_error('The option {} is deprecated. Use hide_window_decorations instead.'.format(key))
|
||||||
if to_bool(val):
|
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):
|
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:
|
if opts.background_opacity < 1.0 and opts.macos_titlebar_color:
|
||||||
log_error('Cannot use both macos_titlebar_color and background_opacity')
|
log_error('Cannot use both macos_titlebar_color and background_opacity')
|
||||||
opts.macos_titlebar_color = 0
|
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
|
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
|
The modifiers to use rectangular selection (i.e. to select text in a
|
||||||
rectangular block with the mouse)'''))
|
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=_('''
|
o('select_by_word_characters', ':@-./_~?&=%+#', long_text=_('''
|
||||||
Characters considered part of a word when double clicking. In addition to these characters
|
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
|
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
|
Set the active window to the window under the mouse when
|
||||||
moving the mouse around'''))
|
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') # {{{
|
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
|
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
|
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
|
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=_('''
|
o('input_delay', 3, option_type=positive_int, long_text=_('''
|
||||||
Delay (in milliseconds) before input from the program running in the terminal
|
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::
|
For example::
|
||||||
|
|
||||||
map ctrl+enter new_window @ some_program
|
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:
|
if is_macos:
|
||||||
k('new_window', 'cmd+enter', 'new_window', _('New window'), add_to_docs=False)
|
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
|
# Scroll the contents of the screen into the scrollback
|
||||||
map kitty_mod+f12 clear_terminal scroll active
|
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
|
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::
|
and clear the screen, instead of just clearing the screen::
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from collections import namedtuple
|
|||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
|
|
||||||
appname = 'kitty'
|
appname = 'kitty'
|
||||||
version = (0, 14, 2)
|
version = (0, 14, 3)
|
||||||
str_version = '.'.join(map(str, version))
|
str_version = '.'.join(map(str, version))
|
||||||
_plat = sys.platform.lower()
|
_plat = sys.platform.lower()
|
||||||
is_macos = 'darwin' in _plat
|
is_macos = 'darwin' in _plat
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
#include "fonts.h"
|
#include "fonts.h"
|
||||||
|
#include "unicode-data.h"
|
||||||
#include <structmember.h>
|
#include <structmember.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
@@ -134,7 +135,7 @@ font_descriptor_from_python(PyObject *src) {
|
|||||||
|
|
||||||
#define SET(x, attr) \
|
#define SET(x, attr) \
|
||||||
t = PyDict_GetItemString(src, #x); \
|
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(family, kCTFontFamilyNameAttribute);
|
||||||
SET(style, kCTFontStyleNameAttribute);
|
SET(style, kCTFontStyleNameAttribute);
|
||||||
@@ -144,23 +145,75 @@ font_descriptor_from_python(PyObject *src) {
|
|||||||
return CTFontDescriptorCreateWithAttributes((CFDictionaryRef) attrs);
|
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*
|
static PyObject*
|
||||||
coretext_all_fonts(PyObject UNUSED *_self) {
|
coretext_all_fonts(PyObject UNUSED *_self) {
|
||||||
static CTFontCollectionRef collection = NULL;
|
CFArrayRef matches = CTFontCollectionCreateMatchingFontDescriptors(all_fonts_collection());
|
||||||
if (collection == NULL) collection = CTFontCollectionCreateFromAvailableFonts(NULL);
|
const CFIndex count = CFArrayGetCount(matches);
|
||||||
NSArray *matches = (NSArray *) CTFontCollectionCreateMatchingFontDescriptors(collection);
|
PyObject *ans = PyTuple_New(count), *temp;
|
||||||
PyObject *ans = PyTuple_New([matches count]), *temp;
|
|
||||||
if (ans == NULL) return PyErr_NoMemory();
|
if (ans == NULL) return PyErr_NoMemory();
|
||||||
for (unsigned int i = 0; i < [matches count]; i++) {
|
for (CFIndex i = 0; i < count; i++) {
|
||||||
temp = font_descriptor_to_python((CTFontDescriptorRef) matches[i]);
|
temp = font_descriptor_to_python((CTFontDescriptorRef) CFArrayGetValueAtIndex(matches, i));
|
||||||
if (temp == NULL) { Py_DECREF(ans); return NULL; }
|
if (temp == NULL) { Py_DECREF(ans); return NULL; }
|
||||||
PyTuple_SET_ITEM(ans, i, temp); temp = NULL;
|
PyTuple_SET_ITEM(ans, i, temp); temp = NULL;
|
||||||
}
|
}
|
||||||
return ans;
|
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
|
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
|
// CTFontCreateForString returns the original font when there are combining
|
||||||
// diacritics in the font and the base character is in the original font,
|
// diacritics in the font and the base character is in the original font,
|
||||||
// so we have to check each character individually
|
// so we have to check each character individually
|
||||||
@@ -171,11 +224,13 @@ find_substitute_face(CFStringRef str, CTFontRef old_font) {
|
|||||||
else start++;
|
else start++;
|
||||||
if (new_font == NULL) { PyErr_SetString(PyExc_ValueError, "Failed to find fallback CTFont"); return NULL; }
|
if (new_font == NULL) { PyErr_SetString(PyExc_ValueError, "Failed to find fallback CTFont"); return NULL; }
|
||||||
if (new_font == old_font) { CFRelease(new_font); continue; }
|
if (new_font == old_font) { CFRelease(new_font); continue; }
|
||||||
CFStringRef name = CTFontCopyPostScriptName(new_font);
|
if (is_last_resort_font(new_font)) {
|
||||||
CFComparisonResult cr = CFStringCompare(name, CFSTR("LastResort"), 0);
|
|
||||||
CFRelease(name);
|
|
||||||
if (cr == kCFCompareEqualTo) {
|
|
||||||
CFRelease(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");
|
PyErr_SetString(PyExc_ValueError, "Failed to find fallback CTFont other than the LastResort font");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -191,11 +246,11 @@ create_fallback_face(PyObject *base_face, CPUCell* cell, bool UNUSED bold, bool
|
|||||||
CTFontRef new_font;
|
CTFontRef new_font;
|
||||||
if (emoji_presentation) new_font = CTFontCreateWithName((CFStringRef)@"AppleColorEmoji", self->scaled_point_sz, NULL);
|
if (emoji_presentation) new_font = CTFontCreateWithName((CFStringRef)@"AppleColorEmoji", self->scaled_point_sz, NULL);
|
||||||
else {
|
else {
|
||||||
char text[256] = {0};
|
char text[64] = {0};
|
||||||
cell_as_utf8_for_fallback(cell, text);
|
cell_as_utf8_for_fallback(cell, text);
|
||||||
CFStringRef str = CFStringCreateWithCString(NULL, text, kCFStringEncodingUTF8);
|
CFStringRef str = CFStringCreateWithCString(NULL, text, kCFStringEncodingUTF8);
|
||||||
if (str == NULL) return PyErr_NoMemory();
|
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);
|
CFRelease(str);
|
||||||
}
|
}
|
||||||
if (new_font == NULL) return NULL;
|
if (new_font == NULL) return NULL;
|
||||||
@@ -205,11 +260,7 @@ create_fallback_face(PyObject *base_face, CPUCell* cell, bool UNUSED bold, bool
|
|||||||
unsigned int
|
unsigned int
|
||||||
glyph_id_for_codepoint(PyObject *s, char_type ch) {
|
glyph_id_for_codepoint(PyObject *s, char_type ch) {
|
||||||
CTFace *self = (CTFace*)s;
|
CTFace *self = (CTFace*)s;
|
||||||
unichar chars[2] = {0};
|
return glyph_id_for_codepoint_ctfont(self->ct_font, ch);
|
||||||
CGGlyph glyphs[2] = {0};
|
|
||||||
int count = CFStringGetSurrogatePairForLongCharacter(ch, chars) ? 2 : 1;
|
|
||||||
CTFontGetGlyphsForCharacters(self->ct_font, chars, glyphs, count);
|
|
||||||
return glyphs[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -274,7 +325,7 @@ cell_metrics(PyObject *s, unsigned int* cell_width, unsigned int* cell_height, u
|
|||||||
if (w > width) width = w;
|
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_position = floor(self->ascent - self->underline_position + 0.5);
|
||||||
*underline_thickness = (unsigned int)ceil(MAX(0.1, self->underline_thickness));
|
*underline_thickness = (unsigned int)ceil(MAX(0.1, self->underline_thickness));
|
||||||
*baseline = (unsigned int)self->ascent;
|
*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);
|
CTFrameGetLineOrigins(test_frame, CFRangeMake(1, 1), &origin2);
|
||||||
CGFloat line_height = origin1.y - origin2.y;
|
CGFloat line_height = origin1.y - origin2.y;
|
||||||
CFRelease(test_frame); CFRelease(path); CFRelease(framesetter);
|
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
|
#undef count
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,6 +387,7 @@ static CGPoint positions[128];
|
|||||||
static void
|
static void
|
||||||
finalize(void) {
|
finalize(void) {
|
||||||
free(render_buf);
|
free(render_buf);
|
||||||
|
if (all_fonts_collection_data) CFRelease(all_fonts_collection_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ START_ALLOW_CASE_RANGE
|
|||||||
case 3:
|
case 3:
|
||||||
self->italic = true; break;
|
self->italic = true; break;
|
||||||
case 4:
|
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;
|
else self->decoration = 1;
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
@@ -161,7 +161,7 @@ apply_sgr_to_cells(GPUCell *first_cell, unsigned int cell_count, unsigned int *p
|
|||||||
case 3:
|
case 3:
|
||||||
SET(ITALIC_SHIFT);
|
SET(ITALIC_SHIFT);
|
||||||
case 4:
|
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); }
|
else { SETM(1, DECORATION_MASK, DECORATION_SHIFT); }
|
||||||
case 7:
|
case 7:
|
||||||
SET(REVERSE_SHIFT);
|
SET(REVERSE_SHIFT);
|
||||||
|
|||||||
@@ -89,7 +89,9 @@ static inline double monotonic_(void) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
double monotonic() { return monotonic_(); }
|
static double start_time = 0;
|
||||||
|
|
||||||
|
double monotonic() { return monotonic_() - start_time; }
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
redirect_std_streams(PyObject UNUSED *self, PyObject *args) {
|
redirect_std_streams(PyObject UNUSED *self, PyObject *args) {
|
||||||
@@ -179,7 +181,7 @@ close_tty(PyObject *self UNUSED, PyObject *args) {
|
|||||||
TTY_ARGS
|
TTY_ARGS
|
||||||
tcsetattr(fd, TCSAFLUSH, termios_p); // deliberately ignore failure
|
tcsetattr(fd, TCSAFLUSH, termios_p); // deliberately ignore failure
|
||||||
free(termios_p);
|
free(termios_p);
|
||||||
close(fd);
|
safe_close(fd);
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,7 +192,7 @@ static PyMethodDef module_methods[] = {
|
|||||||
{"normal_tty", normal_tty, METH_VARARGS, ""},
|
{"normal_tty", normal_tty, METH_VARARGS, ""},
|
||||||
{"raw_tty", raw_tty, METH_VARARGS, ""},
|
{"raw_tty", raw_tty, METH_VARARGS, ""},
|
||||||
{"close_tty", close_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, ""},
|
{"thread_write", (PyCFunction)cm_thread_write, METH_VARARGS, ""},
|
||||||
{"parse_bytes", (PyCFunction)parse_bytes, METH_VARARGS, ""},
|
{"parse_bytes", (PyCFunction)parse_bytes, METH_VARARGS, ""},
|
||||||
{"parse_bytes_dump", (PyCFunction)parse_bytes_dump, METH_VARARGS, ""},
|
{"parse_bytes_dump", (PyCFunction)parse_bytes_dump, METH_VARARGS, ""},
|
||||||
@@ -254,6 +256,7 @@ PyInit_fast_data_types(void) {
|
|||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
mach_timebase_info(&timebase);
|
mach_timebase_info(&timebase);
|
||||||
#endif
|
#endif
|
||||||
|
start_time = monotonic_();
|
||||||
|
|
||||||
if (m != NULL) {
|
if (m != NULL) {
|
||||||
if (!init_logging(m)) return NULL;
|
if (!init_logging(m)) return NULL;
|
||||||
|
|||||||
@@ -22,11 +22,18 @@
|
|||||||
#define EXPORTED __attribute__ ((visibility ("default")))
|
#define EXPORTED __attribute__ ((visibility ("default")))
|
||||||
#define LIKELY(x) __builtin_expect (!!(x), 1)
|
#define LIKELY(x) __builtin_expect (!!(x), 1)
|
||||||
#define UNLIKELY(x) __builtin_expect (!!(x), 0)
|
#define UNLIKELY(x) __builtin_expect (!!(x), 0)
|
||||||
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
|
#define MAX(x, y) __extension__ ({ \
|
||||||
#define MIN(x, y) (((x) > (y)) ? (y) : (x))
|
__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 xstr(s) str(s)
|
||||||
#define str(s) #s
|
#define str(s) #s
|
||||||
#define arraysz(x) (sizeof(x)/sizeof(x[0]))
|
#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)));
|
void log_error(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
|
||||||
#define fatal(...) { log_error(__VA_ARGS__); exit(EXIT_FAILURE); }
|
#define fatal(...) { log_error(__VA_ARGS__); exit(EXIT_FAILURE); }
|
||||||
|
|
||||||
@@ -200,7 +207,6 @@ typedef struct {
|
|||||||
uint8_t decoration;
|
uint8_t decoration;
|
||||||
CursorShape shape;
|
CursorShape shape;
|
||||||
color_type fg, bg, decoration_fg;
|
color_type fg, bg, decoration_fg;
|
||||||
|
|
||||||
} Cursor;
|
} Cursor;
|
||||||
|
|
||||||
typedef struct {
|
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) \
|
#define ensure_space_for(base, array, type, num, capacity, initial_cap, zero_mem) \
|
||||||
if ((base)->capacity < num) { \
|
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); \
|
(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 ((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)); \
|
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 enter_event(void);
|
||||||
void mouse_event(int, int, int);
|
void mouse_event(int, int, int);
|
||||||
void focus_in_event(void);
|
void focus_in_event(void);
|
||||||
void wakeup_io_loop(bool);
|
|
||||||
void scroll_event(double, double, int);
|
void scroll_event(double, double, int);
|
||||||
void fake_scroll(int, bool);
|
void fake_scroll(int, bool);
|
||||||
void set_special_key_combo(int glfw_key, int mods, bool is_native);
|
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 on_key_input(int key, int scancode, int action, int mods, const char*, int);
|
||||||
void request_window_attention(id_type, bool);
|
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 alloc_sprite_map(unsigned int, unsigned int);
|
||||||
SPRITE_MAP_HANDLE free_sprite_map(SPRITE_MAP_HANDLE);
|
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 "data-types.h"
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
#include <canberra.h>
|
||||||
|
|
||||||
#define FUNC(name, restype, ...) typedef restype (*name##_func)(__VA_ARGS__); static name##_func name = NULL
|
#define FUNC(name, restype, ...) typedef restype (*name##_func)(__VA_ARGS__); static name##_func name = NULL
|
||||||
#define LOAD_FUNC(handle, name) {\
|
#define LOAD_FUNC(handle, name) {\
|
||||||
@@ -89,9 +90,25 @@ static PyMethodDef module_methods[] = {
|
|||||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
{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
|
static void
|
||||||
finalize(void) {
|
finalize(void) {
|
||||||
if (libsn_handle) dlclose(libsn_handle);
|
if (libsn_handle) dlclose(libsn_handle);
|
||||||
|
libsn_handle = NULL;
|
||||||
|
if (canberra_ctx) ca_context_destroy(canberra_ctx);
|
||||||
|
canberra_ctx = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|||||||
@@ -12,9 +12,9 @@
|
|||||||
#include "unicode-data.h"
|
#include "unicode-data.h"
|
||||||
|
|
||||||
#define MISSING_GLYPH 4
|
#define MISSING_GLYPH 4
|
||||||
#define MAX_NUM_EXTRA_GLYPHS 8
|
#define MAX_NUM_EXTRA_GLYPHS 8u
|
||||||
#define CELLS_IN_CANVAS ((MAX_NUM_EXTRA_GLYPHS + 1) * 3)
|
#define CELLS_IN_CANVAS ((MAX_NUM_EXTRA_GLYPHS + 1u) * 3u)
|
||||||
#define MAX_NUM_EXTRA_GLYPHS_PUA 4
|
#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*);
|
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;
|
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();
|
add_font_group();
|
||||||
FontGroup *fg = font_groups + num_font_groups - 1;
|
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->font_sz_in_pts = font_sz_in_pts;
|
||||||
fg->logical_dpi_x = logical_dpi_x;
|
fg->logical_dpi_x = logical_dpi_x;
|
||||||
fg->logical_dpi_y = logical_dpi_y;
|
fg->logical_dpi_y = logical_dpi_y;
|
||||||
@@ -196,7 +196,7 @@ sprite_map_set_error(int error) {
|
|||||||
void
|
void
|
||||||
sprite_tracker_set_limits(size_t max_texture_size_, size_t max_array_len_) {
|
sprite_tracker_set_limits(size_t max_texture_size_, size_t max_array_len_) {
|
||||||
max_texture_size = max_texture_size_;
|
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
|
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);
|
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) {
|
if (fg->sprite_tracker.y >= fg->sprite_tracker.max_y) {
|
||||||
fg->sprite_tracker.y = 0; fg->sprite_tracker.z++;
|
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
|
void
|
||||||
clear_sprite_map(Font *font) {
|
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;
|
SpritePosition *s;
|
||||||
for (size_t i = 0; i < sizeof(font->sprite_map)/sizeof(font->sprite_map[0]); i++) {
|
for (size_t i = 0; i < sizeof(font->sprite_map)/sizeof(font->sprite_map[0]); i++) {
|
||||||
s = font->sprite_map + i;
|
s = font->sprite_map + i;
|
||||||
@@ -329,8 +329,8 @@ clear_special_glyph_cache(Font *font) {
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
sprite_tracker_set_layout(GPUSpriteTracker *sprite_tracker, unsigned int cell_width, unsigned int cell_height) {
|
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->xnum = MIN(MAX(1u, max_texture_size / cell_width), (size_t)UINT16_MAX);
|
||||||
sprite_tracker->max_y = MIN(MAX(1, max_texture_size / cell_height), UINT16_MAX);
|
sprite_tracker->max_y = MIN(MAX(1u, max_texture_size / cell_height), (size_t)UINT16_MAX);
|
||||||
sprite_tracker->ynum = 1;
|
sprite_tracker->ynum = 1;
|
||||||
sprite_tracker->x = 0; sprite_tracker->y = 0; sprite_tracker->z = 0;
|
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++) {
|
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];
|
pixel val = d[dc];
|
||||||
uint8_t alpha = s[sc];
|
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;
|
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
|
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) {
|
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];
|
static SpritePosition* sprite_position[16];
|
||||||
@@ -721,7 +716,7 @@ num_codepoints_in_cell(CPUCell *cell) {
|
|||||||
static inline void
|
static inline void
|
||||||
shape(CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, index_type num_cells, hb_font_t *font, bool disable_ligature) {
|
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) {
|
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);
|
group_state.groups = realloc(group_state.groups, sizeof(Group) * group_state.groups_capacity);
|
||||||
if (!group_state.groups) fatal("Out of memory");
|
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.num_codepoints = num_codepoints_in_cell(first_cpu_cell);
|
||||||
group_state.current_cell_data.codepoints_consumed = 0;
|
group_state.current_cell_data.codepoints_consumed = 0;
|
||||||
group_state.current_cell_data.current_codepoint = first_cpu_cell->ch;
|
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.group_idx = 0;
|
||||||
group_state.glyph_idx = 0;
|
group_state.glyph_idx = 0;
|
||||||
group_state.cell_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;
|
uint32_t cluster, next_cluster;
|
||||||
bool add_to_current_group;
|
bool add_to_current_group;
|
||||||
#define G(x) (group_state.x)
|
#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)) {
|
while (G(glyph_idx) < G(num_glyphs) && G(cell_idx) < G(num_cells)) {
|
||||||
glyph_index glyph_id = G(info)[G(glyph_idx)].codepoint;
|
glyph_index glyph_id = G(info)[G(glyph_idx)].codepoint;
|
||||||
cluster = G(info)[G(glyph_idx)].cluster;
|
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)
|
if (is_private_use(cpu_cell->ch)
|
||||||
&& cell_font_idx != BOX_FONT
|
&& cell_font_idx != BOX_FONT
|
||||||
&& cell_font_idx != MISSING_FONT) {
|
&& cell_font_idx != MISSING_FONT) {
|
||||||
int desired_cells = 1;
|
unsigned int desired_cells = 1;
|
||||||
if (cell_font_idx > 0) {
|
if (cell_font_idx > 0) {
|
||||||
Font *font = (fg->fonts + cell_font_idx);
|
Font *font = (fg->fonts + cell_font_idx);
|
||||||
glyph_index glyph_id = glyph_id_for_codepoint(font->face, cpu_cell->ch);
|
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);
|
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 == ' ')
|
while ((line->cpu_cells[i+num_spaces+1].ch == ' ')
|
||||||
&& num_spaces < MAX_NUM_EXTRA_GLYPHS_PUA
|
&& num_spaces < MAX_NUM_EXTRA_GLYPHS_PUA
|
||||||
&& num_spaces < desired_cells
|
&& 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;
|
size_t r;
|
||||||
for (r = 0, src = canvas; r < height; r++, src += width) {
|
for (r = 0, src = canvas; r < height; r++, src += width) {
|
||||||
memmove(src + amt, src, sizeof(pixel) * (width - amt));
|
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
|
static inline unsigned int
|
||||||
calc_cell_height(Face *self, bool for_metrics) {
|
calc_cell_height(Face *self, bool for_metrics) {
|
||||||
unsigned int ans = font_units_to_pixels_y(self, self->height);
|
unsigned int ans = font_units_to_pixels_y(self, self->height);
|
||||||
unsigned int underscore_height = get_height_for_char(self, '_');
|
if (for_metrics) {
|
||||||
if (for_metrics && global_state.debug_font_fallback && underscore_height > ans) {
|
unsigned int underscore_height = get_height_for_char(self, '_');
|
||||||
printf("Increasing cell height by %u pixels to work around buggy font that renders underscore outside the bounding box\n", underscore_height - ans);
|
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
|
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