Merge branch 'remove-sdl'
This commit is contained in:
commit
a509c4bded
@ -170,6 +170,8 @@ bool BufferView::cursor_move(CursorMovement which, bool allow_eol)
|
||||
{
|
||||
case CursorMovement::LEFT:
|
||||
case CursorMovement::RIGHT:
|
||||
case CursorMovement::SCREEN_ROW_UP:
|
||||
case CursorMovement::SCREEN_ROW_DOWN:
|
||||
determine_new_cursor_screen_row();
|
||||
break;
|
||||
case CursorMovement::UP:
|
||||
|
@ -201,8 +201,8 @@ void BufferPane::draw_buffer_character(uint32_t character, int screen_row, int s
|
||||
m_window->gl()->draw_rect(win_x(x + 2), win_y(y),
|
||||
m_window->font()->get_advance() * 2 - 4, 1,
|
||||
0, 0.7, 1.0, 1.0);
|
||||
m_window->gl()->draw_character(win_x(x), win_y(y), '^', *m_window->font(), 1.0, 1.0, 1.0, 1.0);
|
||||
m_window->gl()->draw_character(win_x(col_x(screen_column + 1)), win_y(y), character | 0x40u, *m_window->font(), 1.0, 1.0, 1.0, 1.0);
|
||||
m_window->gl()->draw_character(win_x(x), win_y(y), '^', *m_window->font(), 0.0, 0.7, 1.0, 1.0);
|
||||
m_window->gl()->draw_character(win_x(col_x(screen_column + 1)), win_y(y), character | 0x40u, *m_window->font(), 0.0, 0.7, 1.0, 1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -4,44 +4,16 @@
|
||||
#include "BufferPane.h"
|
||||
#include <iostream>
|
||||
#include "jes_icon-32x32.h"
|
||||
#include <unistd.h>
|
||||
#include <unordered_map>
|
||||
|
||||
#define INITIAL_WIDTH 800
|
||||
#define INITIAL_HEIGHT 800
|
||||
#define FONT_SIZE 16
|
||||
|
||||
struct
|
||||
{
|
||||
SDL_TimerID timer_id;
|
||||
SDL_Keycode keysym;
|
||||
bool pressed;
|
||||
bool event_pending;
|
||||
} Key_Statuses[SDL_NUM_SCANCODES];
|
||||
|
||||
/**
|
||||
* Initialize SDL.
|
||||
*
|
||||
* @retval true SDL was loaded successfully.
|
||||
* @retval false Loading SDL failed.
|
||||
*/
|
||||
static bool Initialize_SDL()
|
||||
{
|
||||
static bool initialized = false;
|
||||
|
||||
if (initialized)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
atexit(SDL_Quit);
|
||||
|
||||
initialized = true;
|
||||
return true;
|
||||
}
|
||||
/* Process multiple queued events for up to this long before stopping to
|
||||
* redraw the screen. */
|
||||
#define MAX_EVENT_PROCESS_TIME 50000
|
||||
|
||||
/**
|
||||
* Initialize OpenGL.
|
||||
@ -80,6 +52,7 @@ static bool Initialize_OpenGL()
|
||||
return true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void Window::set_window_icon()
|
||||
{
|
||||
SDL_Surface * surface = SDL_CreateRGBSurfaceFrom((void *)jes_icon_32x32, 32, 32, 24, 32 * 3, 0xFF0000u, 0xFF00u, 0xFFu, 0u);
|
||||
@ -88,6 +61,7 @@ void Window::set_window_icon()
|
||||
|
||||
SDL_FreeSurface(surface);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Create a Window.
|
||||
@ -97,28 +71,23 @@ void Window::set_window_icon()
|
||||
*/
|
||||
bool Window::create(std::shared_ptr<Buffer> buffer)
|
||||
{
|
||||
if (!Initialize_SDL())
|
||||
if (!Jtk_Init())
|
||||
{
|
||||
std::cerr << "Error initializing SDL" << std::endl;
|
||||
std::cerr << "Error initializing GUI" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_window = SDL_CreateWindow(
|
||||
APPNAME,
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
INITIAL_WIDTH,
|
||||
INITIAL_HEIGHT,
|
||||
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
|
||||
m_window = Jtk_CreateWindow();
|
||||
if (m_window == NULL)
|
||||
{
|
||||
std::cerr << "Error creating SDL window" << std::endl;
|
||||
std::cerr << "Error creating window" << std::endl;
|
||||
return false;
|
||||
}
|
||||
Jtk_SetWindowTitle(m_window, "jes");
|
||||
|
||||
#if 0
|
||||
set_window_icon();
|
||||
|
||||
(void)SDL_GL_CreateContext(m_window);
|
||||
#endif
|
||||
|
||||
if (!Initialize_OpenGL())
|
||||
{
|
||||
@ -157,7 +126,9 @@ bool Window::create(std::shared_ptr<Buffer> buffer)
|
||||
m_command_buffer_pane->set_command_mode();
|
||||
m_command_buffer_screen_rows = 1;
|
||||
|
||||
resize();
|
||||
resize(INITIAL_WIDTH, INITIAL_HEIGHT);
|
||||
|
||||
m_redraw_requested = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -169,76 +140,60 @@ bool Window::create(std::shared_ptr<Buffer> buffer)
|
||||
*/
|
||||
void Window::run_event_loop()
|
||||
{
|
||||
SDL_Event event;
|
||||
Jtk_Event event;
|
||||
|
||||
while ((!m_exit_requested) && SDL_WaitEvent(&event))
|
||||
while (!m_exit_requested)
|
||||
{
|
||||
handle_event(event);
|
||||
if (m_redraw_requested)
|
||||
{
|
||||
m_redraw_requested = false;
|
||||
redraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Uint32 Key_Repeat(Uint32 interval, void * param)
|
||||
Jtk_WaitEvent(&event);
|
||||
uint64_t event_time = Jtk_UsTime();
|
||||
handle_event(event);
|
||||
while (Jtk_CheckEvent(&event) &&
|
||||
((Jtk_UsTime() - event_time) < MAX_EVENT_PROCESS_TIME))
|
||||
{
|
||||
if (Key_Statuses[(uintptr_t)param].pressed)
|
||||
{
|
||||
if (!Key_Statuses[(uintptr_t)param].event_pending)
|
||||
{
|
||||
SDL_Event event;
|
||||
|
||||
event.user.code = 0;
|
||||
event.user.data1 = (void *)(uintptr_t)Key_Statuses[(uintptr_t)param].keysym;
|
||||
event.user.data2 = param;
|
||||
event.type = SDL_USEREVENT;
|
||||
|
||||
SDL_PushEvent(&event);
|
||||
Key_Statuses[(uintptr_t)param].event_pending = true;
|
||||
handle_event(event);
|
||||
}
|
||||
|
||||
return 25u;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0u;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a SDL event.
|
||||
* Handle a Jtk event.
|
||||
*/
|
||||
void Window::handle_event(SDL_Event & event)
|
||||
void Window::handle_event(Jtk_Event & event)
|
||||
{
|
||||
switch (event.type)
|
||||
{
|
||||
#if 0
|
||||
case SDL_QUIT:
|
||||
m_exit_requested = true;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case SDL_KEYDOWN:
|
||||
m_keymod = event.key.keysym.mod;
|
||||
if (event.key.repeat == 0)
|
||||
case JTK_EVENT_KEY_PRESS:
|
||||
#if 0
|
||||
if (!event.key.repeat)
|
||||
{
|
||||
Key_Statuses[event.key.keysym.scancode].pressed = true;
|
||||
Key_Statuses[event.key.keysym.scancode].keysym = event.key.keysym.sym;
|
||||
Key_Statuses[event.key.keysym.scancode].timer_id = SDL_AddTimer(300, Key_Repeat, (void *)event.key.keysym.scancode);
|
||||
handle_keysym(event.key.keysym.sym);
|
||||
Jtk_BeginKeyRepeat(&event.key, 300u, 25u);
|
||||
}
|
||||
#endif
|
||||
handle_keypress(event.key.key);
|
||||
m_redraw_requested = true;
|
||||
break;
|
||||
|
||||
case SDL_KEYUP:
|
||||
m_keymod = event.key.keysym.mod;
|
||||
Key_Statuses[event.key.keysym.scancode].pressed = false;
|
||||
if (Key_Statuses[event.key.keysym.scancode].timer_id != 0)
|
||||
{
|
||||
SDL_RemoveTimer(Key_Statuses[event.key.keysym.scancode].timer_id);
|
||||
Key_Statuses[event.key.keysym.scancode].timer_id = 0;
|
||||
}
|
||||
case JTK_EVENT_WINDOW_EXPOSE:
|
||||
m_redraw_requested = true;
|
||||
break;
|
||||
|
||||
case JTK_EVENT_WINDOW_RESIZE:
|
||||
resize(event.resize.width, event.resize.height);
|
||||
m_redraw_requested = true;
|
||||
break;
|
||||
|
||||
#if 0
|
||||
case SDL_WINDOWEVENT:
|
||||
switch (event.window.event)
|
||||
{
|
||||
@ -251,18 +206,14 @@ void Window::handle_event(SDL_Event & event)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case SDL_USEREVENT:
|
||||
Key_Statuses[(uintptr_t)event.user.data2].event_pending = false;
|
||||
handle_keysym((uint32_t)(uintptr_t)event.user.data1);
|
||||
break;
|
||||
|
||||
case SDL_MOUSEWHEEL:
|
||||
if (event.wheel.y > 0)
|
||||
case JTK_EVENT_BUTTON_PRESS:
|
||||
if (event.button.button == 4)
|
||||
{
|
||||
m_focused_buffer_pane->scroll_window_up(ScrollMode::WHEEL);
|
||||
}
|
||||
else
|
||||
else if (event.button.button == 5)
|
||||
{
|
||||
m_focused_buffer_pane->scroll_window_down(ScrollMode::WHEEL);
|
||||
}
|
||||
@ -270,43 +221,39 @@ void Window::handle_event(SDL_Event & event)
|
||||
}
|
||||
}
|
||||
|
||||
void Window::handle_keysym(uint32_t keysym)
|
||||
void Window::handle_keypress(uint32_t keyval)
|
||||
{
|
||||
handle_keyval(get_keyval(keysym));
|
||||
}
|
||||
|
||||
void Window::handle_keyval(uint32_t keyval)
|
||||
uint32_t keycode = keyval & JTK_KEY_KEYCODE_MASK;
|
||||
switch (keyval & (JTK_KEY_KEYCODE_MASK | JTK_KEY_MODS_CTRL))
|
||||
{
|
||||
switch (keyval)
|
||||
{
|
||||
case SDLK_HOME:
|
||||
case JTK_KEY_HOME:
|
||||
m_focused_buffer_pane->cursor_move(BufferPane::CursorMovement::SOL);
|
||||
break;
|
||||
case SDLK_END:
|
||||
case JTK_KEY_END:
|
||||
m_focused_buffer_pane->cursor_move(BufferPane::CursorMovement::EOL);
|
||||
break;
|
||||
case SDLK_RIGHT:
|
||||
case JTK_KEY_RIGHT:
|
||||
m_focused_buffer_pane->cursor_move(BufferPane::CursorMovement::RIGHT);
|
||||
break;
|
||||
case SDLK_LEFT:
|
||||
case JTK_KEY_LEFT:
|
||||
m_focused_buffer_pane->cursor_move(BufferPane::CursorMovement::LEFT);
|
||||
break;
|
||||
case SDLK_DOWN:
|
||||
case JTK_KEY_DOWN:
|
||||
m_focused_buffer_pane->cursor_move(BufferPane::CursorMovement::DOWN);
|
||||
break;
|
||||
case SDLK_UP:
|
||||
case JTK_KEY_UP:
|
||||
m_focused_buffer_pane->cursor_move(BufferPane::CursorMovement::UP);
|
||||
break;
|
||||
case SDLK_PAGEUP:
|
||||
case JTK_KEY_PAGE_UP:
|
||||
m_focused_buffer_pane->scroll_window_up(ScrollMode::WHOLE_SCREEN);
|
||||
break;
|
||||
case SDLK_PAGEDOWN:
|
||||
case JTK_KEY_PAGE_DOWN:
|
||||
m_focused_buffer_pane->scroll_window_down(ScrollMode::WHOLE_SCREEN);
|
||||
break;
|
||||
default:
|
||||
if (m_focused_buffer_pane->insert_mode())
|
||||
{
|
||||
if (keyval == '\033')
|
||||
if (keycode == '\033')
|
||||
{
|
||||
if (m_focused_buffer_pane == m_command_buffer_pane)
|
||||
{
|
||||
@ -319,9 +266,9 @@ void Window::handle_keyval(uint32_t keyval)
|
||||
m_focused_buffer_pane->exit_insert_mode();
|
||||
}
|
||||
}
|
||||
else if (keyval < 0xFFu)
|
||||
else if (keycode < 0xFFu)
|
||||
{
|
||||
if ((keyval == '\n') && (m_focused_buffer_pane == m_command_buffer_pane))
|
||||
if ((keycode == '\n') && (m_focused_buffer_pane == m_command_buffer_pane))
|
||||
{
|
||||
EncodedString command = m_command_buffer->get_string();
|
||||
m_command_buffer_pane->clear();
|
||||
@ -331,13 +278,13 @@ void Window::handle_keyval(uint32_t keyval)
|
||||
}
|
||||
else
|
||||
{
|
||||
m_focused_buffer_pane->insert_code_point(keyval);
|
||||
m_focused_buffer_pane->insert_code_point(keycode);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (keyval)
|
||||
switch (keyval & (JTK_KEY_KEYCODE_MASK | JTK_KEY_MODS_CTRL))
|
||||
{
|
||||
case '0':
|
||||
m_focused_buffer_pane->cursor_move(BufferPane::CursorMovement::SOL);
|
||||
@ -400,22 +347,22 @@ void Window::handle_keyval(uint32_t keyval)
|
||||
case 'x':
|
||||
m_focused_buffer_pane->kill_character_at_cursor();
|
||||
break;
|
||||
case Keymod::CTRL + 'b':
|
||||
case JTK_KEY_MODS_CTRL + 'b':
|
||||
m_focused_buffer_pane->scroll_window_up(ScrollMode::WHOLE_SCREEN);
|
||||
break;
|
||||
case Keymod::CTRL + 'd':
|
||||
case JTK_KEY_MODS_CTRL + 'd':
|
||||
m_focused_buffer_pane->scroll_window_down(ScrollMode::HALF_SCREEN);
|
||||
break;
|
||||
case Keymod::CTRL + 'e':
|
||||
case JTK_KEY_MODS_CTRL + 'e':
|
||||
m_focused_buffer_pane->scroll_window_down(ScrollMode::ONE_LINE);
|
||||
break;
|
||||
case Keymod::CTRL + 'f':
|
||||
case JTK_KEY_MODS_CTRL + 'f':
|
||||
m_focused_buffer_pane->scroll_window_down(ScrollMode::WHOLE_SCREEN);
|
||||
break;
|
||||
case Keymod::CTRL + 'u':
|
||||
case JTK_KEY_MODS_CTRL + 'u':
|
||||
m_focused_buffer_pane->scroll_window_up(ScrollMode::HALF_SCREEN);
|
||||
break;
|
||||
case Keymod::CTRL + 'y':
|
||||
case JTK_KEY_MODS_CTRL + 'y':
|
||||
m_focused_buffer_pane->scroll_window_up(ScrollMode::ONE_LINE);
|
||||
break;
|
||||
}
|
||||
@ -424,9 +371,10 @@ void Window::handle_keyval(uint32_t keyval)
|
||||
}
|
||||
}
|
||||
|
||||
void Window::resize()
|
||||
void Window::resize(size_t width, size_t height)
|
||||
{
|
||||
SDL_GetWindowSize(m_window, &m_width, &m_height);
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
glViewport(0, 0, m_width, m_height);
|
||||
m_gl->resize(m_width, m_height);
|
||||
int command_buffer_height = m_command_buffer_screen_rows * m_font->get_line_height();
|
||||
@ -443,7 +391,7 @@ void Window::redraw()
|
||||
m_command_buffer_screen_rows = 1;
|
||||
if (m_command_buffer_screen_rows != last_command_buffer_screen_rows)
|
||||
{
|
||||
resize();
|
||||
resize(m_width, m_height);
|
||||
}
|
||||
last_command_buffer_screen_rows = m_command_buffer_screen_rows;
|
||||
|
||||
@ -453,112 +401,7 @@ void Window::redraw()
|
||||
m_gl->draw_rect(0, m_command_buffer_screen_rows * m_font->get_line_height(), m_width, 1, 0.5, 0.5, 0.5, 1.0);
|
||||
m_command_buffer_pane->draw();
|
||||
|
||||
SDL_GL_SwapWindow(m_window);
|
||||
}
|
||||
|
||||
uint32_t Window::get_keyval(SDL_Keycode keysym)
|
||||
{
|
||||
uint32_t keyval = keysym;
|
||||
if ((m_keymod & (KMOD_SHIFT | KMOD_CAPS)) != 0u)
|
||||
{
|
||||
uint32_t shifted = get_shifted(keyval);
|
||||
if (shifted != 0u)
|
||||
{
|
||||
keyval = shifted;
|
||||
}
|
||||
else
|
||||
{
|
||||
keyval |= Keymod::SHIFT;
|
||||
}
|
||||
}
|
||||
switch (keyval)
|
||||
{
|
||||
case SDLK_RETURN: keyval = '\n'; break;
|
||||
case SDLK_KP_DIVIDE: keyval = '/'; break;
|
||||
case SDLK_KP_MULTIPLY: keyval = '*'; break;
|
||||
case SDLK_KP_MINUS: keyval = '-'; break;
|
||||
case SDLK_KP_PLUS: keyval = '+'; break;
|
||||
case SDLK_KP_ENTER: keyval = '\n'; break;
|
||||
case SDLK_KP_1: keyval = '1'; break;
|
||||
case SDLK_KP_2: keyval = '2'; break;
|
||||
case SDLK_KP_3: keyval = '3'; break;
|
||||
case SDLK_KP_4: keyval = '4'; break;
|
||||
case SDLK_KP_5: keyval = '5'; break;
|
||||
case SDLK_KP_6: keyval = '6'; break;
|
||||
case SDLK_KP_7: keyval = '7'; break;
|
||||
case SDLK_KP_8: keyval = '8'; break;
|
||||
case SDLK_KP_9: keyval = '9'; break;
|
||||
case SDLK_KP_0: keyval = '0'; break;
|
||||
case SDLK_KP_PERIOD: keyval = '.'; break;
|
||||
case SDLK_KP_EQUALS: keyval = '='; break;
|
||||
case SDLK_KP_COMMA: keyval = ','; break;
|
||||
case SDLK_KP_LEFTPAREN: keyval = '('; break;
|
||||
case SDLK_KP_RIGHTPAREN: keyval = ')'; break;
|
||||
case SDLK_KP_LEFTBRACE: keyval = '{'; break;
|
||||
case SDLK_KP_RIGHTBRACE: keyval = '}'; break;
|
||||
case SDLK_KP_TAB: keyval = '\t'; break;
|
||||
case SDLK_KP_BACKSPACE: keyval = '\b'; break;
|
||||
case SDLK_KP_PERCENT: keyval = '%'; break;
|
||||
case SDLK_KP_LESS: keyval = '<'; break;
|
||||
case SDLK_KP_GREATER: keyval = '>'; break;
|
||||
case SDLK_KP_AMPERSAND: keyval = '&'; break;
|
||||
case SDLK_KP_VERTICALBAR: keyval = '|'; break;
|
||||
case SDLK_KP_COLON: keyval = ':'; break;
|
||||
case SDLK_KP_HASH: keyval = '#'; break;
|
||||
case SDLK_KP_SPACE: keyval = ' '; break;
|
||||
case SDLK_KP_AT: keyval = '@'; break;
|
||||
case SDLK_KP_EXCLAM: keyval = '!'; break;
|
||||
}
|
||||
if ((m_keymod & KMOD_CTRL) != 0u)
|
||||
{
|
||||
keyval |= Keymod::CTRL;
|
||||
}
|
||||
if ((m_keymod & KMOD_ALT) != 0u)
|
||||
{
|
||||
keyval |= Keymod::ALT;
|
||||
}
|
||||
if ((m_keymod & KMOD_GUI) != 0u)
|
||||
{
|
||||
keyval |= Keymod::GUI;
|
||||
}
|
||||
return keyval;
|
||||
}
|
||||
|
||||
uint32_t Window::get_shifted(uint32_t keysym)
|
||||
{
|
||||
if ((keysym >= 'a') && (keysym <= 'z'))
|
||||
{
|
||||
return keysym - ('a' - 'A');
|
||||
}
|
||||
|
||||
switch (keysym)
|
||||
{
|
||||
case SDLK_QUOTE: return '"';
|
||||
case SDLK_COMMA: return '<';
|
||||
case SDLK_MINUS: return '_';
|
||||
case SDLK_PERIOD: return '>';
|
||||
case SDLK_SLASH: return '?';
|
||||
case SDLK_0: return ')';
|
||||
case SDLK_1: return '!';
|
||||
case SDLK_2: return '@';
|
||||
case SDLK_3: return '#';
|
||||
case SDLK_4: return '$';
|
||||
case SDLK_5: return '%';
|
||||
case SDLK_6: return '^';
|
||||
case SDLK_7: return '&';
|
||||
case SDLK_8: return '*';
|
||||
case SDLK_9: return '(';
|
||||
case SDLK_SEMICOLON: return ':';
|
||||
case SDLK_EQUALS: return '+';
|
||||
case SDLK_LEFTBRACKET: return '{';
|
||||
case SDLK_BACKSLASH: return '|';
|
||||
case SDLK_RIGHTBRACKET: return '}';
|
||||
case SDLK_BACKQUOTE: return '~';
|
||||
case SDLK_SPACE: return ' ';
|
||||
case SDLK_BACKSPACE: return '\b';
|
||||
}
|
||||
|
||||
return 0u;
|
||||
Jtk_SwapBuffers(m_window);
|
||||
}
|
||||
|
||||
void Window::change_focus(std::shared_ptr<BufferPane> buffer_pane)
|
||||
|
@ -3,30 +3,18 @@
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <SDL.h>
|
||||
#include "Font.h"
|
||||
#include "Buffer.h"
|
||||
#include "GL.h"
|
||||
#include "EncodedString.h"
|
||||
#include "CommandParser.h"
|
||||
#include "Jtk.h"
|
||||
|
||||
class BufferPane;
|
||||
|
||||
class Window
|
||||
{
|
||||
public:
|
||||
class Keymod
|
||||
{
|
||||
public:
|
||||
enum : uint32_t
|
||||
{
|
||||
CTRL = 0x10000,
|
||||
ALT = 0x20000,
|
||||
SHIFT = 0x40000,
|
||||
GUI = 0x80000,
|
||||
};
|
||||
};
|
||||
|
||||
enum class ScrollMode : uint8_t
|
||||
{
|
||||
ONE_LINE,
|
||||
@ -53,21 +41,24 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
void resize();
|
||||
void resize(size_t width, size_t height);
|
||||
void redraw();
|
||||
void handle_event(SDL_Event & event);
|
||||
void handle_keysym(uint32_t keysym);
|
||||
void handle_keyval(uint32_t keyval);
|
||||
void handle_event(Jtk_Event & event);
|
||||
void handle_keypress(uint32_t keyval);
|
||||
#if 0
|
||||
uint32_t get_keyval(SDL_Keycode keysym);
|
||||
uint32_t get_shifted(uint32_t keysym);
|
||||
#endif
|
||||
void change_focus(std::shared_ptr<BufferPane> buffer_pane);
|
||||
#if 0
|
||||
void set_window_icon();
|
||||
#endif
|
||||
void handle_command(const EncodedString & command);
|
||||
|
||||
void command_write_file(const CommandParser & cp);
|
||||
void command_quit(const CommandParser & cp);
|
||||
|
||||
SDL_Window * m_window;
|
||||
void * m_window;
|
||||
bool m_exit_requested;
|
||||
bool m_redraw_requested;
|
||||
int m_width;
|
||||
@ -83,8 +74,6 @@ protected:
|
||||
std::shared_ptr<BufferPane> m_focused_buffer_pane;
|
||||
std::shared_ptr<Buffer> m_command_buffer;
|
||||
std::shared_ptr<BufferPane> m_command_buffer_pane;
|
||||
|
||||
Uint16 m_keymod;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
59
src/gui/jtk/Jtk.cc
Normal file
59
src/gui/jtk/Jtk.cc
Normal file
@ -0,0 +1,59 @@
|
||||
#include "Jtk.h"
|
||||
|
||||
#ifdef JTK_X
|
||||
|
||||
#include <GL/glx.h>
|
||||
#include <stdio.h>
|
||||
|
||||
Display * g_display;
|
||||
XVisualInfo * g_vi;
|
||||
XSetWindowAttributes g_swa;
|
||||
GLXContext g_context;
|
||||
|
||||
/**
|
||||
* Initialize the Jtk subsystem.
|
||||
*
|
||||
* @return true on success, false on failure
|
||||
*/
|
||||
bool Jtk_Init()
|
||||
{
|
||||
static int glx_attribute_list[] = {
|
||||
GLX_RGBA,
|
||||
GLX_DOUBLEBUFFER,
|
||||
None,
|
||||
};
|
||||
|
||||
g_display = XOpenDisplay(NULL);
|
||||
if (g_display == NULL)
|
||||
{
|
||||
fprintf(stderr, "XOpenDisplay() failure\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
g_vi = glXChooseVisual(g_display, DefaultScreen(g_display),
|
||||
glx_attribute_list);
|
||||
if (g_vi == NULL)
|
||||
{
|
||||
fprintf(stderr, "glXChooseVisual() failure\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
g_context = glXCreateContext(g_display, g_vi, NULL, True);
|
||||
if (g_context == NULL)
|
||||
{
|
||||
fprintf(stderr, "glXCreateContext() failure\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
Colormap colormap = XCreateColormap(g_display,
|
||||
RootWindow(g_display, g_vi->screen), g_vi->visual, AllocNone);
|
||||
g_swa.colormap = colormap;
|
||||
g_swa.border_pixel = 0;
|
||||
g_swa.event_mask = StructureNotifyMask |
|
||||
KeyPressMask | KeyReleaseMask |
|
||||
ButtonPressMask | ButtonReleaseMask;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
12
src/gui/jtk/Jtk.h
Normal file
12
src/gui/jtk/Jtk.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef JTK_H
|
||||
#define JTK_H
|
||||
|
||||
#include "Jtk_event.h"
|
||||
#include "Jtk_keys.h"
|
||||
#include "Jtk_time.h"
|
||||
#include "Jtk_timer.h"
|
||||
#include "Jtk_window.h"
|
||||
|
||||
bool Jtk_Init();
|
||||
|
||||
#endif
|
460
src/gui/jtk/Jtk_event.cc
Normal file
460
src/gui/jtk/Jtk_event.cc
Normal file
@ -0,0 +1,460 @@
|
||||
#include "Jtk.h"
|
||||
|
||||
#ifdef JTK_X
|
||||
|
||||
#include <GL/glx.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include "Jtk_internal.h"
|
||||
#include <unordered_map>
|
||||
|
||||
/** Do not wait longer than 100ms */
|
||||
#define MAX_WAIT_TIME 100000u
|
||||
|
||||
static std::unordered_map<unsigned int, size_t> g_repeating_keys;
|
||||
static std::unordered_map<size_t, unsigned int> g_key_repeat_timers;
|
||||
|
||||
#if 0
|
||||
static void StopKeyRepeat(unsigned int x_keycode)
|
||||
{
|
||||
auto it = g_repeating_keys.find(x_keycode);
|
||||
if (it != g_repeating_keys.end())
|
||||
{
|
||||
size_t timer_id = it->second;
|
||||
Jtk_RemoveTimer(timer_id);
|
||||
g_repeating_keys.erase(x_keycode);
|
||||
g_key_repeat_timers.erase(timer_id);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
static unsigned int GetXState()
|
||||
{
|
||||
Window win;
|
||||
int i;
|
||||
unsigned int state;
|
||||
XQueryPointer(g_display, RootWindow(g_display, DefaultScreen(g_display)), &win, &win, &i, &i, &i, &i, &state);
|
||||
return state;
|
||||
}
|
||||
#endif
|
||||
|
||||
static uint32_t XStateToJtkKeyMods(unsigned int x_state)
|
||||
{
|
||||
uint32_t mods = 0u;
|
||||
/* OR in the modifier states */
|
||||
if (x_state & ShiftMask)
|
||||
{
|
||||
mods |= JTK_KEY_MODS_SHIFT;
|
||||
}
|
||||
if (x_state & LockMask)
|
||||
{
|
||||
mods |= JTK_KEY_MODS_LOCK;
|
||||
}
|
||||
if (x_state & ControlMask)
|
||||
{
|
||||
mods |= JTK_KEY_MODS_CTRL;
|
||||
}
|
||||
return mods;
|
||||
}
|
||||
|
||||
static uint32_t XKeyToJtkKey(unsigned int x_keycode, unsigned int x_state)
|
||||
{
|
||||
XKeyEvent x_key_event;
|
||||
x_key_event.type = KeyPress;
|
||||
x_key_event.display = g_display;
|
||||
/* Turn off the ControlMask bit for looking up keys. We'll handle control
|
||||
* keys ourselves. */
|
||||
x_key_event.state = x_state & ~ControlMask;
|
||||
x_key_event.keycode = x_keycode;
|
||||
char buffer;
|
||||
KeySym keysym;
|
||||
uint32_t key = JTK_KEY_UNKNOWN;
|
||||
|
||||
if (XLookupString(&x_key_event, &buffer, 1, &keysym, nullptr) > 0)
|
||||
{
|
||||
if (buffer == '\r')
|
||||
{
|
||||
key = '\n';
|
||||
}
|
||||
else
|
||||
{
|
||||
key = buffer;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (keysym)
|
||||
{
|
||||
case XK_F1: key = JTK_KEY_F1; break;
|
||||
case XK_F2: key = JTK_KEY_F2; break;
|
||||
case XK_F3: key = JTK_KEY_F3; break;
|
||||
case XK_F4: key = JTK_KEY_F4; break;
|
||||
case XK_F5: key = JTK_KEY_F5; break;
|
||||
case XK_F6: key = JTK_KEY_F6; break;
|
||||
case XK_F7: key = JTK_KEY_F7; break;
|
||||
case XK_F8: key = JTK_KEY_F8; break;
|
||||
case XK_F9: key = JTK_KEY_F9; break;
|
||||
case XK_F10: key = JTK_KEY_F10; break;
|
||||
case XK_F11: key = JTK_KEY_F11; break;
|
||||
case XK_F12: key = JTK_KEY_F12; break;
|
||||
case XK_F13: key = JTK_KEY_F13; break;
|
||||
case XK_F14: key = JTK_KEY_F14; break;
|
||||
case XK_F15: key = JTK_KEY_F15; break;
|
||||
case XK_F16: key = JTK_KEY_F16; break;
|
||||
case XK_F17: key = JTK_KEY_F17; break;
|
||||
case XK_F18: key = JTK_KEY_F18; break;
|
||||
case XK_F19: key = JTK_KEY_F19; break;
|
||||
case XK_F20: key = JTK_KEY_F20; break;
|
||||
case XK_F21: key = JTK_KEY_F21; break;
|
||||
case XK_F22: key = JTK_KEY_F22; break;
|
||||
case XK_F23: key = JTK_KEY_F23; break;
|
||||
case XK_F24: key = JTK_KEY_F24; break;
|
||||
case XK_F25: key = JTK_KEY_F25; break;
|
||||
case XK_F26: key = JTK_KEY_F26; break;
|
||||
case XK_F27: key = JTK_KEY_F27; break;
|
||||
case XK_F28: key = JTK_KEY_F28; break;
|
||||
case XK_F29: key = JTK_KEY_F29; break;
|
||||
case XK_F30: key = JTK_KEY_F30; break;
|
||||
case XK_F31: key = JTK_KEY_F31; break;
|
||||
|
||||
case XK_Shift_L: key = JTK_KEY_SHIFT_L; break;
|
||||
case XK_Shift_R: key = JTK_KEY_SHIFT_R; break;
|
||||
case XK_Control_L: key = JTK_KEY_CTRL_L; break;
|
||||
case XK_Control_R: key = JTK_KEY_CTRL_R; break;
|
||||
case XK_Caps_Lock: key = JTK_KEY_CAPS_LOCK; break;
|
||||
case XK_Shift_Lock: key = JTK_KEY_SHIFT_LOCK;break;
|
||||
|
||||
case XK_Meta_L: key = JTK_KEY_META_L; break;
|
||||
case XK_Meta_R: key = JTK_KEY_META_R; break;
|
||||
case XK_Alt_L: key = JTK_KEY_ALT_L; break;
|
||||
case XK_Alt_R: key = JTK_KEY_ALT_R; break;
|
||||
case XK_Super_L: key = JTK_KEY_SUPER_L; break;
|
||||
case XK_Super_R: key = JTK_KEY_SUPER_R; break;
|
||||
|
||||
case XK_Home: key = JTK_KEY_HOME; break;
|
||||
case XK_Left: key = JTK_KEY_LEFT; break;
|
||||
case XK_Up: key = JTK_KEY_UP; break;
|
||||
case XK_Right: key = JTK_KEY_RIGHT; break;
|
||||
case XK_Down: key = JTK_KEY_DOWN; break;
|
||||
case XK_Page_Up: key = JTK_KEY_PAGE_UP; break;
|
||||
case XK_Page_Down: key = JTK_KEY_PAGE_DOWN; break;
|
||||
case XK_End: key = JTK_KEY_END; break;
|
||||
case XK_Begin: key = JTK_KEY_BEGIN; break;
|
||||
|
||||
case XK_Select: key = JTK_KEY_SELECT; break;
|
||||
case XK_Print: key = JTK_KEY_PRINT; break;
|
||||
case XK_Execute: key = JTK_KEY_EXECUTE; break;
|
||||
case XK_Insert: key = JTK_KEY_INSERT; break;
|
||||
case XK_Undo: key = JTK_KEY_UNDO; break;
|
||||
case XK_Redo: key = JTK_KEY_REDO; break;
|
||||
case XK_Menu: key = JTK_KEY_MENU; break;
|
||||
case XK_Find: key = JTK_KEY_FIND; break;
|
||||
case XK_Cancel: key = JTK_KEY_CANCEL; break;
|
||||
case XK_Help: key = JTK_KEY_HELP; break;
|
||||
case XK_Break: key = JTK_KEY_BREAK; break;
|
||||
case XK_Num_Lock: key = JTK_KEY_NUM_LOCK; break;
|
||||
|
||||
case XK_KP_Space: key = JTK_KEY_KP_SPACE; break;
|
||||
case XK_KP_Tab: key = JTK_KEY_KP_TAB; break;
|
||||
case XK_KP_Enter: key = JTK_KEY_KP_ENTER; break;
|
||||
case XK_KP_F1: key = JTK_KEY_KP_F1; break;
|
||||
case XK_KP_F2: key = JTK_KEY_KP_F2; break;
|
||||
case XK_KP_F3: key = JTK_KEY_KP_F3; break;
|
||||
case XK_KP_F4: key = JTK_KEY_KP_F4; break;
|
||||
case XK_KP_Home: key = JTK_KEY_KP_HOME; break;
|
||||
case XK_KP_Left: key = JTK_KEY_KP_LEFT; break;
|
||||
case XK_KP_Up: key = JTK_KEY_KP_UP; break;
|
||||
case XK_KP_Right: key = JTK_KEY_KP_RIGHT; break;
|
||||
case XK_KP_Down: key = JTK_KEY_KP_DOWN; break;
|
||||
case XK_KP_Page_Up: key = JTK_KEY_KP_PAGE_UP; break;
|
||||
case XK_KP_Page_Down: key = JTK_KEY_KP_PAGE_DOWN; break;
|
||||
case XK_KP_End: key = JTK_KEY_KP_END; break;
|
||||
case XK_KP_Begin: key = JTK_KEY_KP_BEGIN; break;
|
||||
case XK_KP_Insert: key = JTK_KEY_KP_INSERT; break;
|
||||
case XK_KP_Delete: key = JTK_KEY_KP_DELETE; break;
|
||||
case XK_KP_Equal: key = JTK_KEY_KP_EQUAL; break;
|
||||
case XK_KP_Multiply: key = JTK_KEY_KP_MULTIPLY; break;
|
||||
case XK_KP_Add: key = JTK_KEY_KP_ADD; break;
|
||||
case XK_KP_Separator: key = JTK_KEY_KP_SEPARATOR; break;
|
||||
case XK_KP_Subtract: key = JTK_KEY_KP_SUBTRACT; break;
|
||||
case XK_KP_Decimal: key = JTK_KEY_KP_DECIMAL; break;
|
||||
case XK_KP_Divide: key = JTK_KEY_KP_DIVIDE; break;
|
||||
|
||||
case XK_KP_0: key = JTK_KEY_KP_0; break;
|
||||
case XK_KP_1: key = JTK_KEY_KP_1; break;
|
||||
case XK_KP_2: key = JTK_KEY_KP_2; break;
|
||||
case XK_KP_3: key = JTK_KEY_KP_3; break;
|
||||
case XK_KP_4: key = JTK_KEY_KP_4; break;
|
||||
case XK_KP_5: key = JTK_KEY_KP_5; break;
|
||||
case XK_KP_6: key = JTK_KEY_KP_6; break;
|
||||
case XK_KP_7: key = JTK_KEY_KP_7; break;
|
||||
case XK_KP_8: key = JTK_KEY_KP_8; break;
|
||||
case XK_KP_9: key = JTK_KEY_KP_9; break;
|
||||
}
|
||||
}
|
||||
|
||||
/* OR in the modifier states */
|
||||
key |= XStateToJtkKeyMods(x_state);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static Bool KeyRepeatCheckIfEvent(Display * display, XEvent * chkev,
|
||||
XPointer arg)
|
||||
{
|
||||
XEvent * release_event = (XEvent *)arg;
|
||||
if (chkev->type == KeyPress &&
|
||||
chkev->xkey.keycode == release_event->xkey.keycode &&
|
||||
chkev->xkey.time - release_event->xkey.time < 2)
|
||||
return True;
|
||||
return False;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if this is a repeated key.
|
||||
*/
|
||||
static bool IsRepeatKey(Display * display, XEvent * event)
|
||||
{
|
||||
XEvent dummyev;
|
||||
if (XPending(display))
|
||||
{
|
||||
if (XCheckIfEvent(display, &dummyev, KeyRepeatCheckIfEvent,
|
||||
(XPointer)event) == True)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
static Bool MatchKeyPress(Display * display, XEvent * event, XPointer arg)
|
||||
{
|
||||
XEvent * match_event = (XEvent *)arg;
|
||||
return (event->type == match_event->type) &&
|
||||
(event->xkey.window == match_event->xkey.window) &&
|
||||
(event->xkey.state == match_event->xkey.state) &&
|
||||
(event->xkey.keycode == match_event->xkey.keycode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an X key press event.
|
||||
*
|
||||
* @param x_event
|
||||
* Pointer to the X event.
|
||||
* @param event
|
||||
* Pointer to the Jtk event.
|
||||
*/
|
||||
static bool ProcessXKeyPressEvent(XEvent * x_event, Jtk_Event * event)
|
||||
{
|
||||
unsigned int x_keycode = x_event->xkey.keycode;
|
||||
event->type = JTK_EVENT_KEY_PRESS;
|
||||
event->key.repeat = false;
|
||||
event->key.key = XKeyToJtkKey(x_keycode, x_event->xkey.state);
|
||||
event->key.x_keycode = x_keycode;
|
||||
/* Remove any following keypress events for the same keycode from the X
|
||||
* queue. */
|
||||
XEvent remove_event;
|
||||
while (XCheckIfEvent(g_display, &remove_event, MatchKeyPress, (XPointer)x_event) == True)
|
||||
{
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an X key release event.
|
||||
*
|
||||
* @param x_event
|
||||
* Pointer to the X event.
|
||||
* @param event
|
||||
* Pointer to the Jtk event.
|
||||
*/
|
||||
static bool ProcessXKeyReleaseEvent(XEvent * x_event, Jtk_Event * event)
|
||||
{
|
||||
#if 0
|
||||
if (IsRepeatKey(g_display, x_event))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
StopKeyRepeat(x_event->xkey.keycode);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
static Bool MatchButtonPress(Display * display, XEvent * event, XPointer arg)
|
||||
{
|
||||
XEvent * match_event = (XEvent *)arg;
|
||||
return (event->type == match_event->type) &&
|
||||
(event->xbutton.window == match_event->xbutton.window) &&
|
||||
(event->xbutton.state == match_event->xbutton.state) &&
|
||||
(event->xbutton.button == match_event->xbutton.button);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an X button press event.
|
||||
*/
|
||||
static bool ProcessXButtonPressEvent(XEvent * x_event, Jtk_Event * event)
|
||||
{
|
||||
event->type = JTK_EVENT_BUTTON_PRESS;
|
||||
event->button.mods = XStateToJtkKeyMods(x_event->xbutton.state);
|
||||
event->button.button = x_event->xbutton.button;
|
||||
/* If this is a mouse wheel scroll event, remove any following scroll
|
||||
* events. */
|
||||
if ((event->button.button == 4) || (event->button.button == 5))
|
||||
{
|
||||
XEvent remove_event;
|
||||
while (XCheckIfEvent(g_display, &remove_event, MatchButtonPress, (XPointer)x_event) == True)
|
||||
{
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an X configure event.
|
||||
*
|
||||
* @param x_event
|
||||
* Pointer to the X event.
|
||||
* @param event
|
||||
* Pointer to the Jtk event.
|
||||
*/
|
||||
static bool ProcessConfigureEvent(XEvent * x_event, Jtk_Event * event)
|
||||
{
|
||||
event->type = JTK_EVENT_WINDOW_RESIZE;
|
||||
event->resize.width = x_event->xconfigure.width;
|
||||
event->resize.height = x_event->xconfigure.height;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an X event.
|
||||
*
|
||||
* @param x_event
|
||||
* Pointer to the X event.
|
||||
* @param event
|
||||
* Pointer to the Jtk event.
|
||||
*
|
||||
* @retval true
|
||||
* The event should be passed to the user and event has been filled in.
|
||||
* @retval false
|
||||
* The event should not be passed to the user.
|
||||
*/
|
||||
static bool ProcessXEvent(XEvent * x_event, Jtk_Event * event)
|
||||
{
|
||||
switch (x_event->type)
|
||||
{
|
||||
case KeyPress:
|
||||
return ProcessXKeyPressEvent(x_event, event);
|
||||
|
||||
case KeyRelease:
|
||||
return ProcessXKeyReleaseEvent(x_event, event);
|
||||
|
||||
case ButtonPress:
|
||||
return ProcessXButtonPressEvent(x_event, event);
|
||||
|
||||
case ButtonRelease:
|
||||
break;
|
||||
|
||||
case Expose:
|
||||
event->type = JTK_EVENT_WINDOW_EXPOSE;
|
||||
return true;
|
||||
|
||||
case GraphicsExpose:
|
||||
event->type = JTK_EVENT_WINDOW_EXPOSE;
|
||||
return true;
|
||||
|
||||
case MapNotify:
|
||||
event->type = JTK_EVENT_WINDOW_EXPOSE;
|
||||
return true;
|
||||
|
||||
case ConfigureNotify:
|
||||
return ProcessConfigureEvent(x_event, event);
|
||||
|
||||
case MappingNotify:
|
||||
XRefreshKeyboardMapping(&x_event->xmapping);
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Jtk_CheckEvent(Jtk_Event * event)
|
||||
{
|
||||
/* First check for an X event. */
|
||||
while (XPending(g_display) > 0)
|
||||
{
|
||||
XEvent x_event;
|
||||
XNextEvent(g_display, &x_event);
|
||||
if (ProcessXEvent(&x_event, event))
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Next check if any timer has expired. */
|
||||
size_t timer_id = Jtk_GetExpiredTimer();
|
||||
if (timer_id != (size_t)-1)
|
||||
{
|
||||
#if 0
|
||||
auto it = g_key_repeat_timers.find(timer_id);
|
||||
if (it != g_key_repeat_timers.end())
|
||||
{
|
||||
event->type = JTK_EVENT_KEY_PRESS;
|
||||
event->key.repeat = true;
|
||||
event->key.key = XKeyToJtkKey(it->second);
|
||||
event->key.x_keycode = it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
event->type = JTK_EVENT_TIMER;
|
||||
event->timer.timer_id = timer_id;
|
||||
event->timer.user1 = Jtk_GetTimerUserData(timer_id, 0u);
|
||||
event->timer.user2 = Jtk_GetTimerUserData(timer_id, 1u);
|
||||
#if 0
|
||||
}
|
||||
#endif
|
||||
Jtk_ServiceTimer(timer_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Jtk_WaitEvent(Jtk_Event * event)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (Jtk_CheckEvent(event))
|
||||
return;
|
||||
|
||||
/* Wait for something to happen. */
|
||||
uint64_t time_to_wait = Jtk_TimeToNextTimerExpiration();
|
||||
if (time_to_wait > MAX_WAIT_TIME)
|
||||
{
|
||||
time_to_wait = MAX_WAIT_TIME;
|
||||
}
|
||||
|
||||
int x_fd = ConnectionNumber(g_display);
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(x_fd, &fds);
|
||||
struct timeval tv;
|
||||
tv.tv_sec = time_to_wait / 1000000u;
|
||||
tv.tv_usec = time_to_wait % 1000000u;
|
||||
select(x_fd + 1, &fds, nullptr, nullptr, &tv);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
void Jtk_BeginKeyRepeat(Jtk_KeyEvent * key_event, uint32_t delay, uint32_t interval)
|
||||
{
|
||||
StopKeyRepeat(key_event->x_keycode);
|
||||
size_t timer_id = Jtk_AddTimer(delay, interval, nullptr, nullptr);
|
||||
g_repeating_keys[key_event->x_keycode] = timer_id;
|
||||
g_key_repeat_timers[timer_id] = key_event->x_keycode;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
62
src/gui/jtk/Jtk_event.h
Normal file
62
src/gui/jtk/Jtk_event.h
Normal file
@ -0,0 +1,62 @@
|
||||
#ifndef JTK_EVENT_H
|
||||
#define JTK_EVENT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define JTK_EVENT_CLOSE_WINDOW 1u
|
||||
#define JTK_EVENT_WINDOW_EXPOSE 2u
|
||||
#define JTK_EVENT_KEY_PRESS 3u
|
||||
#define JTK_EVENT_KEY_RELEASE 4u
|
||||
#define JTK_EVENT_BUTTON_PRESS 5u
|
||||
#define JTK_EVENT_BUTTON_RELEASE 6u
|
||||
#define JTK_EVENT_TIMER 7u
|
||||
#define JTK_EVENT_WINDOW_RESIZE 8u
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool repeat;
|
||||
uint32_t key;
|
||||
#ifdef JTK_X
|
||||
unsigned int x_keycode;
|
||||
#endif
|
||||
} Jtk_KeyEvent;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t mods;
|
||||
uint8_t button;
|
||||
} Jtk_ButtonEvent;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t timer_id;
|
||||
void * user1;
|
||||
void * user2;
|
||||
} Jtk_TimerEvent;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t width;
|
||||
size_t height;
|
||||
} Jtk_WindowResizeEvent;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t type;
|
||||
union
|
||||
{
|
||||
Jtk_KeyEvent key;
|
||||
Jtk_ButtonEvent button;
|
||||
Jtk_TimerEvent timer;
|
||||
Jtk_WindowResizeEvent resize;
|
||||
};
|
||||
} Jtk_Event;
|
||||
|
||||
bool Jtk_CheckEvent(Jtk_Event * event);
|
||||
void Jtk_WaitEvent(Jtk_Event * event);
|
||||
#if 0
|
||||
void Jtk_BeginKeyRepeat(Jtk_KeyEvent * key_event, uint32_t delay, uint32_t interval);
|
||||
#endif
|
||||
|
||||
#endif
|
9
src/gui/jtk/Jtk_internal.h
Normal file
9
src/gui/jtk/Jtk_internal.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef JTK_INTERNAL_H
|
||||
#define JTK_INTERNAL_H
|
||||
|
||||
extern Display * g_display;
|
||||
extern XVisualInfo * g_vi;
|
||||
extern XSetWindowAttributes g_swa;
|
||||
extern GLXContext g_context;
|
||||
|
||||
#endif
|
120
src/gui/jtk/Jtk_keys.h
Normal file
120
src/gui/jtk/Jtk_keys.h
Normal file
@ -0,0 +1,120 @@
|
||||
#ifndef JTK_KEYS_H
|
||||
#define JTK_KEYS_H
|
||||
|
||||
#define JTK_KEY_MODS_MASK 0xFF000000u
|
||||
|
||||
#define JTK_KEY_MODS_SHIFT 0x01000000u
|
||||
#define JTK_KEY_MODS_LOCK 0x02000000u
|
||||
#define JTK_KEY_MODS_CTRL 0x04000000u
|
||||
|
||||
#define JTK_KEY_KEYCODE_MASK 0x00FFFFFFu
|
||||
|
||||
#define JTK_KEY_F1 0x00FF0001u
|
||||
#define JTK_KEY_F2 0x00FF0002u
|
||||
#define JTK_KEY_F3 0x00FF0003u
|
||||
#define JTK_KEY_F4 0x00FF0004u
|
||||
#define JTK_KEY_F5 0x00FF0005u
|
||||
#define JTK_KEY_F6 0x00FF0006u
|
||||
#define JTK_KEY_F7 0x00FF0007u
|
||||
#define JTK_KEY_F8 0x00FF0008u
|
||||
#define JTK_KEY_F9 0x00FF0009u
|
||||
#define JTK_KEY_F10 0x00FF000Au
|
||||
#define JTK_KEY_F11 0x00FF000Bu
|
||||
#define JTK_KEY_F12 0x00FF000Cu
|
||||
#define JTK_KEY_F13 0x00FF000Du
|
||||
#define JTK_KEY_F14 0x00FF000Eu
|
||||
#define JTK_KEY_F15 0x00FF000Fu
|
||||
#define JTK_KEY_F16 0x00FF0010u
|
||||
#define JTK_KEY_F17 0x00FF0011u
|
||||
#define JTK_KEY_F18 0x00FF0012u
|
||||
#define JTK_KEY_F19 0x00FF0013u
|
||||
#define JTK_KEY_F20 0x00FF0014u
|
||||
#define JTK_KEY_F21 0x00FF0015u
|
||||
#define JTK_KEY_F22 0x00FF0016u
|
||||
#define JTK_KEY_F23 0x00FF0017u
|
||||
#define JTK_KEY_F24 0x00FF0018u
|
||||
#define JTK_KEY_F25 0x00FF0019u
|
||||
#define JTK_KEY_F26 0x00FF001Au
|
||||
#define JTK_KEY_F27 0x00FF001Bu
|
||||
#define JTK_KEY_F28 0x00FF001Cu
|
||||
#define JTK_KEY_F29 0x00FF001Du
|
||||
#define JTK_KEY_F30 0x00FF001Eu
|
||||
#define JTK_KEY_F31 0x00FF001Fu
|
||||
|
||||
#define JTK_KEY_SHIFT_L 0x00FF0030u
|
||||
#define JTK_KEY_SHIFT_R 0x00FF0031u
|
||||
#define JTK_KEY_CTRL_L 0x00FF0032u
|
||||
#define JTK_KEY_CTRL_R 0x00FF0033u
|
||||
#define JTK_KEY_CAPS_LOCK 0x00FF0034u
|
||||
#define JTK_KEY_SHIFT_LOCK 0x00FF0035u
|
||||
|
||||
#define JTK_KEY_META_L 0x00FF0036u
|
||||
#define JTK_KEY_META_R 0x00FF0037u
|
||||
#define JTK_KEY_ALT_L 0x00FF0038u
|
||||
#define JTK_KEY_ALT_R 0x00FF0039u
|
||||
#define JTK_KEY_SUPER_L 0x00FF003Au
|
||||
#define JTK_KEY_SUPER_R 0x00FF003Bu
|
||||
|
||||
#define JTK_KEY_HOME 0x00FF003Cu
|
||||
#define JTK_KEY_LEFT 0x00FF003Du
|
||||
#define JTK_KEY_UP 0x00FF003Eu
|
||||
#define JTK_KEY_RIGHT 0x00FF003Fu
|
||||
#define JTK_KEY_DOWN 0x00FF0040u
|
||||
#define JTK_KEY_PAGE_UP 0x00FF0042u
|
||||
#define JTK_KEY_PAGE_DOWN 0x00FF0044u
|
||||
#define JTK_KEY_END 0x00FF0045u
|
||||
#define JTK_KEY_BEGIN 0x00FF0046u
|
||||
|
||||
#define JTK_KEY_SELECT 0x00FF0047u
|
||||
#define JTK_KEY_PRINT 0x00FF0048u
|
||||
#define JTK_KEY_EXECUTE 0x00FF0049u
|
||||
#define JTK_KEY_INSERT 0x00FF004Au
|
||||
#define JTK_KEY_UNDO 0x00FF004Bu
|
||||
#define JTK_KEY_REDO 0x00FF004Cu
|
||||
#define JTK_KEY_MENU 0x00FF004Du
|
||||
#define JTK_KEY_FIND 0x00FF004Eu
|
||||
#define JTK_KEY_CANCEL 0x00FF004Fu
|
||||
#define JTK_KEY_HELP 0x00FF0050u
|
||||
#define JTK_KEY_BREAK 0x00FF0051u
|
||||
#define JTK_KEY_NUM_LOCK 0x00FF0054u
|
||||
|
||||
#define JTK_KEY_KP_SPACE 0x00FF0055u
|
||||
#define JTK_KEY_KP_TAB 0x00FF0056u
|
||||
#define JTK_KEY_KP_ENTER 0x00FF0057u
|
||||
#define JTK_KEY_KP_F1 0x00FF0058u
|
||||
#define JTK_KEY_KP_F2 0x00FF0059u
|
||||
#define JTK_KEY_KP_F3 0x00FF005Au
|
||||
#define JTK_KEY_KP_F4 0x00FF005Bu
|
||||
#define JTK_KEY_KP_HOME 0x00FF005Cu
|
||||
#define JTK_KEY_KP_LEFT 0x00FF005Du
|
||||
#define JTK_KEY_KP_UP 0x00FF005Eu
|
||||
#define JTK_KEY_KP_RIGHT 0x00FF005Fu
|
||||
#define JTK_KEY_KP_DOWN 0x00FF0060u
|
||||
#define JTK_KEY_KP_PAGE_UP 0x00FF0062u
|
||||
#define JTK_KEY_KP_PAGE_DOWN 0x00FF0064u
|
||||
#define JTK_KEY_KP_END 0x00FF0065u
|
||||
#define JTK_KEY_KP_BEGIN 0x00FF0066u
|
||||
#define JTK_KEY_KP_INSERT 0x00FF0067u
|
||||
#define JTK_KEY_KP_DELETE 0x00FF0068u
|
||||
#define JTK_KEY_KP_EQUAL 0x00FF0069u
|
||||
#define JTK_KEY_KP_MULTIPLY 0x00FF006Au
|
||||
#define JTK_KEY_KP_ADD 0x00FF006Bu
|
||||
#define JTK_KEY_KP_SEPARATOR 0x00FF006Cu
|
||||
#define JTK_KEY_KP_SUBTRACT 0x00FF006Du
|
||||
#define JTK_KEY_KP_DECIMAL 0x00FF006Eu
|
||||
#define JTK_KEY_KP_DIVIDE 0x00FF006Fu
|
||||
|
||||
#define JTK_KEY_KP_0 0x00FF0070u
|
||||
#define JTK_KEY_KP_1 0x00FF0071u
|
||||
#define JTK_KEY_KP_2 0x00FF0072u
|
||||
#define JTK_KEY_KP_3 0x00FF0073u
|
||||
#define JTK_KEY_KP_4 0x00FF0074u
|
||||
#define JTK_KEY_KP_5 0x00FF0075u
|
||||
#define JTK_KEY_KP_6 0x00FF0076u
|
||||
#define JTK_KEY_KP_7 0x00FF0077u
|
||||
#define JTK_KEY_KP_8 0x00FF0078u
|
||||
#define JTK_KEY_KP_9 0x00FF0079u
|
||||
|
||||
#define JTK_KEY_UNKNOWN 0x00FFFFFFu
|
||||
|
||||
#endif
|
9
src/gui/jtk/Jtk_time.cc
Normal file
9
src/gui/jtk/Jtk_time.cc
Normal file
@ -0,0 +1,9 @@
|
||||
#include "Jtk.h"
|
||||
#include <sys/time.h>
|
||||
|
||||
uint64_t Jtk_UsTime()
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
return (uint64_t)tv.tv_sec * 1000000u + (uint64_t)tv.tv_usec;
|
||||
}
|
9
src/gui/jtk/Jtk_time.h
Normal file
9
src/gui/jtk/Jtk_time.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef JTK_TIME_H
|
||||
#define JTK_TIME_H
|
||||
|
||||
#include "Jtk_timer.h"
|
||||
|
||||
bool Jtk_Init();
|
||||
uint64_t Jtk_UsTime();
|
||||
|
||||
#endif
|
157
src/gui/jtk/Jtk_timer.cc
Normal file
157
src/gui/jtk/Jtk_timer.cc
Normal file
@ -0,0 +1,157 @@
|
||||
#include "Jtk.h"
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <list>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint64_t next; /**< Time the timer next expires (us). */
|
||||
uint64_t interval; /**< Timer interval (us). */
|
||||
size_t id; /**< Timer ID. */
|
||||
void * user[2]; /**< User data pointers. */
|
||||
} Timer;
|
||||
|
||||
/** Vector used to allocate timer IDs. */
|
||||
static std::vector<std::shared_ptr<Timer>> g_timers;
|
||||
|
||||
/** Linked list used to traverse all active timers. */
|
||||
static std::list<std::shared_ptr<Timer>> g_active_timers;
|
||||
|
||||
static size_t AllocateTimerID()
|
||||
{
|
||||
for (size_t i = 0; i < g_timers.size(); i++)
|
||||
{
|
||||
if (!g_timers[i])
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
g_timers.push_back(nullptr);
|
||||
return g_timers.size() - 1u;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a timer.
|
||||
*
|
||||
* @param delay
|
||||
* Delay time in milliseconds.
|
||||
* @param interval
|
||||
* Interval time in milliseconds. A value of 0 indicates that the timer
|
||||
* is not periodic.
|
||||
* @param user1
|
||||
* User data pointer 1. This value is not used by Jtk but can be retrieved by
|
||||
* the user when a timer expires.
|
||||
* @param user2
|
||||
* User data pointer 2. This value is not used by Jtk but can be retrieved by
|
||||
* the user when a timer expires.
|
||||
*
|
||||
* @return
|
||||
* Timer ID.
|
||||
*/
|
||||
size_t Jtk_AddTimer(uint32_t delay, uint32_t interval, void * user1, void * user2)
|
||||
{
|
||||
uint64_t current_system_time = Jtk_UsTime();
|
||||
size_t timer_id = AllocateTimerID();
|
||||
auto timer = std::make_shared<Timer>();
|
||||
timer->next = current_system_time + (delay * 1000u);
|
||||
timer->interval = interval * 1000u;
|
||||
timer->id = timer_id;
|
||||
timer->user[0] = user1;
|
||||
timer->user[1] = user2;
|
||||
g_timers[timer_id] = timer;
|
||||
g_active_timers.push_back(timer);
|
||||
return timer_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a timer.
|
||||
*
|
||||
* @param timer_id
|
||||
* The ID of the timer to remove.
|
||||
*/
|
||||
void Jtk_RemoveTimer(size_t timer_id)
|
||||
{
|
||||
if (timer_id < g_timers.size())
|
||||
{
|
||||
auto timer = g_timers[timer_id];
|
||||
g_active_timers.remove(timer);
|
||||
g_timers[timer_id] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the amount of time until the next timer expires (in us).
|
||||
*
|
||||
* @return
|
||||
* Time (in us) until the next timer expires. This will be 0 if an active
|
||||
* timer has already expired, and will be (uint64_t)-1 if there are no
|
||||
* active timers.
|
||||
*/
|
||||
uint64_t Jtk_TimeToNextTimerExpiration()
|
||||
{
|
||||
uint64_t time = (uint64_t)-1;
|
||||
uint64_t current_system_time = Jtk_UsTime();
|
||||
for (auto & timer : g_active_timers)
|
||||
{
|
||||
if (timer->next <= current_system_time)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
uint64_t time_until_this_timer = timer->next - current_system_time;
|
||||
if (time_until_this_timer < time)
|
||||
{
|
||||
time = time_until_this_timer;
|
||||
}
|
||||
}
|
||||
return time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Service a timer.
|
||||
*
|
||||
* This will increment the timer's next activation time by its interval, or
|
||||
* for a timer with an interval of 0, will remove the timer.
|
||||
*
|
||||
* @param timer_id
|
||||
* The ID of the timer to service.
|
||||
*/
|
||||
void Jtk_ServiceTimer(size_t timer_id)
|
||||
{
|
||||
auto timer = g_timers[timer_id];
|
||||
if (timer->interval == 0u)
|
||||
{
|
||||
Jtk_RemoveTimer(timer_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
timer->next += timer->interval;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ID of an expired timer.
|
||||
*
|
||||
* @return
|
||||
* The ID of an expired timer, or (size_t)-1 if no timer is expired.
|
||||
*/
|
||||
size_t Jtk_GetExpiredTimer()
|
||||
{
|
||||
uint64_t current_system_time = Jtk_UsTime();
|
||||
for (auto & timer : g_active_timers)
|
||||
{
|
||||
if (timer->next <= current_system_time)
|
||||
{
|
||||
return timer->id;
|
||||
}
|
||||
}
|
||||
return (size_t)-1;
|
||||
}
|
||||
|
||||
void * Jtk_GetTimerUserData(size_t timer_id, uint8_t index)
|
||||
{
|
||||
if (timer_id < g_timers.size())
|
||||
{
|
||||
return g_timers[timer_id]->user[index];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
14
src/gui/jtk/Jtk_timer.h
Normal file
14
src/gui/jtk/Jtk_timer.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef JTK_TIMER_H
|
||||
#define JTK_TIMER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
size_t Jtk_AddTimer(uint32_t delay, uint32_t interval, void * user1, void * user2);
|
||||
void Jtk_RemoveTimer(size_t timer_id);
|
||||
uint64_t Jtk_TimeToNextTimerExpiration();
|
||||
void Jtk_ServiceTimer(size_t timer_id);
|
||||
size_t Jtk_GetExpiredTimer();
|
||||
void * Jtk_GetTimerUserData(size_t timer_id, uint8_t index);
|
||||
|
||||
#endif
|
55
src/gui/jtk/Jtk_window.cc
Normal file
55
src/gui/jtk/Jtk_window.cc
Normal file
@ -0,0 +1,55 @@
|
||||
|
||||
#include "Jtk.h"
|
||||
|
||||
#ifdef JTK_X
|
||||
|
||||
#include <GL/glx.h>
|
||||
#include "Jtk_internal.h"
|
||||
#include <stdio.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
static Bool WaitForNotify(Display * display, XEvent * event, XPointer arg)
|
||||
{
|
||||
return (event->type == MapNotify) && (event->xmap.window == (Window)arg);
|
||||
}
|
||||
|
||||
void * Jtk_CreateWindow()
|
||||
{
|
||||
XEvent event;
|
||||
Window window = XCreateWindow(g_display,
|
||||
RootWindow(g_display, g_vi->screen),
|
||||
0, 0, 800, 800, 0, g_vi->depth, InputOutput, g_vi->visual,
|
||||
CWBorderPixel | CWColormap | CWEventMask, &g_swa);
|
||||
XMapWindow(g_display, window);
|
||||
XIfEvent(g_display, &event, WaitForNotify, (XPointer)window);
|
||||
if (glXMakeCurrent(g_display, window, g_context) == False)
|
||||
{
|
||||
fprintf(stderr, "glXMakeCurrent() failure\n");
|
||||
XDestroyWindow(g_display, window);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return (void *)window;
|
||||
}
|
||||
|
||||
void Jtk_SwapBuffers(void * window)
|
||||
{
|
||||
glXSwapBuffers(g_display, (Window)window);
|
||||
}
|
||||
|
||||
void Jtk_CloseWindow(void * window)
|
||||
{
|
||||
XDestroyWindow(g_display, (Window)window);
|
||||
}
|
||||
|
||||
void Jtk_SetWindowTitle(void * window, const char * title)
|
||||
{
|
||||
XTextProperty title_property;
|
||||
if (XStringListToTextProperty((char **)&title, 1, &title_property) != 0)
|
||||
{
|
||||
XSetTextProperty(g_display, (Window)window, &title_property, XA_WM_NAME);
|
||||
XFree(title_property.value);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
9
src/gui/jtk/Jtk_window.h
Normal file
9
src/gui/jtk/Jtk_window.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef JTK_WINDOW_H
|
||||
#define JTK_WINDOW_H
|
||||
|
||||
void * Jtk_CreateWindow();
|
||||
void Jtk_SwapBuffers(void * window);
|
||||
void Jtk_CloseWindow(void * window);
|
||||
void Jtk_SetWindowTitle(void * window, const char * title);
|
||||
|
||||
#endif
|
15
wscript
15
wscript
@ -11,8 +11,11 @@ def options(opt):
|
||||
def configure(conf):
|
||||
conf.load("compiler_c compiler_cxx")
|
||||
conf.check(header_name = "getopt.h", global_define = False)
|
||||
conf.check_cfg(package = "sdl2", args = "--cflags --libs")
|
||||
conf.check_cfg(package = "freetype2", uselib_store = "FreeType2", args = "--cflags --libs")
|
||||
if platform.system() == "Linux":
|
||||
conf.check(header_name = "X11/Xlib.h", global_define = False)
|
||||
elif platform.system() == "Windows":
|
||||
conf.check(header_name = "windows.h", global_define = False)
|
||||
|
||||
def build(bld):
|
||||
defines = ['APPNAME="%s"' % APPNAME]
|
||||
@ -22,9 +25,11 @@ def build(bld):
|
||||
libs = []
|
||||
if platform.system() == "Linux":
|
||||
defines += ["PLATFORM_LINUX"]
|
||||
libs += ["dl", "GL"]
|
||||
elif re.search(r'MINGW', platform.system()):
|
||||
defines += ["JTK_X"]
|
||||
libs += ["dl", "GL", "X11"]
|
||||
elif platform.system() == "Windows":
|
||||
defines += ["PLATFORM_WINDOWS"]
|
||||
defines += ["JTK_WINDOWS"]
|
||||
libs += ["opengl32"]
|
||||
defines += ['GLCXX_GL_INCLUDE="gl3w.h"']
|
||||
sources = bld.path.ant_glob(["src/**/*.cc", "src/**/*.c", "libs/glcxx/src/glcxx/*"])
|
||||
@ -35,7 +40,7 @@ def build(bld):
|
||||
defines = defines,
|
||||
cxxflags = ["-Wall", "-std=gnu++14", "-O2", "-Wno-switch"],
|
||||
lib = libs,
|
||||
uselib = ["SDL2", "FreeType2"])
|
||||
uselib = ["FreeType2"])
|
||||
|
||||
test_libs = libs + []
|
||||
if platform.system() == "Linux":
|
||||
@ -56,4 +61,4 @@ def build(bld):
|
||||
lib = test_libs,
|
||||
cxxflags = ["-Wall", "-std=gnu++14", "--coverage", "-Wno-switch", "-include", "iostream"],
|
||||
linkflags = ["--coverage"],
|
||||
uselib = ["SDL2", "FreeType2"])
|
||||
uselib = ["FreeType2"])
|
||||
|
Loading…
x
Reference in New Issue
Block a user