Get rid of the GLFW ctypes bindings
This commit is contained in:
parent
a52c4670dc
commit
f713117908
409
glfw.py
409
glfw.py
@ -1,409 +0,0 @@
|
||||
# -*- 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 collections import namedtuple
|
||||
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
|
||||
|
||||
|
||||
# --- 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)
|
||||
charmodsfun = CFUNCTYPE(None, POINTER(GLFWwindow), c_uint, c_int)
|
||||
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,
|
||||
'charmodsfun': 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
|
||||
|
||||
|
||||
VideoMode = namedtuple('VideoMode', 'width height redBits blueBits greenBits refreshRate')
|
||||
|
||||
|
||||
def glfwGetVideoMode(monitor):
|
||||
_glfw.glfwGetVideoMode.restype = POINTER(GLFWvidmode)
|
||||
c_mode = _glfw.glfwGetVideoMode(monitor).contents
|
||||
return VideoMode(
|
||||
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__('CharMods'))
|
||||
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__)
|
||||
@ -22,6 +22,8 @@ static PyMethodDef module_methods[] = {
|
||||
{"glfw_window_hint", (PyCFunction)glfw_window_hint, METH_VARARGS, ""},
|
||||
{"glfw_swap_interval", (PyCFunction)glfw_swap_interval, METH_VARARGS, ""},
|
||||
{"glfw_wait_events", (PyCFunction)glfw_wait_events, METH_NOARGS, ""},
|
||||
{"glfw_post_empty_event", (PyCFunction)glfw_post_empty_event, METH_NOARGS, ""},
|
||||
{"glfw_get_physical_dpi", (PyCFunction)glfw_get_physical_dpi, METH_NOARGS, ""},
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
@ -54,6 +56,7 @@ PyInit_fast_data_types(void) {
|
||||
if (!init_Face(m)) return NULL;
|
||||
if (!add_module_gl_constants(m)) return NULL;
|
||||
if (!init_glfw(m)) return NULL;
|
||||
if (!init_Window(m)) return NULL;
|
||||
PyModule_AddIntConstant(m, "BOLD", BOLD_SHIFT);
|
||||
PyModule_AddIntConstant(m, "ITALIC", ITALIC_SHIFT);
|
||||
PyModule_AddIntConstant(m, "REVERSE", REVERSE_SHIFT);
|
||||
|
||||
@ -176,6 +176,7 @@ typedef struct {
|
||||
PyTypeObject Cursor_Type;
|
||||
|
||||
PyTypeObject Face_Type;
|
||||
PyTypeObject Window_Type;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
@ -295,6 +296,7 @@ int init_SpriteMap(PyObject *);
|
||||
int init_ChangeTracker(PyObject *);
|
||||
int init_Screen(PyObject *);
|
||||
int init_Face(PyObject *);
|
||||
int init_Window(PyObject *);
|
||||
PyObject* create_256_color_table();
|
||||
PyObject* read_bytes_dump(PyObject UNUSED *, PyObject *);
|
||||
PyObject* read_bytes(PyObject UNUSED *, PyObject *);
|
||||
|
||||
215
kitty/glfw.c
215
kitty/glfw.c
@ -5,22 +5,103 @@
|
||||
*/
|
||||
|
||||
#include "data-types.h"
|
||||
#include <structmember.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#define MAX_WINDOWS 255
|
||||
/* static PyObject* window_weakrefs[MAX_WINDOWS + 1] = {0}; */
|
||||
#define MAX_WINDOWS 256
|
||||
|
||||
#define CALLBACK(name, fmt, ...) \
|
||||
if ((name) != NULL) { \
|
||||
PyGILState_STATE _pystate = PyGILState_Ensure(); \
|
||||
PyObject *_pyret = PyObject_CallFunction((name), fmt, __VA_ARGS__); \
|
||||
PyGILState_Release(_pystate); \
|
||||
if (_pyret == NULL) { PyErr_Print(); PyErr_Clear(); return; } \
|
||||
if (_pyret == NULL && PyErr_Occurred() != NULL) PyErr_Print(); \
|
||||
Py_CLEAR(_pyret); \
|
||||
PyGILState_Release(_pystate); \
|
||||
}
|
||||
|
||||
#define WINDOW_CALLBACK(name, fmt, ...) \
|
||||
Window *self = find_window(w); \
|
||||
if (self) { CALLBACK(self->name, "O" fmt, self, __VA_ARGS__); }
|
||||
|
||||
// Library Setup {{{
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
|
||||
GLFWwindow *window;
|
||||
PyObject *framebuffer_size_callback, *char_mods_callback, *key_callback, *mouse_button_callback, *scroll_callback, *cursor_pos_callback, *window_focus_callback;
|
||||
} Window;
|
||||
static Window* window_weakrefs[MAX_WINDOWS] = {0};
|
||||
|
||||
static inline Window*
|
||||
find_window(GLFWwindow *w) {
|
||||
for(int i = 0; i < MAX_WINDOWS; i++) {
|
||||
if (window_weakrefs[i] == NULL) break;
|
||||
if (window_weakrefs[i]->window == w) return window_weakrefs[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
framebuffer_size_callback(GLFWwindow *w, int width, int height) {
|
||||
WINDOW_CALLBACK(framebuffer_size_callback, "ii", width, height);
|
||||
}
|
||||
|
||||
static void
|
||||
char_mods_callback(GLFWwindow *w, unsigned int codepoint, int mods) {
|
||||
WINDOW_CALLBACK(char_mods_callback, "Ii", codepoint, mods);
|
||||
}
|
||||
|
||||
static void
|
||||
key_callback(GLFWwindow *w, int key, int scancode, int action, int mods) {
|
||||
WINDOW_CALLBACK(key_callback, "iiii", key, scancode, action, mods);
|
||||
}
|
||||
|
||||
static void
|
||||
mouse_button_callback(GLFWwindow *w, int button, int action, int mods) {
|
||||
WINDOW_CALLBACK(mouse_button_callback, "iii", button, action, mods);
|
||||
}
|
||||
|
||||
static void
|
||||
scroll_callback(GLFWwindow *w, double xoffset, double yoffset) {
|
||||
WINDOW_CALLBACK(scroll_callback, "dd", xoffset, yoffset);
|
||||
}
|
||||
|
||||
static void
|
||||
cursor_pos_callback(GLFWwindow *w, double x, double y) {
|
||||
WINDOW_CALLBACK(cursor_pos_callback, "dd", x, y);
|
||||
}
|
||||
|
||||
static void
|
||||
window_focus_callback(GLFWwindow *w, int focused) {
|
||||
WINDOW_CALLBACK(window_focus_callback, "O", focused ? Py_True : Py_False);
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
||||
Window *self;
|
||||
char *title;
|
||||
int width, height, i;
|
||||
if (!PyArg_ParseTuple(args, "iis", &width, &height, &title)) return NULL;
|
||||
|
||||
self = (Window *)type->tp_alloc(type, 0);
|
||||
if (self != NULL) {
|
||||
self->window = glfwCreateWindow(width, height, title, NULL, NULL);
|
||||
if (self->window == NULL) { Py_CLEAR(self); PyErr_SetString(PyExc_ValueError, "Failed to create GLFWWindow"); return NULL; }
|
||||
for(i = 0; i < MAX_WINDOWS; i++) {
|
||||
if (window_weakrefs[i] == NULL) { window_weakrefs[i] = self; break; }
|
||||
}
|
||||
if (i >= MAX_WINDOWS) { Py_CLEAR(self); PyErr_SetString(PyExc_ValueError, "Too many windows created"); return NULL; }
|
||||
glfwSetFramebufferSizeCallback(self->window, framebuffer_size_callback);
|
||||
glfwSetCharModsCallback(self->window, char_mods_callback);
|
||||
glfwSetKeyCallback(self->window, key_callback);
|
||||
glfwSetMouseButtonCallback(self->window, mouse_button_callback);
|
||||
glfwSetScrollCallback(self->window, scroll_callback);
|
||||
glfwSetCursorPosCallback(self->window, cursor_pos_callback);
|
||||
glfwSetWindowFocusCallback(self->window, window_focus_callback);
|
||||
}
|
||||
return (PyObject*)self;
|
||||
}
|
||||
|
||||
// Global functions {{{
|
||||
static PyObject *error_callback = NULL;
|
||||
|
||||
static void
|
||||
@ -36,6 +117,7 @@ glfw_set_error_callback(PyObject UNUSED *self, PyObject *callback) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
PyObject*
|
||||
glfw_init(PyObject UNUSED *self) {
|
||||
PyObject *ans = glfwInit() ? Py_True: Py_False;
|
||||
@ -73,8 +155,130 @@ glfw_wait_events(PyObject UNUSED *self) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyObject*
|
||||
glfw_post_empty_event(PyObject UNUSED *self) {
|
||||
glfwPostEmptyEvent();
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyObject*
|
||||
glfw_get_physical_dpi(PyObject UNUSED *self) {
|
||||
GLFWmonitor *m = glfwGetPrimaryMonitor();
|
||||
if (m == NULL) { PyErr_SetString(PyExc_ValueError, "Failed to get primary monitor"); return NULL; }
|
||||
int width = 0, height = 0;
|
||||
glfwGetMonitorPhysicalSize(m, &width, &height);
|
||||
if (width == 0 || height == 0) { PyErr_SetString(PyExc_ValueError, "Failed to get primary monitor size"); return NULL; }
|
||||
const GLFWvidmode *vm = glfwGetVideoMode(m);
|
||||
if (vm == NULL) { PyErr_SetString(PyExc_ValueError, "Failed to get video mode for monitor"); return NULL; }
|
||||
float dpix = vm->width / (width / 25.4);
|
||||
float dpiy = vm->height / (height / 25.4);
|
||||
return Py_BuildValue("ff", dpix, dpiy);
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
static void
|
||||
dealloc(Window* self) {
|
||||
for(unsigned int i = 0; i < MAX_WINDOWS; i++) {
|
||||
if (window_weakrefs[i] == self) window_weakrefs[i] = NULL;
|
||||
}
|
||||
Py_CLEAR(self->framebuffer_size_callback); Py_CLEAR(self->char_mods_callback); Py_CLEAR(self->key_callback); Py_CLEAR(self->mouse_button_callback); Py_CLEAR(self->scroll_callback); Py_CLEAR(self->cursor_pos_callback); Py_CLEAR(self->window_focus_callback);
|
||||
if (self->window != NULL) glfwDestroyWindow(self->window);
|
||||
Py_TYPE(self)->tp_free((PyObject*)self);
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
swap_buffers(Window *self) {
|
||||
glfwSwapBuffers(self->window);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
make_context_current(Window *self) {
|
||||
glfwMakeContextCurrent(self->window);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
should_close(Window *self) {
|
||||
PyObject *ans = glfwWindowShouldClose(self->window) ? Py_True : Py_False;
|
||||
Py_INCREF(ans);
|
||||
return ans;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
get_clipboard_string(Window *self) {
|
||||
return Py_BuildValue("s", glfwGetClipboardString(self->window));
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
set_should_close(Window *self, PyObject *args) {
|
||||
int c;
|
||||
if (!PyArg_ParseTuple(args, "p", &c)) return NULL;
|
||||
glfwSetWindowShouldClose(self->window, c);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
is_key_pressed(Window *self, PyObject *args) {
|
||||
int c;
|
||||
if (!PyArg_ParseTuple(args, "i", &c)) return NULL;
|
||||
PyObject *ans = glfwGetKey(self->window, c) == GLFW_PRESS ? Py_True : Py_False;
|
||||
Py_INCREF(ans);
|
||||
return ans;
|
||||
}
|
||||
|
||||
|
||||
static PyObject*
|
||||
_set_title(Window *self, PyObject *args) {
|
||||
char *title;
|
||||
if(!PyArg_ParseTuple(args, "s", &title)) return NULL;
|
||||
glfwSetWindowTitle(self->window, title);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
// Boilerplate {{{
|
||||
#define MND(name, args) {#name, (PyCFunction)name, args, ""}
|
||||
|
||||
static PyMethodDef methods[] = {
|
||||
MND(swap_buffers, METH_NOARGS),
|
||||
MND(get_clipboard_string, METH_NOARGS),
|
||||
MND(should_close, METH_NOARGS),
|
||||
MND(set_should_close, METH_VARARGS),
|
||||
MND(is_key_pressed, METH_VARARGS),
|
||||
MND(make_context_current, METH_NOARGS),
|
||||
{"set_title", (PyCFunction)_set_title, METH_VARARGS, ""},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
static PyMemberDef members[] = {
|
||||
#define CBE(name) {#name, T_OBJECT_EX, offsetof(Window, name), 0, #name}
|
||||
CBE(framebuffer_size_callback),
|
||||
CBE(char_mods_callback),
|
||||
CBE(key_callback),
|
||||
CBE(mouse_button_callback),
|
||||
CBE(scroll_callback),
|
||||
CBE(cursor_pos_callback),
|
||||
CBE(window_focus_callback),
|
||||
{NULL}
|
||||
#undef CBE
|
||||
};
|
||||
|
||||
PyTypeObject Window_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "fast_data_types.Window",
|
||||
.tp_basicsize = sizeof(Window),
|
||||
.tp_dealloc = (destructor)dealloc,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_doc = "A GLFW window",
|
||||
.tp_methods = methods,
|
||||
.tp_members = members,
|
||||
.tp_new = new,
|
||||
};
|
||||
|
||||
INIT_TYPE(Window)
|
||||
|
||||
|
||||
// constants {{{
|
||||
bool
|
||||
init_glfw(PyObject *m) {
|
||||
@ -336,3 +540,4 @@ return true;
|
||||
#undef ADDC
|
||||
}
|
||||
// }}}
|
||||
// }}}
|
||||
|
||||
@ -15,3 +15,5 @@ PyObject* glfw_terminate(PyObject UNUSED *self);
|
||||
PyObject* glfw_window_hint(PyObject UNUSED *self, PyObject *args);
|
||||
PyObject* glfw_swap_interval(PyObject UNUSED *self, PyObject *args);
|
||||
PyObject* glfw_wait_events(PyObject UNUSED *self);
|
||||
PyObject* glfw_post_empty_event(PyObject UNUSED *self);
|
||||
PyObject* glfw_get_physical_dpi(PyObject UNUSED *self);
|
||||
|
||||
@ -19,9 +19,8 @@ from .fast_data_types import (
|
||||
GLFW_CONTEXT_VERSION_MINOR, GLFW_OPENGL_PROFILE,
|
||||
GLFW_OPENGL_FORWARD_COMPAT, GLFW_OPENGL_CORE_PROFILE, GLFW_SAMPLES,
|
||||
glfw_set_error_callback, glfw_init, glfw_terminate, glfw_window_hint,
|
||||
glfw_swap_interval, glfw_wait_events
|
||||
glfw_swap_interval, glfw_wait_events, Window
|
||||
)
|
||||
import glfw
|
||||
|
||||
|
||||
def option_parser():
|
||||
@ -54,33 +53,29 @@ def clear_buffers(window, opts):
|
||||
glClearColor(bg.red / 255, bg.green / 255, bg.blue / 255, 1)
|
||||
glfw_swap_interval(0)
|
||||
glClear(GL_COLOR_BUFFER_BIT)
|
||||
glfw.glfwSwapBuffers(window)
|
||||
window.swap_buffers()
|
||||
glClear(GL_COLOR_BUFFER_BIT)
|
||||
glfw_swap_interval(1)
|
||||
|
||||
|
||||
def run_app(opts, args):
|
||||
setup_opengl()
|
||||
window = glfw.glfwCreateWindow(
|
||||
viewport_size.width, viewport_size.height, args.cls.encode('utf-8'), None, None)
|
||||
if not window:
|
||||
raise SystemExit("glfwCreateWindow failed")
|
||||
glfw.glfwSetWindowTitle(window, appname.encode('utf-8'))
|
||||
window = Window(
|
||||
viewport_size.width, viewport_size.height, args.cls)
|
||||
window.set_title(appname)
|
||||
window.make_context_current()
|
||||
glewInit()
|
||||
tabs = TabManager(window, opts, args)
|
||||
tabs.start()
|
||||
clear_buffers(window, opts)
|
||||
try:
|
||||
glfw.glfwMakeContextCurrent(window)
|
||||
glewInit()
|
||||
tabs = TabManager(window, opts, args)
|
||||
tabs.start()
|
||||
clear_buffers(window, opts)
|
||||
try:
|
||||
while not glfw.glfwWindowShouldClose(window):
|
||||
tabs.render()
|
||||
glfw.glfwSwapBuffers(window)
|
||||
glfw_wait_events()
|
||||
finally:
|
||||
tabs.destroy()
|
||||
while not window.should_close():
|
||||
tabs.render()
|
||||
window.swap_buffers()
|
||||
glfw_wait_events()
|
||||
finally:
|
||||
glfw.glfwDestroyWindow(window)
|
||||
tabs.destroy()
|
||||
del window
|
||||
|
||||
|
||||
def on_glfw_error(code, msg):
|
||||
|
||||
@ -14,12 +14,11 @@ from threading import Thread
|
||||
from time import monotonic
|
||||
from queue import Queue, Empty
|
||||
|
||||
import glfw
|
||||
from .child import Child
|
||||
from .constants import viewport_size, shell_path, appname, set_tab_manager, tab_manager, wakeup, cell_size, MODIFIER_KEYS
|
||||
from .fast_data_types import (
|
||||
glViewport, glBlendFunc, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GLFW_PRESS,
|
||||
GLFW_REPEAT, GLFW_MOUSE_BUTTON_1
|
||||
GLFW_REPEAT, GLFW_MOUSE_BUTTON_1, glfw_post_empty_event
|
||||
)
|
||||
from .fonts import set_font_family
|
||||
from .borders import Borders, BordersProgram
|
||||
@ -123,13 +122,13 @@ class TabManager(Thread):
|
||||
cell_size.width, cell_size.height = set_font_family(opts.font_family, opts.font_size)
|
||||
self.opts, self.args = opts, args
|
||||
self.glfw_window = glfw_window
|
||||
glfw.glfwSetFramebufferSizeCallback(glfw_window, partial(self.queue_action, self.on_window_resize))
|
||||
glfw.glfwSetCharModsCallback(glfw_window, partial(self.queue_action, self.on_text_input))
|
||||
glfw.glfwSetKeyCallback(glfw_window, partial(self.queue_action, self.on_key))
|
||||
glfw.glfwSetMouseButtonCallback(glfw_window, partial(self.queue_action, self.on_mouse_button))
|
||||
glfw.glfwSetScrollCallback(glfw_window, partial(self.queue_action, self.on_mouse_scroll))
|
||||
glfw.glfwSetCursorPosCallback(glfw_window, partial(self.queue_action, self.on_mouse_move))
|
||||
glfw.glfwSetWindowFocusCallback(glfw_window, partial(self.queue_action, self.on_focus))
|
||||
glfw_window.framebuffer_size_callback = partial(self.queue_action, self.on_window_resize)
|
||||
glfw_window.char_mods_callback = partial(self.queue_action, self.on_text_input)
|
||||
glfw_window.key_callback = partial(self.queue_action, self.on_key)
|
||||
glfw_window.mouse_button_callback = partial(self.queue_action, self.on_mouse_button)
|
||||
glfw_window.scroll_callback = partial(self.queue_action, self.on_mouse_scroll)
|
||||
glfw_window.cursor_pos_callback = partial(self.queue_action, self.on_mouse_move)
|
||||
glfw_window.window_focus_callback = partial(self.queue_action, self.on_focus)
|
||||
self.tabs = deque()
|
||||
self.tabs.append(Tab(opts, args))
|
||||
self.sprites = Sprites()
|
||||
@ -156,8 +155,8 @@ class TabManager(Thread):
|
||||
def shutdown(self):
|
||||
if not self.shutting_down:
|
||||
self.shutting_down = True
|
||||
glfw.glfwSetWindowShouldClose(self.glfw_window, True)
|
||||
glfw.glfwPostEmptyEvent()
|
||||
self.glfw_window.set_should_close(True)
|
||||
glfw_post_empty_event()
|
||||
|
||||
def __iter__(self):
|
||||
yield from iter(self.tabs)
|
||||
@ -277,7 +276,7 @@ class TabManager(Thread):
|
||||
tab.relayout()
|
||||
self.pending_resize = None
|
||||
self.resize_gl_viewport = True
|
||||
glfw.glfwPostEmptyEvent()
|
||||
glfw_post_empty_event()
|
||||
|
||||
@property
|
||||
def active_tab(self):
|
||||
@ -328,19 +327,19 @@ class TabManager(Thread):
|
||||
return w
|
||||
|
||||
def on_mouse_button(self, window, button, action, mods):
|
||||
w = self.window_for_pos(*glfw.glfwGetCursorPos(window))
|
||||
w = self.window_for_pos(*window.get_cursor_pos())
|
||||
if w is not None:
|
||||
if button == GLFW_MOUSE_BUTTON_1 and w is not self.active_window:
|
||||
pass # TODO: Switch focus to this window
|
||||
w.on_mouse_button(window, button, action, mods)
|
||||
|
||||
def on_mouse_move(self, window, xpos, ypos):
|
||||
w = self.window_for_pos(*glfw.glfwGetCursorPos(window))
|
||||
w = self.window_for_pos(*window.get_cursor_pos())
|
||||
if w is not None:
|
||||
w.on_mouse_move(window, xpos, ypos)
|
||||
|
||||
def on_mouse_scroll(self, window, x, y):
|
||||
w = self.window_for_pos(*glfw.glfwGetCursorPos(window))
|
||||
w = self.window_for_pos(*window.get_cursor_pos())
|
||||
if w is not None:
|
||||
w.on_mouse_scroll(window, x, y)
|
||||
|
||||
@ -355,7 +354,7 @@ class TabManager(Thread):
|
||||
if tab is not None:
|
||||
if tab.title != self.glfw_window_title:
|
||||
self.glfw_window_title = tab.title
|
||||
glfw.glfwSetWindowTitle(self.glfw_window, self.glfw_window_title.encode('utf-8'))
|
||||
self.glfw_window.set_title(self.glfw_window_title)
|
||||
with self.sprites:
|
||||
self.sprites.render_dirty_cells()
|
||||
tab.render()
|
||||
|
||||
@ -12,6 +12,7 @@ from contextlib import contextmanager
|
||||
from functools import lru_cache
|
||||
from time import monotonic
|
||||
|
||||
from .fast_data_types import glfw_get_physical_dpi
|
||||
|
||||
libc = ctypes.CDLL(None)
|
||||
wcwidth_native = libc.wcwidth
|
||||
@ -50,14 +51,9 @@ def get_logical_dpi():
|
||||
|
||||
|
||||
def get_dpi():
|
||||
import glfw
|
||||
if not hasattr(get_dpi, 'ans'):
|
||||
m = glfw.glfwGetPrimaryMonitor()
|
||||
width, height = glfw.glfwGetMonitorPhysicalSize(m)
|
||||
vmode = glfw.glfwGetVideoMode(m)
|
||||
dpix = vmode.width / (width / 25.4)
|
||||
dpiy = vmode.height / (height / 25.4)
|
||||
get_dpi.ans = {'physical': (dpix, dpiy), 'logical': get_logical_dpi()}
|
||||
pdpi = glfw_get_physical_dpi()
|
||||
get_dpi.ans = {'physical': pdpi, 'logical': get_logical_dpi()}
|
||||
return get_dpi.ans
|
||||
|
||||
# Color names {{{
|
||||
|
||||
@ -8,14 +8,13 @@ from collections import deque
|
||||
from functools import partial
|
||||
from time import monotonic
|
||||
|
||||
import glfw
|
||||
from .char_grid import CharGrid
|
||||
from .constants import wakeup, tab_manager, appname, WindowGeometry
|
||||
from .fast_data_types import (
|
||||
BRACKETED_PASTE_START, BRACKETED_PASTE_END, Screen, read_bytes_dump,
|
||||
read_bytes, GLFW_MOD_SHIFT, GLFW_MOUSE_BUTTON_1, GLFW_PRESS,
|
||||
GLFW_MOUSE_BUTTON_MIDDLE, GLFW_RELEASE, GLFW_KEY_LEFT_SHIFT,
|
||||
GLFW_KEY_RIGHT_SHIFT
|
||||
GLFW_KEY_RIGHT_SHIFT, glfw_post_empty_event
|
||||
)
|
||||
from .terminfo import get_capabilities
|
||||
from .utils import sanitize_title, get_primary_selection
|
||||
@ -83,7 +82,7 @@ class Window:
|
||||
|
||||
def update_screen(self):
|
||||
self.char_grid.update_cell_data()
|
||||
glfw.glfwPostEmptyEvent()
|
||||
glfw_post_empty_event()
|
||||
|
||||
def focus_changed(self, focused):
|
||||
if focused:
|
||||
@ -95,7 +94,7 @@ class Window:
|
||||
|
||||
def title_changed(self, new_title):
|
||||
self.title = sanitize_title(new_title or appname)
|
||||
glfw.glfwPostEmptyEvent()
|
||||
glfw_post_empty_event()
|
||||
|
||||
def icon_changed(self, new_icon):
|
||||
pass # TODO: Implement this
|
||||
@ -113,7 +112,7 @@ class Window:
|
||||
color_changes[w] = val
|
||||
code += 1
|
||||
self.char_grid.change_colors(color_changes)
|
||||
glfw.glfwPostEmptyEvent()
|
||||
glfw_post_empty_event()
|
||||
|
||||
def request_capabilities(self, q):
|
||||
self.write_to_child(get_capabilities(q))
|
||||
@ -121,16 +120,16 @@ class Window:
|
||||
def dispatch_multi_click(self, x, y):
|
||||
if len(self.click_queue) > 2 and self.click_queue[-1] - self.click_queue[-3] <= 2 * self.opts.click_interval:
|
||||
self.char_grid.multi_click(3, x, y)
|
||||
glfw.glfwPostEmptyEvent()
|
||||
glfw_post_empty_event()
|
||||
elif len(self.click_queue) > 1 and self.click_queue[-1] - self.click_queue[-2] <= self.opts.click_interval:
|
||||
self.char_grid.multi_click(2, x, y)
|
||||
glfw.glfwPostEmptyEvent()
|
||||
glfw_post_empty_event()
|
||||
|
||||
def on_mouse_button(self, window, button, action, mods):
|
||||
handle_event = mods == GLFW_MOD_SHIFT or not self.screen.mouse_button_tracking_enabled()
|
||||
if handle_event:
|
||||
if button == GLFW_MOUSE_BUTTON_1:
|
||||
x, y = glfw.glfwGetCursorPos(window)
|
||||
x, y = window.get_cursor_pos()
|
||||
x, y = max(0, x - self.geometry.left), max(0, y - self.geometry.top)
|
||||
self.char_grid.update_drag(action == GLFW_PRESS, x, y)
|
||||
if action == GLFW_RELEASE:
|
||||
@ -140,7 +139,7 @@ class Window:
|
||||
if action == GLFW_RELEASE:
|
||||
self.paste_from_selection()
|
||||
else:
|
||||
x, y = glfw.glfwGetCursorPos(window)
|
||||
x, y = window.get_cursor_pos()
|
||||
x, y = max(0, x - self.geometry.left), max(0, y - self.geometry.top)
|
||||
x, y = self.char_grid.cell_for_pos(x, y)
|
||||
|
||||
@ -150,14 +149,14 @@ class Window:
|
||||
|
||||
def on_mouse_scroll(self, window, x, y):
|
||||
handle_event = (
|
||||
glfw.glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS or
|
||||
glfw.glfwGetKey(window, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS or
|
||||
window.is_key_pressed(GLFW_KEY_LEFT_SHIFT) or
|
||||
window.is_key_pressed(GLFW_KEY_RIGHT_SHIFT) or
|
||||
not self.screen.mouse_button_tracking_enabled())
|
||||
if handle_event:
|
||||
s = int(round(y * self.opts.wheel_scroll_multiplier))
|
||||
if abs(s) > 0:
|
||||
self.char_grid.scroll(abs(s), s > 0)
|
||||
glfw.glfwPostEmptyEvent()
|
||||
glfw_post_empty_event()
|
||||
|
||||
# actions {{{
|
||||
|
||||
@ -170,9 +169,9 @@ class Window:
|
||||
self.write_to_child(text)
|
||||
|
||||
def paste_from_clipboard(self):
|
||||
text = glfw.glfwGetClipboardString(tab_manager().glfw_window)
|
||||
text = tab_manager().glfw_window.get_clipboard_string()
|
||||
if text:
|
||||
self.paste(text.decode('utf-8'))
|
||||
self.paste(text)
|
||||
|
||||
def paste_from_selection(self):
|
||||
text = get_primary_selection()
|
||||
@ -183,27 +182,27 @@ class Window:
|
||||
|
||||
def scroll_line_up(self):
|
||||
self.char_grid.scroll('line', True)
|
||||
glfw.glfwPostEmptyEvent()
|
||||
glfw_post_empty_event()
|
||||
|
||||
def scroll_line_down(self):
|
||||
self.char_grid.scroll('line', False)
|
||||
glfw.glfwPostEmptyEvent()
|
||||
glfw_post_empty_event()
|
||||
|
||||
def scroll_page_up(self):
|
||||
self.char_grid.scroll('page', True)
|
||||
glfw.glfwPostEmptyEvent()
|
||||
glfw_post_empty_event()
|
||||
|
||||
def scroll_page_down(self):
|
||||
self.char_grid.scroll('page', False)
|
||||
glfw.glfwPostEmptyEvent()
|
||||
glfw_post_empty_event()
|
||||
|
||||
def scroll_home(self):
|
||||
self.char_grid.scroll('full', True)
|
||||
glfw.glfwPostEmptyEvent()
|
||||
glfw_post_empty_event()
|
||||
|
||||
def scroll_end(self):
|
||||
self.char_grid.scroll('full', False)
|
||||
glfw.glfwPostEmptyEvent()
|
||||
glfw_post_empty_event()
|
||||
# }}}
|
||||
|
||||
def dump_commands(self, *a):
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user