From a27004da35e3021ee280f2ded0abbebe3542aaa2 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 14 Sep 2017 13:53:24 +0530 Subject: [PATCH] Port drag select to C --- kitty/data-types.c | 7 ------- kitty/data-types.h | 12 ++++-------- kitty/glfw.c | 5 +++++ kitty/mouse.c | 37 +++++++++++++++++++++++++++++++------ kitty/mouse.py | 4 ++-- kitty/screen.c | 20 -------------------- kitty/state.h | 3 +++ kitty/window.py | 7 ++++--- 8 files changed, 49 insertions(+), 46 deletions(-) diff --git a/kitty/data-types.c b/kitty/data-types.c index 6f1c5590b..8a59b334a 100644 --- a/kitty/data-types.c +++ b/kitty/data-types.c @@ -197,13 +197,6 @@ PyInit_fast_data_types(void) { PyModule_AddIntMacro(m, DECCOLM); PyModule_AddIntMacro(m, DECOM); PyModule_AddIntMacro(m, IRM); - PyModule_AddIntMacro(m, ANY_MODE); - PyModule_AddIntMacro(m, MOTION_MODE); - PyModule_AddIntMacro(m, BUTTON_MODE); - PyModule_AddIntMacro(m, SGR_PROTOCOL); - PyModule_AddIntMacro(m, NORMAL_PROTOCOL); - PyModule_AddIntMacro(m, URXVT_PROTOCOL); - PyModule_AddIntMacro(m, UTF8_PROTOCOL); } return m; diff --git a/kitty/data-types.h b/kitty/data-types.h index 1567ff93a..84a605c95 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -32,13 +32,8 @@ typedef uint16_t sprite_index; typedef enum CursorShapes { NO_CURSOR_SHAPE, CURSOR_BLOCK, CURSOR_BEAM, CURSOR_UNDERLINE, NUM_OF_CURSOR_SHAPES } CursorShape; #define ERROR_PREFIX "[PARSE ERROR]" -#define ANY_MODE 3 -#define MOTION_MODE 2 -#define BUTTON_MODE 1 -#define NORMAL_PROTOCOL 0 -#define UTF8_PROTOCOL 1 -#define SGR_PROTOCOL 2 -#define URXVT_PROTOCOL 3 +typedef enum MouseTrackingModes { NO_TRACKING, BUTTON_MODE, MOTION_MODE, ANY_MODE } MouseTrackingMode; +typedef enum MouseTrackingProtocols { NORMAL_PROTOCOL, UTF8_PROTOCOL, SGR_PROTOCOL, URXVT_PROTOCOL} MouseTrackingProtocol; #define MAX_CHILDREN 256 #define BLANK_CHAR 0 @@ -197,7 +192,8 @@ PyTypeObject ColorProfile_Type; typedef struct { bool mLNM, mIRM, mDECTCEM, mDECSCNM, mDECOM, mDECAWM, mDECCOLM, mDECARM, mDECCKM, mBRACKETED_PASTE, mFOCUS_TRACKING, mEXTENDED_KEYBOARD; - unsigned long mouse_tracking_mode, mouse_tracking_protocol; + MouseTrackingMode mouse_tracking_mode; + MouseTrackingProtocol mouse_tracking_protocol; } ScreenModes; PyTypeObject ScreenModes_Type; diff --git a/kitty/glfw.c b/kitty/glfw.c index ada3920ca..1c5d79652 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -16,6 +16,10 @@ #error "glfw >= 3.2 required" #endif +#if GLFW_KEY_LAST >= MAX_KEY_COUNT +#error "glfw has too many keys, you should increase MAX_KEY_COUNT" +#endif + #define MAX_WINDOWS 256 #define CALLBACK(name, fmt, ...) \ @@ -59,6 +63,7 @@ char_mods_callback(GLFWwindow UNUSED *w, unsigned int codepoint, int mods) { static void key_callback(GLFWwindow UNUSED *w, int key, int scancode, int action, int mods) { global_state.cursor_blink_zero_time = monotonic(); + if (key >= 0 && key <= GLFW_KEY_LAST) global_state.is_key_pressed[key] = action == GLFW_RELEASE ? false : true; WINDOW_CALLBACK(key_callback, "iiii", key, scancode, action, mods); } diff --git a/kitty/mouse.c b/kitty/mouse.c index c666b2813..0990aa730 100644 --- a/kitty/mouse.c +++ b/kitty/mouse.c @@ -40,14 +40,37 @@ cell_for_pos(Window *w, unsigned int *x, unsigned int *y) { #define HANDLER(name) static inline void name(Window UNUSED *w, int UNUSED button, int UNUSED modifiers, unsigned int UNUSED window_idx) +static inline void +update_drag(bool from_button, Window *w, bool is_release) { + Screen *screen = w->render_data.screen; + if (from_button) { + if (is_release) screen_update_selection(screen, w->mouse_cell_x, w->mouse_cell_y, true); + else screen_start_selection(screen, w->mouse_cell_x, w->mouse_cell_y); + } else if (screen->selection.in_progress) { + screen_update_selection(screen, w->mouse_cell_x, w->mouse_cell_y, false); + call_boss(set_primary_selection, NULL); + } +} + HANDLER(handle_move_event) { unsigned int x, y; - if (cell_for_pos(w, &x, &y)) { - Line *line = screen_visual_line(w->render_data.screen, y); - has_click_cursor = (line && line_url_start_at(line, x) < line->xnum) ? true : false; - if (x != w->mouse_cell_x || y != w->mouse_cell_y) { - w->mouse_cell_x = x; w->mouse_cell_y = y; + if (!cell_for_pos(w, &x, &y)) return; + Line *line = screen_visual_line(w->render_data.screen, y); + has_click_cursor = (line && line_url_start_at(line, x) < line->xnum) ? true : false; + if (x == w->mouse_cell_x && y == w->mouse_cell_y) return; + w->mouse_cell_x = x; w->mouse_cell_y = y; + Screen *screen = w->render_data.screen; + bool handle_in_kitty = ( + (screen->modes.mouse_tracking_mode == ANY_MODE || + (screen->modes.mouse_tracking_mode == MOTION_MODE && button >= 0)) && + !(global_state.is_key_pressed[GLFW_KEY_LEFT_SHIFT] || global_state.is_key_pressed[GLFW_KEY_RIGHT_SHIFT]) + ) ? false : true; + if (handle_in_kitty) { + if (screen->selection.in_progress && button == GLFW_MOUSE_BUTTON_LEFT) { + update_drag(false, w, false); } + } else { + // TODO: Implement this } } @@ -107,7 +130,7 @@ HANDLER(handle_button_event) { if (handle_in_kitty) { switch(button) { case GLFW_MOUSE_BUTTON_LEFT: - // TODO: update_drag + update_drag(true, w, is_release); if (is_release) { if (modifiers == (int)OPT(open_url_modifiers)) { // TODO: click_url @@ -121,12 +144,14 @@ HANDLER(handle_button_event) { break; } } else { + // TODO: Implement this } } HANDLER(handle_event) { switch(button) { case -1: + for (int i = 0; i < GLFW_MOUSE_BUTTON_5; i++) { if (global_state.mouse_button_pressed[i]) { button = i; break; } } handle_move_event(w, button, modifiers, window_idx); break; case GLFW_MOUSE_BUTTON_LEFT: diff --git a/kitty/mouse.py b/kitty/mouse.py index 704110634..623daf244 100644 --- a/kitty/mouse.py +++ b/kitty/mouse.py @@ -4,8 +4,8 @@ from .fast_data_types import ( GLFW_MOUSE_BUTTON_2, GLFW_MOUSE_BUTTON_3, GLFW_MOD_ALT, GLFW_MOD_CONTROL, - GLFW_MOD_SHIFT, GLFW_MOUSE_BUTTON_4, GLFW_MOUSE_BUTTON_5, SGR_PROTOCOL, - GLFW_MOUSE_BUTTON_1, URXVT_PROTOCOL, UTF8_PROTOCOL + GLFW_MOD_SHIFT, GLFW_MOUSE_BUTTON_4, GLFW_MOUSE_BUTTON_5, + GLFW_MOUSE_BUTTON_1, ) PRESS, RELEASE, DRAG, MOVE = range(4) diff --git a/kitty/screen.c b/kitty/screen.c index de58e0d33..c26ca4729 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -1283,16 +1283,6 @@ MODE_GETSET(auto_repeat_enabled, DECARM) MODE_GETSET(cursor_visible, DECTCEM) MODE_GETSET(cursor_key_mode, DECCKM) -static PyObject* -mouse_tracking_mode(Screen *self) { - return PyLong_FromUnsignedLong(self->modes.mouse_tracking_mode); -} - -static PyObject* -mouse_tracking_protocol(Screen *self) { - return PyLong_FromUnsignedLong(self->modes.mouse_tracking_protocol); -} - static PyObject* cursor_up(Screen *self, PyObject *args) { unsigned int count = 1; @@ -1417,13 +1407,6 @@ scroll(Screen *self, PyObject *args) { Py_RETURN_FALSE; } -static PyObject* -is_selection_in_progress(Screen *self) { - PyObject *ans = self->selection.in_progress ? Py_True : Py_False; - Py_INCREF(ans); - return ans; -} - bool screen_is_selection_dirty(Screen *self) { SelectionBoundary start, end; @@ -1507,8 +1490,6 @@ static PyMethodDef methods[] = { MND(change_scrollback_size, METH_VARARGS) MND(erase_characters, METH_VARARGS) MND(cursor_up, METH_VARARGS) - MND(mouse_tracking_mode, METH_NOARGS) - MND(mouse_tracking_protocol, METH_NOARGS) MND(cursor_up1, METH_VARARGS) MND(cursor_down, METH_VARARGS) MND(cursor_down1, METH_VARARGS) @@ -1526,7 +1507,6 @@ static PyMethodDef methods[] = { MND(resize, METH_VARARGS) MND(set_margins, METH_VARARGS) MND(text_for_selection, METH_NOARGS) - MND(is_selection_in_progress, METH_NOARGS) MND(scroll, METH_VARARGS) MND(toggle_alt_screen, METH_NOARGS) MND(reset_callbacks, METH_NOARGS) diff --git a/kitty/state.h b/kitty/state.h index f78b0b746..d161d8aa7 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -53,6 +53,8 @@ typedef struct { Window windows[MAX_CHILDREN]; } Tab; +#define MAX_KEY_COUNT 512 + typedef struct { Options opts; @@ -68,6 +70,7 @@ typedef struct { unsigned int cell_width, cell_height; PyObject *application_title; PyObject *boss; + bool is_key_pressed[MAX_KEY_COUNT]; } GlobalState; extern GlobalState global_state; diff --git a/kitty/window.py b/kitty/window.py index 8cdcac4af..9832d4c2c 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -16,11 +16,11 @@ from .constants import ( is_key_pressed, mouse_button_pressed, viewport_size, wakeup ) from .fast_data_types import ( - ANY_MODE, BRACKETED_PASTE_END, BRACKETED_PASTE_START, CELL_PROGRAM, + BRACKETED_PASTE_END, BRACKETED_PASTE_START, CELL_PROGRAM, CURSOR_PROGRAM, GLFW_KEY_DOWN, GLFW_KEY_LEFT_SHIFT, GLFW_KEY_RIGHT_SHIFT, GLFW_KEY_UP, GLFW_MOD_SHIFT, GLFW_MOUSE_BUTTON_1, GLFW_MOUSE_BUTTON_4, GLFW_MOUSE_BUTTON_5, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS, GLFW_RELEASE, - MOTION_MODE, SCROLL_FULL, SCROLL_LINE, SCROLL_PAGE, Screen, + SCROLL_FULL, SCROLL_LINE, SCROLL_PAGE, Screen, compile_program, create_cell_vao, glfw_post_empty_event, init_cell_program, init_cursor_program, remove_vao, set_window_render_data, update_window_title, update_window_visibility @@ -350,14 +350,15 @@ class Window: if mouse_button_pressed[b]: button = b break - action = MOVE if button is None else DRAG mode = self.screen.mouse_tracking_mode() + ANY_MODE, MOTION_MODE = 3, 2 send_event = (mode == ANY_MODE or (mode == MOTION_MODE and button is not None)) and not ( is_key_pressed[GLFW_KEY_LEFT_SHIFT] or is_key_pressed[GLFW_KEY_RIGHT_SHIFT]) x, y = max(0, x - self.geometry.left), max(0, y - self.geometry.top) self.last_mouse_cursor_pos = x, y get_boss().change_mouse_cursor(self.has_url_at(x, y)) if send_event: + action = MOVE if button is None else DRAG x, y = self.cell_for_pos(x, y) if x is not None: ev = encode_mouse_event(mode, self.screen.mouse_tracking_protocol(),