Start work on migrating to OpenGL based rendering
This commit is contained in:
parent
aa2e11430a
commit
6f81e12041
657
glfw.py
Normal file
657
glfw.py
Normal file
@ -0,0 +1,657 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# GLFW - An OpenGL framework
|
||||
# API version: 3.0.1
|
||||
# WWW: http://www.glfw.org/
|
||||
# ----------------------------------------------------------------------------
|
||||
# Copyright (c) 2002-2006 Marcus Geelnard
|
||||
# Copyright (c) 2006-2010 Camilla Berglund
|
||||
#
|
||||
# Python bindings - Copyright (c) 2013 Nicolas P. Rougier
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# NOTE:
|
||||
# This source has been modified from its original form by the vispy dev team
|
||||
|
||||
import os
|
||||
import ctypes.util
|
||||
from ctypes import (Structure, POINTER, CFUNCTYPE, byref, c_char_p, c_int,
|
||||
c_uint, c_double, c_float, c_ushort)
|
||||
|
||||
|
||||
_glfw_file = None
|
||||
|
||||
# First if there is an environment variable pointing to the library
|
||||
if 'GLFW_LIBRARY' in os.environ:
|
||||
if os.path.exists(os.environ['GLFW_LIBRARY']):
|
||||
_glfw_file = os.path.realpath(os.environ['GLFW_LIBRARY'])
|
||||
|
||||
# Else, try to find it
|
||||
if _glfw_file is None:
|
||||
order = ['glfw', 'glfw3']
|
||||
for check in order:
|
||||
_glfw_file = ctypes.util.find_library(check)
|
||||
if _glfw_file is not None:
|
||||
break
|
||||
|
||||
# Else, we failed and exit
|
||||
if _glfw_file is None:
|
||||
raise OSError('GLFW library not found')
|
||||
|
||||
# Load it
|
||||
_glfw = ctypes.CDLL(_glfw_file)
|
||||
|
||||
|
||||
# Ensure it's new enough
|
||||
def glfwGetVersion():
|
||||
major, minor, rev = c_int(0), c_int(0), c_int(0)
|
||||
_glfw.glfwGetVersion(byref(major), byref(minor), byref(rev))
|
||||
return major.value, minor.value, rev.value
|
||||
|
||||
version = glfwGetVersion()
|
||||
|
||||
if version[0] != 3:
|
||||
version = '.'.join([str(v) for v in version])
|
||||
raise OSError('Need GLFW library version 3, found version %s' % version)
|
||||
|
||||
|
||||
# --- Version -----------------------------------------------------------------
|
||||
GLFW_VERSION_MAJOR = version[0]
|
||||
GLFW_VERSION_MINOR = version[1]
|
||||
GLFW_VERSION_REVISION = version[2]
|
||||
__version__ = GLFW_VERSION_MAJOR, GLFW_VERSION_MINOR, GLFW_VERSION_REVISION
|
||||
|
||||
# --- Input handling definitions ----------------------------------------------
|
||||
GLFW_RELEASE = 0
|
||||
GLFW_PRESS = 1
|
||||
GLFW_REPEAT = 2
|
||||
|
||||
# --- Keys --------------------------------------------------------------------
|
||||
|
||||
# --- The unknown key ---------------------------------------------------------
|
||||
GLFW_KEY_UNKNOWN = -1
|
||||
|
||||
# --- Printable keys ----------------------------------------------------------
|
||||
GLFW_KEY_SPACE = 32
|
||||
GLFW_KEY_APOSTROPHE = 39 # ''
|
||||
GLFW_KEY_COMMA = 44 # ,
|
||||
GLFW_KEY_MINUS = 45 # -
|
||||
GLFW_KEY_PERIOD = 46 # .
|
||||
GLFW_KEY_SLASH = 47 # /
|
||||
GLFW_KEY_0 = 48
|
||||
GLFW_KEY_1 = 49
|
||||
GLFW_KEY_2 = 50
|
||||
GLFW_KEY_3 = 51
|
||||
GLFW_KEY_4 = 52
|
||||
GLFW_KEY_5 = 53
|
||||
GLFW_KEY_6 = 54
|
||||
GLFW_KEY_7 = 55
|
||||
GLFW_KEY_8 = 56
|
||||
GLFW_KEY_9 = 57
|
||||
GLFW_KEY_SEMICOLON = 59 # ;
|
||||
GLFW_KEY_EQUAL = 61 # =
|
||||
GLFW_KEY_A = 65
|
||||
GLFW_KEY_B = 66
|
||||
GLFW_KEY_C = 67
|
||||
GLFW_KEY_D = 68
|
||||
GLFW_KEY_E = 69
|
||||
GLFW_KEY_F = 70
|
||||
GLFW_KEY_G = 71
|
||||
GLFW_KEY_H = 72
|
||||
GLFW_KEY_I = 73
|
||||
GLFW_KEY_J = 74
|
||||
GLFW_KEY_K = 75
|
||||
GLFW_KEY_L = 76
|
||||
GLFW_KEY_M = 77
|
||||
GLFW_KEY_N = 78
|
||||
GLFW_KEY_O = 79
|
||||
GLFW_KEY_P = 80
|
||||
GLFW_KEY_Q = 81
|
||||
GLFW_KEY_R = 82
|
||||
GLFW_KEY_S = 83
|
||||
GLFW_KEY_T = 84
|
||||
GLFW_KEY_U = 85
|
||||
GLFW_KEY_V = 86
|
||||
GLFW_KEY_W = 87
|
||||
GLFW_KEY_X = 88
|
||||
GLFW_KEY_Y = 89
|
||||
GLFW_KEY_Z = 90
|
||||
GLFW_KEY_LEFT_BRACKET = 91 # [
|
||||
GLFW_KEY_BACKSLASH = 92 # \
|
||||
GLFW_KEY_RIGHT_BRACKET = 93 # ]
|
||||
GLFW_KEY_GRAVE_ACCENT = 96 # `
|
||||
GLFW_KEY_WORLD_1 = 161 # non-US #1
|
||||
GLFW_KEY_WORLD_2 = 162 # non-US #2
|
||||
|
||||
# --- Function keys -----------------------------------------------------------
|
||||
GLFW_KEY_ESCAPE = 256
|
||||
GLFW_KEY_ENTER = 257
|
||||
GLFW_KEY_TAB = 258
|
||||
GLFW_KEY_BACKSPACE = 259
|
||||
GLFW_KEY_INSERT = 260
|
||||
GLFW_KEY_DELETE = 261
|
||||
GLFW_KEY_RIGHT = 262
|
||||
GLFW_KEY_LEFT = 263
|
||||
GLFW_KEY_DOWN = 264
|
||||
GLFW_KEY_UP = 265
|
||||
GLFW_KEY_PAGE_UP = 266
|
||||
GLFW_KEY_PAGE_DOWN = 267
|
||||
GLFW_KEY_HOME = 268
|
||||
GLFW_KEY_END = 269
|
||||
GLFW_KEY_CAPS_LOCK = 280
|
||||
GLFW_KEY_SCROLL_LOCK = 281
|
||||
GLFW_KEY_NUM_LOCK = 282
|
||||
GLFW_KEY_PRINT_SCREEN = 283
|
||||
GLFW_KEY_PAUSE = 284
|
||||
GLFW_KEY_F1 = 290
|
||||
GLFW_KEY_F2 = 291
|
||||
GLFW_KEY_F3 = 292
|
||||
GLFW_KEY_F4 = 293
|
||||
GLFW_KEY_F5 = 294
|
||||
GLFW_KEY_F6 = 295
|
||||
GLFW_KEY_F7 = 296
|
||||
GLFW_KEY_F8 = 297
|
||||
GLFW_KEY_F9 = 298
|
||||
GLFW_KEY_F10 = 299
|
||||
GLFW_KEY_F11 = 300
|
||||
GLFW_KEY_F12 = 301
|
||||
GLFW_KEY_F13 = 302
|
||||
GLFW_KEY_F14 = 303
|
||||
GLFW_KEY_F15 = 304
|
||||
GLFW_KEY_F16 = 305
|
||||
GLFW_KEY_F17 = 306
|
||||
GLFW_KEY_F18 = 307
|
||||
GLFW_KEY_F19 = 308
|
||||
GLFW_KEY_F20 = 309
|
||||
GLFW_KEY_F21 = 310
|
||||
GLFW_KEY_F22 = 311
|
||||
GLFW_KEY_F23 = 312
|
||||
GLFW_KEY_F24 = 313
|
||||
GLFW_KEY_F25 = 314
|
||||
GLFW_KEY_KP_0 = 320
|
||||
GLFW_KEY_KP_1 = 321
|
||||
GLFW_KEY_KP_2 = 322
|
||||
GLFW_KEY_KP_3 = 323
|
||||
GLFW_KEY_KP_4 = 324
|
||||
GLFW_KEY_KP_5 = 325
|
||||
GLFW_KEY_KP_6 = 326
|
||||
GLFW_KEY_KP_7 = 327
|
||||
GLFW_KEY_KP_8 = 328
|
||||
GLFW_KEY_KP_9 = 329
|
||||
GLFW_KEY_KP_DECIMAL = 330
|
||||
GLFW_KEY_KP_DIVIDE = 331
|
||||
GLFW_KEY_KP_MULTIPLY = 332
|
||||
GLFW_KEY_KP_SUBTRACT = 333
|
||||
GLFW_KEY_KP_ADD = 334
|
||||
GLFW_KEY_KP_ENTER = 335
|
||||
GLFW_KEY_KP_EQUAL = 336
|
||||
GLFW_KEY_LEFT_SHIFT = 340
|
||||
GLFW_KEY_LEFT_CONTROL = 341
|
||||
GLFW_KEY_LEFT_ALT = 342
|
||||
GLFW_KEY_LEFT_SUPER = 343
|
||||
GLFW_KEY_RIGHT_SHIFT = 344
|
||||
GLFW_KEY_RIGHT_CONTROL = 345
|
||||
GLFW_KEY_RIGHT_ALT = 346
|
||||
GLFW_KEY_RIGHT_SUPER = 347
|
||||
GLFW_KEY_MENU = 348
|
||||
GLFW_KEY_LAST = GLFW_KEY_MENU
|
||||
|
||||
|
||||
# --- Modifiers ---------------------------------------------------------------
|
||||
GLFW_MOD_SHIFT = 0x0001
|
||||
GLFW_MOD_CONTROL = 0x0002
|
||||
GLFW_MOD_ALT = 0x0004
|
||||
GLFW_MOD_SUPER = 0x0008
|
||||
|
||||
# --- Mouse -------------------------------------------------------------------
|
||||
GLFW_MOUSE_BUTTON_1 = 0
|
||||
GLFW_MOUSE_BUTTON_2 = 1
|
||||
GLFW_MOUSE_BUTTON_3 = 2
|
||||
GLFW_MOUSE_BUTTON_4 = 3
|
||||
GLFW_MOUSE_BUTTON_5 = 4
|
||||
GLFW_MOUSE_BUTTON_6 = 5
|
||||
GLFW_MOUSE_BUTTON_7 = 6
|
||||
GLFW_MOUSE_BUTTON_8 = 7
|
||||
GLFW_MOUSE_BUTTON_LAST = GLFW_MOUSE_BUTTON_8
|
||||
GLFW_MOUSE_BUTTON_LEFT = GLFW_MOUSE_BUTTON_1
|
||||
GLFW_MOUSE_BUTTON_RIGHT = GLFW_MOUSE_BUTTON_2
|
||||
GLFW_MOUSE_BUTTON_MIDDLE = GLFW_MOUSE_BUTTON_3
|
||||
|
||||
|
||||
# --- Joystick ----------------------------------------------------------------
|
||||
GLFW_JOYSTICK_1 = 0
|
||||
GLFW_JOYSTICK_2 = 1
|
||||
GLFW_JOYSTICK_3 = 2
|
||||
GLFW_JOYSTICK_4 = 3
|
||||
GLFW_JOYSTICK_5 = 4
|
||||
GLFW_JOYSTICK_6 = 5
|
||||
GLFW_JOYSTICK_7 = 6
|
||||
GLFW_JOYSTICK_8 = 7
|
||||
GLFW_JOYSTICK_9 = 8
|
||||
GLFW_JOYSTICK_10 = 9
|
||||
GLFW_JOYSTICK_11 = 10
|
||||
GLFW_JOYSTICK_12 = 11
|
||||
GLFW_JOYSTICK_13 = 12
|
||||
GLFW_JOYSTICK_14 = 13
|
||||
GLFW_JOYSTICK_15 = 14
|
||||
GLFW_JOYSTICK_16 = 15
|
||||
GLFW_JOYSTICK_LAST = GLFW_JOYSTICK_16
|
||||
|
||||
|
||||
# --- Error codes -------------------------------------------------------------
|
||||
GLFW_NOT_INITIALIZED = 0x00010001
|
||||
GLFW_NO_CURRENT_CONTEXT = 0x00010002
|
||||
GLFW_INVALID_ENUM = 0x00010003
|
||||
GLFW_INVALID_VALUE = 0x00010004
|
||||
GLFW_OUT_OF_MEMORY = 0x00010005
|
||||
GLFW_API_UNAVAILABLE = 0x00010006
|
||||
GLFW_VERSION_UNAVAILABLE = 0x00010007
|
||||
GLFW_PLATFORM_ERROR = 0x00010008
|
||||
GLFW_FORMAT_UNAVAILABLE = 0x00010009
|
||||
|
||||
# ---
|
||||
GLFW_FOCUSED = 0x00020001
|
||||
GLFW_ICONIFIED = 0x00020002
|
||||
GLFW_RESIZABLE = 0x00020003
|
||||
GLFW_VISIBLE = 0x00020004
|
||||
GLFW_DECORATED = 0x00020005
|
||||
GLFW_AUTO_ICONIFY = 0x00020006
|
||||
GLFW_FLOATING = 0x00020007
|
||||
|
||||
# ---
|
||||
GLFW_RED_BITS = 0x00021001
|
||||
GLFW_GREEN_BITS = 0x00021002
|
||||
GLFW_BLUE_BITS = 0x00021003
|
||||
GLFW_ALPHA_BITS = 0x00021004
|
||||
GLFW_DEPTH_BITS = 0x00021005
|
||||
GLFW_STENCIL_BITS = 0x00021006
|
||||
GLFW_ACCUM_RED_BITS = 0x00021007
|
||||
GLFW_ACCUM_GREEN_BITS = 0x00021008
|
||||
GLFW_ACCUM_BLUE_BITS = 0x00021009
|
||||
GLFW_ACCUM_ALPHA_BITS = 0x0002100A
|
||||
GLFW_AUX_BUFFERS = 0x0002100B
|
||||
GLFW_STEREO = 0x0002100C
|
||||
GLFW_SAMPLES = 0x0002100D
|
||||
GLFW_SRGB_CAPABLE = 0x0002100E
|
||||
GLFW_REFRESH_RATE = 0x0002100F
|
||||
GLFW_DOUBLEBUFFER = 0x00021010
|
||||
|
||||
# ---
|
||||
GLFW_CLIENT_API = 0x00022001
|
||||
GLFW_CONTEXT_VERSION_MAJOR = 0x00022002
|
||||
GLFW_CONTEXT_VERSION_MINOR = 0x00022003
|
||||
GLFW_CONTEXT_REVISION = 0x00022004
|
||||
GLFW_CONTEXT_ROBUSTNESS = 0x00022005
|
||||
GLFW_OPENGL_FORWARD_COMPAT = 0x00022006
|
||||
GLFW_OPENGL_DEBUG_CONTEXT = 0x00022007
|
||||
GLFW_OPENGL_PROFILE = 0x00022008
|
||||
|
||||
# ---
|
||||
GLFW_OPENGL_API = 0x00030001
|
||||
GLFW_OPENGL_ES_API = 0x00030002
|
||||
|
||||
# ---
|
||||
GLFW_NO_ROBUSTNESS = 0
|
||||
GLFW_NO_RESET_NOTIFICATION = 0x00031001
|
||||
GLFW_LOSE_CONTEXT_ON_RESET = 0x00031002
|
||||
|
||||
# ---
|
||||
GLFW_OPENGL_ANY_PROFILE = 0
|
||||
GLFW_OPENGL_CORE_PROFILE = 0x00032001
|
||||
GLFW_OPENGL_COMPAT_PROFILE = 0x00032002
|
||||
|
||||
# ---
|
||||
GLFW_CURSOR = 0x00033001
|
||||
GLFW_STICKY_KEYS = 0x00033002
|
||||
GLFW_STICKY_MOUSE_BUTTONS = 0x00033003
|
||||
|
||||
# ---
|
||||
GLFW_CURSOR_NORMAL = 0x00034001
|
||||
GLFW_CURSOR_HIDDEN = 0x00034002
|
||||
GLFW_CURSOR_DISABLED = 0x00034003
|
||||
|
||||
# ---
|
||||
GLFW_CONNECTED = 0x00040001
|
||||
GLFW_DISCONNECTED = 0x00040002
|
||||
|
||||
|
||||
# --- Structures --------------------------------------------------------------
|
||||
class GLFWvidmode(Structure):
|
||||
_fields_ = [('width', c_int),
|
||||
('height', c_int),
|
||||
('redBits', c_int),
|
||||
('greenBits', c_int),
|
||||
('blueBits', c_int),
|
||||
('refreshRate', c_int)]
|
||||
|
||||
|
||||
class GLFWgammaramp(Structure):
|
||||
_fields_ = [('red', POINTER(c_ushort)),
|
||||
('green', POINTER(c_ushort)),
|
||||
('blue', POINTER(c_ushort)),
|
||||
('size', c_int)]
|
||||
|
||||
|
||||
class GLFWwindow(Structure):
|
||||
pass
|
||||
|
||||
|
||||
class GLFWmonitor(Structure):
|
||||
pass
|
||||
|
||||
# --- Callbacks ---------------------------------------------------------------
|
||||
errorfun = CFUNCTYPE(None, c_int, c_char_p)
|
||||
windowposfun = CFUNCTYPE(None, POINTER(GLFWwindow), c_int, c_int)
|
||||
windowsizefun = CFUNCTYPE(None, POINTER(GLFWwindow), c_int, c_int)
|
||||
windowclosefun = CFUNCTYPE(None, POINTER(GLFWwindow))
|
||||
windowrefreshfun = CFUNCTYPE(None, POINTER(GLFWwindow))
|
||||
windowfocusfun = CFUNCTYPE(None, POINTER(GLFWwindow), c_int)
|
||||
windowiconifyfun = CFUNCTYPE(None, POINTER(GLFWwindow), c_int)
|
||||
framebuffersizefun = CFUNCTYPE(None, POINTER(GLFWwindow), c_int, c_int)
|
||||
mousebuttonfun = CFUNCTYPE(None, POINTER(GLFWwindow), c_int, c_int, c_int)
|
||||
cursorposfun = CFUNCTYPE(None, POINTER(GLFWwindow), c_double, c_double)
|
||||
cursorenterfun = CFUNCTYPE(None, POINTER(GLFWwindow), c_int)
|
||||
scrollfun = CFUNCTYPE(None, POINTER(GLFWwindow), c_double, c_double)
|
||||
keyfun = CFUNCTYPE(None, POINTER(GLFWwindow), c_int, c_int, c_int, c_int)
|
||||
charfun = CFUNCTYPE(None, POINTER(GLFWwindow), c_uint)
|
||||
monitorfun = CFUNCTYPE(None, POINTER(GLFWmonitor), c_int)
|
||||
|
||||
# --- Init --------------------------------------------------------------------
|
||||
glfwInit = _glfw.glfwInit
|
||||
glfwTerminate = _glfw.glfwTerminate
|
||||
# glfwGetVersion = _glfw.glfwGetVersion
|
||||
|
||||
# --- Error -------------------------------------------------------------------
|
||||
# glfwSetErrorCallback = _glfw.glfwSetErrorCallback
|
||||
|
||||
# --- Monitor -----------------------------------------------------------------
|
||||
# glfwGetMonitors = _glfw.glfwGetMonitors
|
||||
# glfwGetMonitors.restype = POINTER(GLFWmonitor)
|
||||
glfwGetPrimaryMonitor = _glfw.glfwGetPrimaryMonitor
|
||||
glfwGetPrimaryMonitor.restype = POINTER(GLFWmonitor)
|
||||
# glfwGetMonitorPos = _glfw.glfwGetMonitorPos
|
||||
# glfwGetMonitorPhysicalSize = _glfw.glfwGetMonitorPhysicalSize
|
||||
glfwGetMonitorName = _glfw.glfwGetMonitorName
|
||||
glfwGetMonitorName.restype = c_char_p
|
||||
# glfwSetMonitorCallback = _glfw.glfwSetMonitorCallback
|
||||
# glfwGetVideoModes = _glfw.glfwGetVideoModes
|
||||
# glfwGetVideoMode = _glfw.glfwGetVideoMode
|
||||
|
||||
# --- Gama --------------------------------------------------------------------
|
||||
glfwSetGamma = _glfw.glfwSetGamma
|
||||
# glfwGetGammaRamp = _glfw.glfwGetGammaRamp
|
||||
# glfwSetGammaRamp = _glfw.glfwSetGammaRamp
|
||||
|
||||
# --- Window ------------------------------------------------------------------
|
||||
glfwDefaultWindowHints = _glfw.glfwDefaultWindowHints
|
||||
glfwWindowHint = _glfw.glfwWindowHint
|
||||
# glfwCreateWindow = _glfw.glfwCreateWindow
|
||||
# glfwDestroyWindow = _glfw.glfwDestroyWindow
|
||||
glfwWindowShouldClose = _glfw.glfwWindowShouldClose
|
||||
glfwSetWindowShouldClose = _glfw.glfwSetWindowShouldClose
|
||||
glfwSetWindowTitle = _glfw.glfwSetWindowTitle
|
||||
# glfwGetWindowPos = _glfw.glfwGetWindowPos
|
||||
glfwSetWindowPos = _glfw.glfwSetWindowPos
|
||||
# glfwGetWindowSize = _glfw.glfwGetWindowSize
|
||||
glfwSetWindowSize = _glfw.glfwSetWindowSize
|
||||
# glfwGetFramebufferSize = _glfw.glfwGetFramebufferSize
|
||||
glfwIconifyWindow = _glfw.glfwIconifyWindow
|
||||
glfwRestoreWindow = _glfw.glfwRestoreWindow
|
||||
glfwShowWindow = _glfw.glfwShowWindow
|
||||
glfwHideWindow = _glfw.glfwHideWindow
|
||||
glfwGetWindowMonitor = _glfw.glfwGetWindowMonitor
|
||||
glfwGetWindowAttrib = _glfw.glfwGetWindowAttrib
|
||||
glfwSetWindowUserPointer = _glfw.glfwSetWindowUserPointer
|
||||
glfwGetWindowUserPointer = _glfw.glfwGetWindowUserPointer
|
||||
# glfwSetWindowPosCallback = _glfw.glfwSetWindowPosCallback
|
||||
# glfwSetWindowSizeCallback = _glfw.glfwSetWindowSizeCallback
|
||||
# glfwSetWindowCloseCallback = _glfw.glfwSetWindowCloseCallback
|
||||
# glfwSetWindowRefreshCallback = _glfw.glfwSetWindowRefreshCallback
|
||||
# glfwSetWindowFocusCallback = _glfw.glfwSetWindowFocusCallback
|
||||
# glfwSetWindowIconifyCallback = _glfw.glfwSetWindowIconifyCallback
|
||||
# glfwSetFramebufferSizeCallback = _glfw.glfwSetFramebufferSizeCallback
|
||||
glfwPollEvents = _glfw.glfwPollEvents
|
||||
glfwWaitEvents = _glfw.glfwWaitEvents
|
||||
glfwPostEmptyEvent = _glfw.glfwPostEmptyEvent
|
||||
|
||||
# --- Input -------------------------------------------------------------------
|
||||
glfwGetInputMode = _glfw.glfwGetInputMode
|
||||
glfwSetInputMode = _glfw.glfwSetInputMode
|
||||
glfwGetKey = _glfw.glfwGetKey
|
||||
glfwGetMouseButton = _glfw.glfwGetMouseButton
|
||||
# glfwGetCursorPos = _glfw.glfwGetCursorPos
|
||||
glfwSetCursorPos = _glfw.glfwSetCursorPos
|
||||
# glfwSetKeyCallback = _glfw.glfwSetKeyCallback
|
||||
# glfwSetCharCallback = _glfw.glfwSetCharCallback
|
||||
# glfwSetMouseButtonCallback = _glfw.glfwSetMouseButtonCallback
|
||||
# glfwSetCursorPosCallback = _glfw.glfwSetCursorPosCallback
|
||||
# glfwSetCursorEnterCallback = _glfw.glfwSetCursorEnterCallback
|
||||
# glfwSetScrollCallback = _glfw.glfwSetScrollCallback
|
||||
glfwJoystickPresent = _glfw.glfwJoystickPresent
|
||||
# glfwGetJoystickAxes = _glfw.glfwGetJoystickAxes
|
||||
# glfwGetJoystickButtons = _glfw.glfwGetJoystickButtons
|
||||
glfwGetJoystickName = _glfw.glfwGetJoystickName
|
||||
glfwGetJoystickName.restype = c_char_p
|
||||
|
||||
# --- Clipboard ---------------------------------------------------------------
|
||||
glfwSetClipboardString = _glfw.glfwSetClipboardString
|
||||
glfwGetClipboardString = _glfw.glfwGetClipboardString
|
||||
glfwGetClipboardString.restype = c_char_p
|
||||
|
||||
# --- Timer -------------------------------------------------------------------
|
||||
glfwGetTime = _glfw.glfwGetTime
|
||||
glfwGetTime.restype = c_double
|
||||
glfwSetTime = _glfw.glfwSetTime
|
||||
|
||||
# --- Context -----------------------------------------------------------------
|
||||
glfwMakeContextCurrent = _glfw.glfwMakeContextCurrent
|
||||
glfwGetCurrentContext = _glfw.glfwGetCurrentContext
|
||||
glfwSwapBuffers = _glfw.glfwSwapBuffers
|
||||
glfwSwapInterval = _glfw.glfwSwapInterval
|
||||
glfwExtensionSupported = _glfw.glfwExtensionSupported
|
||||
glfwGetProcAddress = _glfw.glfwGetProcAddress
|
||||
|
||||
|
||||
# --- Pythonizer --------------------------------------------------------------
|
||||
|
||||
# This keeps track of current windows
|
||||
__windows__ = []
|
||||
__destroyed__ = []
|
||||
|
||||
# This is to prevent garbage collection on callbacks
|
||||
__c_callbacks__ = {}
|
||||
__py_callbacks__ = {}
|
||||
__c_error_callback__ = None
|
||||
|
||||
|
||||
def glfwCreateWindow(width=640, height=480, title="GLFW Window",
|
||||
monitor=None, share=None):
|
||||
_glfw.glfwCreateWindow.restype = POINTER(GLFWwindow)
|
||||
window = _glfw.glfwCreateWindow(width, height, title, monitor, share)
|
||||
__windows__.append(window)
|
||||
__destroyed__.append(False)
|
||||
index = __windows__.index(window)
|
||||
__c_callbacks__[index] = {}
|
||||
__py_callbacks__[index] = {'errorfun': None,
|
||||
'monitorfun': None,
|
||||
'windowposfun': None,
|
||||
'windowsizefun': None,
|
||||
'windowclosefun': None,
|
||||
'windowrefreshfun': None,
|
||||
'windowfocusfun': None,
|
||||
'windowiconifyfun': None,
|
||||
'framebuffersizefun': None,
|
||||
'keyfun': None,
|
||||
'charfun': None,
|
||||
'mousebuttonfun': None,
|
||||
'cursorposfun': None,
|
||||
'cursorenterfun': None,
|
||||
'scrollfun': None}
|
||||
return window
|
||||
|
||||
|
||||
def glfwDestroyWindow(window):
|
||||
index = __windows__.index(window)
|
||||
if not __destroyed__[index]:
|
||||
_glfw.glfwDestroyWindow(window)
|
||||
# We do not delete window from the list (or it would impact numbering)
|
||||
del __c_callbacks__[index]
|
||||
del __py_callbacks__[index]
|
||||
# del __windows__[index]
|
||||
__destroyed__[index] = True
|
||||
|
||||
|
||||
def glfwGetWindowPos(window):
|
||||
xpos, ypos = c_int(0), c_int(0)
|
||||
_glfw.glfwGetWindowPos(window, byref(xpos), byref(ypos))
|
||||
return xpos.value, ypos.value
|
||||
|
||||
|
||||
def glfwGetCursorPos(window):
|
||||
xpos, ypos = c_double(0), c_double(0)
|
||||
_glfw.glfwGetCursorPos(window, byref(xpos), byref(ypos))
|
||||
return int(xpos.value), int(ypos.value)
|
||||
|
||||
|
||||
def glfwGetWindowSize(window):
|
||||
width, height = c_int(0), c_int(0)
|
||||
_glfw.glfwGetWindowSize(window, byref(width), byref(height))
|
||||
return width.value, height.value
|
||||
|
||||
|
||||
def glfwGetFramebufferSize(window):
|
||||
width, height = c_int(0), c_int(0)
|
||||
_glfw.glfwGetFramebufferSize(window, byref(width), byref(height))
|
||||
return width.value, height.value
|
||||
|
||||
|
||||
def glfwGetMonitors():
|
||||
count = c_int(0)
|
||||
_glfw.glfwGetMonitors.restype = POINTER(POINTER(GLFWmonitor))
|
||||
c_monitors = _glfw.glfwGetMonitors(byref(count))
|
||||
return [c_monitors[i] for i in range(count.value)]
|
||||
|
||||
|
||||
def glfwGetVideoModes(monitor):
|
||||
count = c_int(0)
|
||||
_glfw.glfwGetVideoModes.restype = POINTER(GLFWvidmode)
|
||||
c_modes = _glfw.glfwGetVideoModes(monitor, byref(count))
|
||||
modes = []
|
||||
for i in range(count.value):
|
||||
modes.append((c_modes[i].width,
|
||||
c_modes[i].height,
|
||||
c_modes[i].redBits,
|
||||
c_modes[i].blueBits,
|
||||
c_modes[i].greenBits,
|
||||
c_modes[i].refreshRate))
|
||||
return modes
|
||||
|
||||
|
||||
def glfwGetMonitorPos(monitor):
|
||||
xpos, ypos = c_int(0), c_int(0)
|
||||
_glfw.glfwGetMonitorPos(monitor, byref(xpos), byref(ypos))
|
||||
return xpos.value, ypos.value
|
||||
|
||||
|
||||
def glfwGetMonitorPhysicalSize(monitor):
|
||||
width, height = c_int(0), c_int(0)
|
||||
_glfw.glfwGetMonitorPhysicalSize(monitor, byref(width), byref(height))
|
||||
return width.value, height.value
|
||||
|
||||
|
||||
def glfwGetVideoMode(monitor):
|
||||
_glfw.glfwGetVideoMode.restype = POINTER(GLFWvidmode)
|
||||
c_mode = _glfw.glfwGetVideoMode(monitor)
|
||||
return (c_mode.width,
|
||||
c_mode.height,
|
||||
c_mode.redBits,
|
||||
c_mode.blueBits,
|
||||
c_mode.greenBits,
|
||||
c_mode.refreshRate)
|
||||
|
||||
|
||||
def GetGammaRamp(monitor):
|
||||
_glfw.glfwGetGammaRamp.restype = POINTER(GLFWgammaramp)
|
||||
c_gamma = _glfw.glfwGetGammaRamp(monitor).contents
|
||||
gamma = {'red': [], 'green': [], 'blue': []}
|
||||
if c_gamma:
|
||||
for i in range(c_gamma.size):
|
||||
gamma['red'].append(c_gamma.red[i])
|
||||
gamma['green'].append(c_gamma.green[i])
|
||||
gamma['blue'].append(c_gamma.blue[i])
|
||||
return gamma
|
||||
|
||||
|
||||
def glfwGetJoystickAxes(joy):
|
||||
count = c_int(0)
|
||||
_glfw.glfwGetJoystickAxes.restype = POINTER(c_float)
|
||||
c_axes = _glfw.glfwGetJoystickAxes(joy, byref(count))
|
||||
axes = [c_axes[i].value for i in range(count)]
|
||||
return axes
|
||||
|
||||
|
||||
def glfwGetJoystickButtons(joy):
|
||||
count = c_int(0)
|
||||
_glfw.glfwGetJoystickButtons.restype = POINTER(c_int)
|
||||
c_buttons = _glfw.glfwGetJoystickButtons(joy, byref(count))
|
||||
buttons = [c_buttons[i].value for i in range(count)]
|
||||
return buttons
|
||||
|
||||
|
||||
# --- Callbacks ---------------------------------------------------------------
|
||||
|
||||
def __callback__(name):
|
||||
callback = 'glfwSet%sCallback' % name
|
||||
fun = '%sfun' % name.lower()
|
||||
code = """
|
||||
def %(callback)s(window, callback = None):
|
||||
index = __windows__.index(window)
|
||||
old_callback = __py_callbacks__[index]['%(fun)s']
|
||||
__py_callbacks__[index]['%(fun)s'] = callback
|
||||
if callback: callback = %(fun)s(callback)
|
||||
__c_callbacks__[index]['%(fun)s'] = callback
|
||||
_glfw.%(callback)s(window, callback)
|
||||
return old_callback""" % {'callback': callback, 'fun': fun}
|
||||
return code
|
||||
|
||||
exec(__callback__('Monitor'))
|
||||
exec(__callback__('WindowPos'))
|
||||
exec(__callback__('WindowSize'))
|
||||
exec(__callback__('WindowClose'))
|
||||
exec(__callback__('WindowRefresh'))
|
||||
exec(__callback__('WindowFocus'))
|
||||
exec(__callback__('WindowIconify'))
|
||||
exec(__callback__('FramebufferSize'))
|
||||
exec(__callback__('Key'))
|
||||
exec(__callback__('Char'))
|
||||
exec(__callback__('MouseButton'))
|
||||
exec(__callback__('CursorPos'))
|
||||
exec(__callback__('Scroll'))
|
||||
|
||||
|
||||
# Error callback does not take window parameter
|
||||
def glfwSetErrorCallback(callback=None):
|
||||
global __c_error_callback__
|
||||
__c_error_callback__ = errorfun(callback)
|
||||
_glfw.glfwSetErrorCallback(__c_error_callback__)
|
||||
123
kitty/boss.py
123
kitty/boss.py
@ -4,64 +4,113 @@
|
||||
|
||||
import os
|
||||
import io
|
||||
import select
|
||||
import signal
|
||||
import struct
|
||||
from threading import Thread
|
||||
from queue import Queue, Empty
|
||||
|
||||
from PyQt5.QtCore import QObject, QSocketNotifier
|
||||
|
||||
from .term import TerminalWidget
|
||||
from .utils import resize_pty, hangup, create_pty
|
||||
import glfw
|
||||
from .utils import resize_pty, create_pty
|
||||
|
||||
|
||||
class Boss(QObject):
|
||||
def handle_unix_signals():
|
||||
read_fd, write_fd = os.pipe2(os.O_NONBLOCK | os.O_CLOEXEC)
|
||||
for sig in (signal.SIGINT, signal.SIGTERM):
|
||||
signal.signal(sig, lambda x, y: None)
|
||||
signal.siginterrupt(sig, False)
|
||||
signal.set_wakeup_fd(write_fd)
|
||||
return read_fd
|
||||
|
||||
def __init__(self, opts, parent, dump_commands):
|
||||
QObject.__init__(self, parent)
|
||||
self.shutting_down = False
|
||||
|
||||
class Boss(Thread):
|
||||
|
||||
daemon = True
|
||||
shutting_down = False
|
||||
|
||||
def __init__(self, window, opts, args):
|
||||
Thread.__init__(self, name='ChildMonitor')
|
||||
self.window = window
|
||||
self.write_queue = Queue()
|
||||
self.write_buf = memoryview(b'')
|
||||
self.read_notifier = QSocketNotifier(create_pty()[0], QSocketNotifier.Read, self)
|
||||
self.read_notifier.activated.connect(self.read_ready)
|
||||
self.write_notifier = QSocketNotifier(create_pty()[0], QSocketNotifier.Write, self)
|
||||
self.write_notifier.setEnabled(False)
|
||||
self.write_notifier.activated.connect(self.write_ready)
|
||||
self.term = TerminalWidget(opts, parent, dump_commands)
|
||||
self.term.relayout_lines.connect(self.relayout_lines)
|
||||
self.term.send_data_to_child.connect(self.write_to_child)
|
||||
self.term.write_to_child.connect(self.write_to_child)
|
||||
self.child_fd = create_pty()[0]
|
||||
self.signal_fd = handle_unix_signals()
|
||||
self.read_wakeup_fd, self.write_wakeup_fd = os.pipe2(os.O_NONBLOCK | os.O_CLOEXEC)
|
||||
self.readers = [self.child_fd, self.signal_fd, self.read_wakeup_fd]
|
||||
self.writers = [self.child_fd]
|
||||
resize_pty(80, 24)
|
||||
|
||||
def apply_opts(self, opts):
|
||||
self.term.apply_opts(opts)
|
||||
def on_window_resize(self, window, w, h):
|
||||
pass
|
||||
|
||||
def read_ready(self, read_fd):
|
||||
def render(self):
|
||||
pass
|
||||
|
||||
def wakeup(self):
|
||||
os.write(self.write_wakeup_fd, b'1')
|
||||
|
||||
def on_wakeup(self):
|
||||
try:
|
||||
os.read(self.read_wakeup_fd, 1024)
|
||||
except Exception:
|
||||
pass
|
||||
buf = b''
|
||||
while True:
|
||||
try:
|
||||
buf += self.write_queue.get_nowait()
|
||||
except Empty:
|
||||
break
|
||||
if buf:
|
||||
self.write_buf = memoryview(self.write_buf.tobytes() + buf)
|
||||
|
||||
def run(self):
|
||||
while not self.shutting_down:
|
||||
readers, writers, _ = select.select(self.readers, self.writers if self.write_buf else [], [])
|
||||
for r in readers:
|
||||
if r is self.child_fd:
|
||||
self.read_ready()
|
||||
elif r is self.read_wakeup_fd:
|
||||
self.on_wakeup()
|
||||
elif r is self.signal_fd:
|
||||
self.signal_received()
|
||||
if writers:
|
||||
self.write_ready()
|
||||
|
||||
def signal_received(self):
|
||||
try:
|
||||
data = os.read(self.signal_fd, 1024)
|
||||
except BlockingIOError:
|
||||
return
|
||||
if data:
|
||||
signals = struct.unpack('%uB' % len(data), data)
|
||||
if signal.SIGINT in signals or signal.SIGTERM in signals:
|
||||
self.shutdown()
|
||||
|
||||
def shutdown(self):
|
||||
self.shutting_down = True
|
||||
glfw.glfwSetWindowShouldClose(self.window, True)
|
||||
glfw.glfwPostEmptyEvent()
|
||||
|
||||
def read_ready(self):
|
||||
if self.shutting_down:
|
||||
return
|
||||
try:
|
||||
data = os.read(read_fd, io.DEFAULT_BUFFER_SIZE)
|
||||
data = os.read(self.child_fd, io.DEFAULT_BUFFER_SIZE)
|
||||
except EnvironmentError:
|
||||
data = b''
|
||||
if not data:
|
||||
# EOF
|
||||
self.read_notifier.setEnabled(False)
|
||||
self.parent().child_process_died()
|
||||
self.shutdown()
|
||||
return
|
||||
self.term.feed(data)
|
||||
|
||||
def write_ready(self, write_fd):
|
||||
def write_ready(self):
|
||||
if not self.shutting_down:
|
||||
while self.write_buf:
|
||||
n = os.write(write_fd, self.write_buf)
|
||||
n = os.write(self.child_fd, self.write_buf)
|
||||
if not n:
|
||||
return
|
||||
self.write_buf = self.write_buf[n:]
|
||||
self.write_notifier.setEnabled(False)
|
||||
|
||||
def write_to_child(self, data):
|
||||
self.write_buf = memoryview(self.write_buf.tobytes() + data)
|
||||
self.write_notifier.setEnabled(True)
|
||||
|
||||
def relayout_lines(self, cells_per_line, lines_per_screen):
|
||||
resize_pty(cells_per_line, lines_per_screen)
|
||||
|
||||
def shutdown(self):
|
||||
self.shutting_down = True
|
||||
self.read_notifier.setEnabled(False)
|
||||
hangup()
|
||||
self.write_queue.put(data)
|
||||
self.wakeup()
|
||||
|
||||
193
kitty/config.py
193
kitty/config.py
@ -6,18 +6,179 @@ import re
|
||||
from collections import namedtuple
|
||||
from typing import Tuple
|
||||
|
||||
from PyQt5.QtGui import QFont, QFontInfo, QColor
|
||||
|
||||
key_pat = re.compile(r'([a-zA-Z][a-zA-Z0-9_-]*)\s+(.+)$')
|
||||
# Color definitions {{{
|
||||
color_pat = re.compile(r'^#([a-fA-F0-9]{3}|[a-fA-F0-9]{6})$')
|
||||
color_names = {
|
||||
'aliceblue': 'f0f8ff',
|
||||
'antiquewhite': 'faebd7',
|
||||
'aqua': '00ffff',
|
||||
'aquamarine': '7fffd4',
|
||||
'azure': 'f0ffff',
|
||||
'beige': 'f5f5dc',
|
||||
'bisque': 'ffe4c4',
|
||||
'black': '000000',
|
||||
'blanchedalmond': 'ffebcd',
|
||||
'blue': '0000ff',
|
||||
'blueviolet': '8a2be2',
|
||||
'brown': 'a52a2a',
|
||||
'burlywood': 'deb887',
|
||||
'cadetblue': '5f9ea0',
|
||||
'chartreuse': '7fff00',
|
||||
'chocolate': 'd2691e',
|
||||
'coral': 'ff7f50',
|
||||
'cornflowerblue': '6495ed',
|
||||
'cornsilk': 'fff8dc',
|
||||
'crimson': 'dc143c',
|
||||
'cyan': '00ffff',
|
||||
'darkblue': '00008b',
|
||||
'darkcyan': '008b8b',
|
||||
'darkgoldenrod': 'b8860b',
|
||||
'darkgray': 'a9a9a9',
|
||||
'darkgrey': 'a9a9a9',
|
||||
'darkgreen': '006400',
|
||||
'darkkhaki': 'bdb76b',
|
||||
'darkmagenta': '8b008b',
|
||||
'darkolivegreen': '556b2f',
|
||||
'darkorange': 'ff8c00',
|
||||
'darkorchid': '9932cc',
|
||||
'darkred': '8b0000',
|
||||
'darksalmon': 'e9967a',
|
||||
'darkseagreen': '8fbc8f',
|
||||
'darkslateblue': '483d8b',
|
||||
'darkslategray': '2f4f4f',
|
||||
'darkslategrey': '2f4f4f',
|
||||
'darkturquoise': '00ced1',
|
||||
'darkviolet': '9400d3',
|
||||
'deeppink': 'ff1493',
|
||||
'deepskyblue': '00bfff',
|
||||
'dimgray': '696969',
|
||||
'dimgrey': '696969',
|
||||
'dodgerblue': '1e90ff',
|
||||
'firebrick': 'b22222',
|
||||
'floralwhite': 'fffaf0',
|
||||
'forestgreen': '228b22',
|
||||
'fuchsia': 'ff00ff',
|
||||
'gainsboro': 'dcdcdc',
|
||||
'ghostwhite': 'f8f8ff',
|
||||
'gold': 'ffd700',
|
||||
'goldenrod': 'daa520',
|
||||
'gray': '808080',
|
||||
'grey': '808080',
|
||||
'green': '008000',
|
||||
'greenyellow': 'adff2f',
|
||||
'honeydew': 'f0fff0',
|
||||
'hotpink': 'ff69b4',
|
||||
'indianred': 'cd5c5c',
|
||||
'indigo': '4b0082',
|
||||
'ivory': 'fffff0',
|
||||
'khaki': 'f0e68c',
|
||||
'lavender': 'e6e6fa',
|
||||
'lavenderblush': 'fff0f5',
|
||||
'lawngreen': '7cfc00',
|
||||
'lemonchiffon': 'fffacd',
|
||||
'lightblue': 'add8e6',
|
||||
'lightcoral': 'f08080',
|
||||
'lightcyan': 'e0ffff',
|
||||
'lightgoldenrodyellow': 'fafad2',
|
||||
'lightgray': 'd3d3d3',
|
||||
'lightgrey': 'd3d3d3',
|
||||
'lightgreen': '90ee90',
|
||||
'lightpink': 'ffb6c1',
|
||||
'lightsalmon': 'ffa07a',
|
||||
'lightseagreen': '20b2aa',
|
||||
'lightskyblue': '87cefa',
|
||||
'lightslategray': '778899',
|
||||
'lightslategrey': '778899',
|
||||
'lightsteelblue': 'b0c4de',
|
||||
'lightyellow': 'ffffe0',
|
||||
'lime': '00ff00',
|
||||
'limegreen': '32cd32',
|
||||
'linen': 'faf0e6',
|
||||
'magenta': 'ff00ff',
|
||||
'maroon': '800000',
|
||||
'mediumaquamarine': '66cdaa',
|
||||
'mediumblue': '0000cd',
|
||||
'mediumorchid': 'ba55d3',
|
||||
'mediumpurple': '9370db',
|
||||
'mediumseagreen': '3cb371',
|
||||
'mediumslateblue': '7b68ee',
|
||||
'mediumspringgreen': '00fa9a',
|
||||
'mediumturquoise': '48d1cc',
|
||||
'mediumvioletred': 'c71585',
|
||||
'midnightblue': '191970',
|
||||
'mintcream': 'f5fffa',
|
||||
'mistyrose': 'ffe4e1',
|
||||
'moccasin': 'ffe4b5',
|
||||
'navajowhite': 'ffdead',
|
||||
'navy': '000080',
|
||||
'oldlace': 'fdf5e6',
|
||||
'olive': '808000',
|
||||
'olivedrab': '6b8e23',
|
||||
'orange': 'ffa500',
|
||||
'orangered': 'ff4500',
|
||||
'orchid': 'da70d6',
|
||||
'palegoldenrod': 'eee8aa',
|
||||
'palegreen': '98fb98',
|
||||
'paleturquoise': 'afeeee',
|
||||
'palevioletred': 'db7093',
|
||||
'papayawhip': 'ffefd5',
|
||||
'peachpuff': 'ffdab9',
|
||||
'per': 'cd853f',
|
||||
'pink': 'ffc0cb',
|
||||
'plum': 'dda0dd',
|
||||
'powderblue': 'b0e0e6',
|
||||
'purple': '800080',
|
||||
'red': 'ff0000',
|
||||
'rosybrown': 'bc8f8f',
|
||||
'royalblue': '4169e1',
|
||||
'saddlebrown': '8b4513',
|
||||
'salmon': 'fa8072',
|
||||
'sandybrown': 'f4a460',
|
||||
'seagreen': '2e8b57',
|
||||
'seashell': 'fff5ee',
|
||||
'sienna': 'a0522d',
|
||||
'silver': 'c0c0c0',
|
||||
'skyblue': '87ceeb',
|
||||
'slateblue': '6a5acd',
|
||||
'slategray': '708090',
|
||||
'slategrey': '708090',
|
||||
'snow': 'fffafa',
|
||||
'springgreen': '00ff7f',
|
||||
'steelblue': '4682b4',
|
||||
'tan': 'd2b48c',
|
||||
'teal': '008080',
|
||||
'thistle': 'd8bfd8',
|
||||
'tomato': 'ff6347',
|
||||
'turquoise': '40e0d0',
|
||||
'violet': 'ee82ee',
|
||||
'wheat': 'f5deb3',
|
||||
'white': 'ffffff',
|
||||
'whitesmoke': 'f5f5f5',
|
||||
'yellow': 'ffff00',
|
||||
'yellowgreen': '9acd32',
|
||||
}
|
||||
Color = namedtuple('Color', 'red green blue')
|
||||
# }}}
|
||||
|
||||
defaults = {}
|
||||
|
||||
|
||||
def to_qcolor(x):
|
||||
ans = QColor(x)
|
||||
if not ans.isValid():
|
||||
raise ValueError('{} is not a valid color'.format(x))
|
||||
return ans
|
||||
def to_color(raw, validate=False):
|
||||
x = raw.strip().lower()
|
||||
m = color_pat.match(x)
|
||||
val = None
|
||||
if m is not None:
|
||||
val = m.group(1)
|
||||
if len(val) == 3:
|
||||
val = ''.join(2 * s for s in val)
|
||||
else:
|
||||
val = color_names.get(x)
|
||||
if val is None:
|
||||
if validate:
|
||||
raise ValueError('Invalid color name: {}'.format(raw))
|
||||
return
|
||||
return Color(int(val[:2], 16), int(val[2:4], 16), int(val[4:], 16))
|
||||
|
||||
|
||||
def to_font_size(x):
|
||||
@ -44,7 +205,9 @@ type_map = {
|
||||
'cursor_blink': to_bool,
|
||||
}
|
||||
for name in 'foreground foreground_bold background cursor'.split():
|
||||
type_map[name] = to_qcolor
|
||||
type_map[name] = lambda x: to_color(x, validate=True)
|
||||
for i in range(16):
|
||||
type_map['color%d' % i] = lambda x: to_color(x, validate=True)
|
||||
|
||||
|
||||
for line in '''
|
||||
@ -77,8 +240,8 @@ color3 #cecb00
|
||||
color11 #fffd00
|
||||
|
||||
# blue
|
||||
color4 = #0d73cc
|
||||
color12 = #1a8fff
|
||||
color4 #0d73cc
|
||||
color12 #1a8fff
|
||||
|
||||
# magenta
|
||||
color5 #cb1ed1
|
||||
@ -131,19 +294,19 @@ def load_config(path: str) -> Options:
|
||||
|
||||
|
||||
def validate_font(opts: Options):
|
||||
if not QFontInfo(QFont(opts.font_family)).fixedPitch():
|
||||
if False: # TODO: Implement this
|
||||
raise ValueError('The font specified in the configuration "{}" is not a monospace font'.format(opts.font_family))
|
||||
|
||||
|
||||
def build_ansi_color_tables(opts: Options) -> Tuple[dict, dict]:
|
||||
def col(i):
|
||||
return QColor(getattr(opts, 'color{}'.format(i))).getRgb()[:3]
|
||||
return getattr(opts, 'color{}'.format(i))
|
||||
fg = {30 + i: col(i) for i in range(8)}
|
||||
fg[39] = opts.foreground.getRgb()[:3]
|
||||
fg[39] = opts.foreground
|
||||
fg.update({90 + i: col(i + 8) for i in range(8)})
|
||||
fg[99] = opts.foreground_bold.getRgb()[:3]
|
||||
fg[99] = opts.foreground_bold
|
||||
bg = {40 + i: col(i) for i in range(8)}
|
||||
bg[49] = opts.background.getRgb()[:3]
|
||||
bg[49] = opts.background
|
||||
bg.update({100 + i: col(i + 8) for i in range(8)})
|
||||
build_ansi_color_tables.fg, build_ansi_color_tables.bg = fg, bg
|
||||
build_ansi_color_tables(defaults)
|
||||
|
||||
160
kitty/main.py
160
kitty/main.py
@ -5,83 +5,21 @@
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import struct
|
||||
import pwd
|
||||
import signal
|
||||
from gettext import gettext as _
|
||||
|
||||
from PyQt5.QtCore import Qt, QSocketNotifier, pyqtSignal
|
||||
from PyQt5.QtGui import QIcon
|
||||
from PyQt5.QtWidgets import QApplication, QMainWindow, QMessageBox
|
||||
|
||||
from .config import load_config, validate_font
|
||||
from .constants import appname, str_version, config_dir
|
||||
from .boss import Boss
|
||||
from .utils import fork_child
|
||||
from .keys import KeyFilter
|
||||
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
|
||||
report_error = pyqtSignal(object)
|
||||
|
||||
def __init__(self, opts, dump_commands):
|
||||
QMainWindow.__init__(self)
|
||||
self.setWindowTitle(appname)
|
||||
sys.excepthook = self.on_unhandled_error
|
||||
self.report_error.connect(self.show_error, type=Qt.QueuedConnection)
|
||||
self.handle_unix_signals()
|
||||
self.boss = Boss(opts, self, dump_commands)
|
||||
self.boss.term.title_changed.connect(self.setWindowTitle)
|
||||
self.boss.term.icon_changed.connect(lambda name: self.setWindowIcon(QIcon.fromTheme(name)))
|
||||
self.setCentralWidget(self.boss.term)
|
||||
|
||||
def on_unhandled_error(self, etype, value, tb):
|
||||
if etype == KeyboardInterrupt:
|
||||
return
|
||||
sys.__excepthook__(etype, value, tb)
|
||||
try:
|
||||
msg = str(value)
|
||||
except Exception:
|
||||
msg = repr(value)
|
||||
self.report_error.emit(msg)
|
||||
|
||||
def show_error(self, msg):
|
||||
QMessageBox.critical(self, _('Unhandled exception'), msg)
|
||||
|
||||
def handle_unix_signals(self):
|
||||
read_fd, write_fd = os.pipe2(os.O_NONBLOCK | os.O_CLOEXEC)
|
||||
for sig in (signal.SIGINT, signal.SIGTERM):
|
||||
signal.signal(sig, lambda x, y: None)
|
||||
signal.siginterrupt(sig, False)
|
||||
signal.set_wakeup_fd(write_fd)
|
||||
self.signal_notifier = QSocketNotifier(read_fd, QSocketNotifier.Read, self)
|
||||
self.signal_notifier.setEnabled(True)
|
||||
self.signal_notifier.activated.connect(self.signal_received, type=Qt.QueuedConnection)
|
||||
|
||||
def signal_received(self, read_fd):
|
||||
try:
|
||||
data = os.read(read_fd, 1024)
|
||||
except BlockingIOError:
|
||||
return
|
||||
if data:
|
||||
signals = struct.unpack('%uB' % len(data), data)
|
||||
if signal.SIGINT in signals or signal.SIGTERM in signals:
|
||||
self.shutdown()
|
||||
|
||||
def child_process_died(self):
|
||||
self.shutdown()
|
||||
|
||||
def shutdown(self):
|
||||
self.close()
|
||||
self.boss.shutdown()
|
||||
from .utils import fork_child, hangup
|
||||
import glfw
|
||||
|
||||
|
||||
def option_parser():
|
||||
parser = argparse.ArgumentParser(prog=appname, description=_('The {} terminal emulator').format(appname))
|
||||
a = parser.add_argument
|
||||
a('--name', default=appname, help=_('Set the name part of the WM_CLASS property'))
|
||||
a('--class', default=appname, dest='cls', help=_('Set the class part of the WM_CLASS property'))
|
||||
a('--class', default=appname, dest='cls', help=_('Set the WM_CLASS property'))
|
||||
a('--config', default=os.path.join(config_dir, 'kitty.conf'), help=_('Specify a path to the config file to use'))
|
||||
a('--cmd', '-c', default=None, help=_('Run python code in the kitty context'))
|
||||
a('-d', '--directory', default='.', help=_('Change to the specified directory when launching'))
|
||||
@ -95,11 +33,43 @@ def option_parser():
|
||||
return parser
|
||||
|
||||
|
||||
def run_app():
|
||||
def setup_opengl():
|
||||
glfw.glfwWindowHint(glfw.GLFW_CONTEXT_VERSION_MAJOR, 3)
|
||||
glfw.glfwWindowHint(glfw.GLFW_CONTEXT_VERSION_MINOR, 2)
|
||||
glfw.glfwWindowHint(glfw.GLFW_OPENGL_PROFILE, glfw.GLFW_OPENGL_CORE_PROFILE)
|
||||
glfw.glfwWindowHint(glfw.GLFW_OPENGL_FORWARD_COMPAT, True)
|
||||
glfw.glfwWindowHint(glfw.GLFW_SAMPLES, 0)
|
||||
|
||||
|
||||
def run_app(opts, args):
|
||||
setup_opengl()
|
||||
window = glfw.glfwCreateWindow(
|
||||
1024, 1024, args.cls.encode('utf-8'), None, None)
|
||||
if not window:
|
||||
raise SystemExit("glfwCreateWindow failed")
|
||||
glfw.glfwSetWindowTitle(window, appname.encode('utf-8'))
|
||||
try:
|
||||
return QApplication.instance().exec_()
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
glfw.glfwMakeContextCurrent(window)
|
||||
glfw.glfwSwapInterval(1)
|
||||
boss = Boss(window, opts, args)
|
||||
glfw.glfwSetFramebufferSizeCallback(window, boss.on_window_resize)
|
||||
boss.start()
|
||||
|
||||
while not glfw.glfwWindowShouldClose(window):
|
||||
boss.render()
|
||||
glfw.glfwSwapBuffers(window)
|
||||
glfw.glfwWaitEvents()
|
||||
finally:
|
||||
glfw.glfwDestroyWindow(window)
|
||||
|
||||
|
||||
def on_glfw_error(code, msg):
|
||||
if isinstance(msg, bytes):
|
||||
try:
|
||||
msg = msg.decode('utf-8')
|
||||
except Exception:
|
||||
msg = repr(msg)
|
||||
print('[glfw error]:', msg, file=sys.stderr)
|
||||
|
||||
|
||||
def main():
|
||||
@ -107,37 +77,31 @@ def main():
|
||||
if args.cmd:
|
||||
exec(args.cmd)
|
||||
return
|
||||
# Ensure the child process gets no environment from Qt
|
||||
opts = load_config(args.config)
|
||||
child = args.args or [pwd.getpwuid(os.geteuid()).pw_shell or '/bin/sh']
|
||||
fork_child(child, args.directory, opts)
|
||||
|
||||
QApplication.setAttribute(Qt.AA_DisableHighDpiScaling, True)
|
||||
app = QApplication([appname])
|
||||
keyfilter = KeyFilter(app)
|
||||
app.installEventFilter(keyfilter)
|
||||
app.setOrganizationName(args.cls)
|
||||
app.setApplicationName(args.name)
|
||||
try:
|
||||
validate_font(opts)
|
||||
except ValueError as err:
|
||||
raise SystemExit(str(err)) from None
|
||||
w = MainWindow(opts, args.dump_commands)
|
||||
w.show()
|
||||
if args.profile:
|
||||
import cProfile
|
||||
import pstats
|
||||
pr = cProfile.Profile()
|
||||
pr.enable()
|
||||
ret = run_app()
|
||||
pr.disable()
|
||||
pr.create_stats()
|
||||
s = pstats.Stats(pr)
|
||||
s.strip_dirs()
|
||||
s.sort_stats('time', 'name')
|
||||
s.print_stats(30)
|
||||
else:
|
||||
ret = run_app()
|
||||
app.installEventFilter(None)
|
||||
del keyfilter
|
||||
return ret
|
||||
glfw.glfwSetErrorCallback(on_glfw_error)
|
||||
if not glfw.glfwInit():
|
||||
raise SystemExit('GLFW initialization failed')
|
||||
try:
|
||||
child = args.args or [pwd.getpwuid(os.geteuid()).pw_shell or '/bin/sh']
|
||||
fork_child(child, args.directory, opts)
|
||||
if args.profile:
|
||||
import cProfile
|
||||
import pstats
|
||||
pr = cProfile.Profile()
|
||||
pr.enable()
|
||||
run_app(opts, args)
|
||||
pr.disable()
|
||||
pr.create_stats()
|
||||
s = pstats.Stats(pr)
|
||||
s.strip_dirs()
|
||||
s.sort_stats('time', 'name')
|
||||
s.print_stats(30)
|
||||
else:
|
||||
run_app(opts, args)
|
||||
finally:
|
||||
glfw.glfwTerminate()
|
||||
hangup()
|
||||
|
||||
@ -15,11 +15,8 @@ from contextlib import contextmanager
|
||||
from functools import lru_cache
|
||||
from time import monotonic
|
||||
|
||||
from PyQt5.QtGui import QFontMetrics
|
||||
|
||||
from .constants import terminfo_dir
|
||||
|
||||
current_font_metrics = cell_width = None
|
||||
libc = ctypes.CDLL(None)
|
||||
wcwidth_native = libc.wcwidth
|
||||
del libc
|
||||
@ -31,23 +28,14 @@ wcwidth_native.restype = ctypes.c_int
|
||||
def wcwidth(c: str) -> int:
|
||||
if unicodedata.combining(c):
|
||||
return 0
|
||||
if current_font_metrics is None:
|
||||
if wcwidth.current_font is None:
|
||||
return min(2, wcwidth_native(c))
|
||||
try:
|
||||
w = current_font_metrics.widthChar(c)
|
||||
except ValueError:
|
||||
# Happens for non-BMP unicode chars
|
||||
w = current_font_metrics.width(c)
|
||||
cells, extra = divmod(w, cell_width)
|
||||
if extra > 0.1 * cell_width:
|
||||
cells += 1
|
||||
return min(2, cells)
|
||||
wcwidth.current_font = wcwidth.cell_width = None
|
||||
|
||||
|
||||
def set_current_font_metrics(fm: QFontMetrics, cw: int) -> None:
|
||||
global current_font_metrics, cell_width
|
||||
current_font_metrics, cell_width = fm, cw
|
||||
def set_current_font_metrics(current_font, cw: int) -> None:
|
||||
wcwidth.cache_clear()
|
||||
wcwidth.current_font, wcwidth.cell_width = current_font, cw
|
||||
|
||||
|
||||
def create_pty():
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user