zephr/os/windows: create window and gl context

This commit is contained in:
2024-01-26 01:32:54 +02:00
committed by Illusion
parent 43da578ff2
commit 5bc58af47f
14 changed files with 1013 additions and 573 deletions
+154 -544
View File
@@ -8,9 +8,6 @@ import x11 "vendor:x11/xlib"
import gl "vendor:OpenGL"
import "vendor:stb/image"
import "../glx"
import "../xcursor"
Cursor :: enum {
ARROW,
IBEAM,
@@ -349,7 +346,7 @@ Keyboard :: struct {
}
Context :: struct {
window_delete_atom: x11.Atom,
//window_delete_atom: x11.Atom,
should_quit: bool,
screen_size: Vec2,
window: Window,
@@ -357,7 +354,7 @@ Context :: struct {
mouse: Mouse,
keyboard: Keyboard,
cursor: Cursor,
cursors: [Cursor]x11.Cursor,
//cursors: [Cursor]x11.Cursor,
ui: Ui,
/* ZephrKeyboard keyboard; */
@@ -369,14 +366,6 @@ Context :: struct {
projection: Mat4,
}
@private
PropModeReplace :: 0
@private
XA_ATOM :: x11.Atom(4)
@private
XA_STRING :: x11.Atom(31)
@private
XA_CARDINAL :: x11.Atom(6)
@private
FNV_HASH32_INIT :: 0x811c9dc5
@private
@@ -643,306 +632,12 @@ evdev_scancode_to_zephr_scancode_map := []Scancode {
236 = .NULL, // KEY_BATTERY
}
@private
x11_display : ^x11.Display
@private
x11_window : x11.Window
@private
x11_colormap : x11.Colormap
@private
glx_context : glx.Context
@private
zephr_ctx : Context
@private
logger : log.Logger
////////////////////////////
//
// X11
//
///////////////////////////
@private
x11_go_fullscreen :: proc() {
// remove the resizing constraint before going fullscreen so WMs such as gnome
// can add the _NET_WM_ACTION_FULLSCREEN action to the _NET_WM_ALLOWED_ACTIONS atom
// and properly fullscreen the window
size_hints := x11.XAllocSizeHints()
zephr_ctx.window.pre_fullscreen_size.x = zephr_ctx.window.size.x
zephr_ctx.window.pre_fullscreen_size.y = zephr_ctx.window.size.y
if (size_hints != nil) {
size_hints.flags = {.PPosition, .PSize}
size_hints.width = cast(i32)zephr_ctx.window.size.x
size_hints.height = cast(i32)zephr_ctx.window.size.y
x11.XSetWMNormalHints(x11_display, x11_window, size_hints)
x11.XFree(size_hints)
}
xev: x11.XEvent
wm_state := x11.XInternAtom(x11_display, "_NET_WM_STATE", false)
fullscreen := x11.XInternAtom(x11_display, "_NET_WM_STATE_FULLSCREEN", false)
xev.type = .ClientMessage
xev.xclient.window = x11_window
xev.xclient.message_type = wm_state
xev.xclient.format = 32
xev.xclient.data.l[0] = 1 // _NET_WM_STATE_ADD
xev.xclient.data.l[1] = cast(int)fullscreen
xev.xclient.data.l[2] = 0
x11.XSendEvent(x11_display, x11.XDefaultRootWindow(x11_display), false,
{.SubstructureNotify, .SubstructureRedirect}, &xev)
}
@private
x11_return_fullscreen :: proc() {
xev: x11.XEvent
wm_state := x11.XInternAtom(x11_display, "_NET_WM_STATE", false)
fullscreen := x11.XInternAtom(x11_display, "_NET_WM_STATE_FULLSCREEN", false)
xev.type = .ClientMessage
xev.xclient.window = x11_window
xev.xclient.message_type = wm_state
xev.xclient.format = 32
xev.xclient.data.l[0] = 0 // _NET_WM_STATE_REMOVE
xev.xclient.data.l[1] = cast(int)fullscreen
xev.xclient.data.l[2] = 0
x11.XSendEvent(x11_display, x11.XDefaultRootWindow(x11_display), false,
{.SubstructureNotify, .SubstructureRedirect}, &xev)
// restore the resizing constraint as well as the pre-fullscreen window size
// when returning from fullscreen
size_hints := x11.XAllocSizeHints()
if (size_hints != nil) {
size_hints.flags = {.PPosition, .PSize}
size_hints.width = cast(i32)zephr_ctx.window.pre_fullscreen_size.x
size_hints.height = cast(i32)zephr_ctx.window.pre_fullscreen_size.y
if (zephr_ctx.window.non_resizable) {
size_hints.flags |= {.PMinSize, .PMaxSize}
size_hints.min_width = cast(i32)zephr_ctx.window.pre_fullscreen_size.x
size_hints.min_height = cast(i32)zephr_ctx.window.pre_fullscreen_size.y
size_hints.max_width = cast(i32)zephr_ctx.window.pre_fullscreen_size.x
size_hints.max_height = cast(i32)zephr_ctx.window.pre_fullscreen_size.y
}
x11.XSetWMNormalHints(x11_display, x11_window, size_hints)
x11.XFree(size_hints)
}
}
@private
x11_toggle_fullscreen :: proc(fullscreen: bool) {
if fullscreen {
x11_return_fullscreen()
} else {
x11_go_fullscreen()
}
}
@private
x11_assign_window_icon :: proc(icon_path: cstring, window_title: cstring) {
icon_width, icon_height: i32
icon_data := image.load(icon_path, &icon_width, &icon_height, nil, 4)
defer image.image_free(icon_data)
assert(icon_data != nil, "Failed to load icon image")
target_size := 2 + icon_width * icon_height
data := make([]u64, target_size)
// first two elements are width and height
data[0] = cast(u64)icon_width
data[1] = cast(u64)icon_height
for i in 0..<(icon_width * icon_height) {
data[i + 2] = (cast(u64)icon_data[i * 4] << 16) | (cast(u64)icon_data[i * 4 + 1] << 8) | (cast(u64)icon_data[i * 4 + 2] << 0) | (cast(u64)icon_data[i * 4 + 3] << 24)
}
net_wm_icon := x11.XInternAtom(x11_display, "_NET_WM_ICON", false)
x11.XChangeProperty(x11_display, x11_window, net_wm_icon, XA_CARDINAL, 32, PropModeReplace, raw_data(data), target_size)
}
@private
x11_get_screen_size :: proc() -> Vec2 {
screen := x11.XDefaultScreenOfDisplay(x11_display)
return Vec2{cast(f32)screen.width, cast(f32)screen.height}
}
@private
x11_resize_window :: proc() {
win_attrs : x11.XWindowAttributes
x11.XGetWindowAttributes(x11_display, x11_window, &win_attrs)
gl.Viewport(0, 0, win_attrs.width, win_attrs.height)
}
@private
x11_create_window :: proc(window_title: cstring, window_size: Vec2, icon_path: cstring, window_non_resizable: bool) {
context.logger = logger
x11_display = x11.XOpenDisplay(nil)
if x11_display == nil {
log.error("Failed to open X11 display")
return
}
screen_num := x11.XDefaultScreen(x11_display)
root := x11.XRootWindow(x11_display, screen_num)
visual := x11.XDefaultVisual(x11_display, screen_num)
x11_colormap = x11.XCreateColormap(x11_display, root, visual, x11.ColormapAlloc.AllocNone)
attributes: x11.XSetWindowAttributes
attributes.event_mask = {.Exposure, .KeyPress, .KeyRelease,
.StructureNotify, .ButtonPress, .ButtonRelease, .PointerMotion}
attributes.colormap = x11_colormap
screen := x11.XDefaultScreenOfDisplay(x11_display)
window_start_x := screen.width / 2 - cast(i32)window_size.x / 2
window_start_y := screen.height / 2 - cast(i32)window_size.y / 2
x11_window = x11.XCreateWindow(x11_display, root, window_start_x, window_start_y, cast(u32)window_size.x, cast(u32)window_size.y, 0,
x11.XDefaultDepth(x11_display), .InputOutput, visual,
{.CWColormap, .CWEventMask}, &attributes)
if (icon_path != "") {
x11_assign_window_icon(icon_path, window_title)
}
// Hints to the WM that the window is a normal window
// Of course this is only a hint and the WM can ignore it
net_wm_window_type := x11.XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", false)
net_wm_window_type_normal := x11.XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_NORMAL", false)
x11.XChangeProperty(x11_display, x11_window, net_wm_window_type, XA_ATOM, 32, PropModeReplace, &net_wm_window_type_normal, 1)
wm_delete_window := x11.XInternAtom(x11_display, "WM_DELETE_WINDOW", false)
x11.XSetWMProtocols(x11_display, x11_window, &wm_delete_window, 1)
zephr_ctx.window_delete_atom = wm_delete_window
// set window name
{
UTF8_STRING := x11.XInternAtom(x11_display, "UTF8_STRING", false)
x11.XStoreName(x11_display, x11_window, window_title)
text_property: x11.XTextProperty
text_property.value = raw_data(string(window_title))
text_property.format = 8
text_property.encoding = UTF8_STRING
text_property.nitems = len(window_title)
x11.XSetWMName(x11_display, x11_window, &text_property)
net_wm_name := x11.XInternAtom(x11_display, "_NET_WM_NAME", false)
wm_class := x11.XInternAtom(x11_display, "WM_CLASS", false)
x11.XChangeProperty(x11_display, x11_window, net_wm_name, UTF8_STRING, 8, PropModeReplace, raw_data(string(window_title)), cast(i32)len(window_title))
x11.XChangeProperty(x11_display, x11_window, wm_class, XA_STRING, 8, PropModeReplace, raw_data(string(window_title)), cast(i32)len(window_title))
// name to be displayed when the window is reduced to an icon
net_wm_icon_name := x11.XInternAtom(x11_display, "_NET_WM_ICON_NAME", false)
x11.XChangeProperty(x11_display, x11_window, net_wm_icon_name, UTF8_STRING, 8, PropModeReplace, raw_data(string(window_title)), cast(i32)len(window_title))
text_property.encoding = XA_STRING
x11.XSetWMIconName(x11_display, x11_window, &text_property)
class_hint := x11.XAllocClassHint()
if (class_hint != nil) {
class_hint.res_name = window_title
class_hint.res_class = window_title
x11.XSetClassHint(x11_display, x11_window, class_hint)
x11.XFree(class_hint)
}
}
size_hints := x11.XAllocSizeHints()
if (size_hints != nil) {
size_hints.flags = {.PPosition, .PSize}
/* size_hints->win_gravity = StaticGravity; */
size_hints.x = window_start_x
size_hints.y = window_start_y
size_hints.width = cast(i32)window_size.x
size_hints.height = cast(i32)window_size.y
if (window_non_resizable) {
size_hints.flags |= {.PMinSize, .PMaxSize}
size_hints.min_width = cast(i32)window_size.x
size_hints.min_height = cast(i32)window_size.y
size_hints.max_width = cast(i32)window_size.x
size_hints.max_height = cast(i32)window_size.y
}
x11.XSetWMNormalHints(x11_display, x11_window, size_hints)
x11.XFree(size_hints)
}
x11.XMapWindow(x11_display, x11_window)
gl.load_up_to(3, 3, proc(p: rawptr, name: cstring) { (cast(^rawptr)p)^ = glx.GetProcAddressARB(raw_data(string(name))) })
glx_major : i32
glx_minor : i32
glx.QueryVersion(x11_display, &glx_major, &glx_minor)
log.infof("Loaded GLX: %d.%d", glx_major, glx_minor)
visual_attributes := []i32 {
glx.RENDER_TYPE, glx.RGBA_BIT,
glx.RED_SIZE, 8,
glx.GREEN_SIZE, 8,
glx.BLUE_SIZE, 8,
glx.ALPHA_SIZE, 8,
glx.DEPTH_SIZE, 24,
glx.DOUBLEBUFFER, 1,
glx.SAMPLES, 4, // MSAA
x11.None,
}
num_fbc: i32
fbc := glx.ChooseFBConfig(x11_display, screen_num, raw_data(visual_attributes), &num_fbc)
context_attributes := []i32 {
glx.CONTEXT_MAJOR_VERSION_ARB, 3,
glx.CONTEXT_MINOR_VERSION_ARB, 3,
glx.CONTEXT_PROFILE_MASK_ARB, glx.CONTEXT_CORE_PROFILE_BIT_ARB,
x11.None,
}
glx_context = glx.CreateContextAttribsARB(x11_display, fbc[0], nil, true, raw_data(context_attributes))
if glx_context == nil {
log.error("Failed to create GLX context")
return
}
glx.MakeCurrent(x11_display, x11_window, glx_context)
gl_version := gl.GetString(gl.VERSION)
log.infof("GL Version: %s", gl_version)
glx.SwapIntervalEXT(x11_display, x11_window, 1)
// we enable blending for text
gl.Enable(gl.BLEND)
gl.Enable(gl.MULTISAMPLE)
gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
x11_resize_window()
x11.XFree(fbc)
}
@private
x11_init :: proc(window_title: cstring, window_size: Vec2, icon_path: cstring, window_non_resizable: bool) {
x11_create_window(window_title, window_size, icon_path, window_non_resizable)
}
@private
x11_close :: proc() {
glx.MakeCurrent(x11_display, 0, nil)
glx.DestroyContext(x11_display, glx_context)
x11.XDestroyWindow(x11_display, x11_window)
x11.XFreeColormap(x11_display, x11_colormap)
x11.XCloseDisplay(x11_display)
}
////////////////////////////
//
// Zephr
@@ -957,7 +652,7 @@ init :: proc(font_path: cstring, icon_path: cstring, window_title: cstring, wind
//int res = audio_init();
//CORE_ASSERT(res == 0, "Failed to initialize audio");
x11_init(window_title, window_size, icon_path, window_non_resizable)
backend_init(window_title, window_size, icon_path, window_non_resizable)
ui_init(font_path)
@@ -967,22 +662,22 @@ init :: proc(font_path: cstring, icon_path: cstring, window_title: cstring, wind
zephr_ctx.window.non_resizable = window_non_resizable
zephr_ctx.projection = orthographic_projection_2d(0, window_size.x, window_size.y, 0)
zephr_ctx.cursors[.ARROW] = x11.XCreateFontCursor(x11_display, .XC_left_ptr)
zephr_ctx.cursors[.IBEAM] = x11.XCreateFontCursor(x11_display, .XC_xterm)
zephr_ctx.cursors[.CROSSHAIR] = x11.XCreateFontCursor(x11_display, .XC_crosshair)
zephr_ctx.cursors[.HAND] = x11.XCreateFontCursor(x11_display, .XC_hand1)
zephr_ctx.cursors[.HRESIZE] = x11.XCreateFontCursor(x11_display, .XC_sb_h_double_arrow)
zephr_ctx.cursors[.VRESIZE] = x11.XCreateFontCursor(x11_display, .XC_sb_v_double_arrow)
// zephr_ctx.cursors[.ARROW] = x11.XCreateFontCursor(x11_display, .XC_left_ptr)
// zephr_ctx.cursors[.IBEAM] = x11.XCreateFontCursor(x11_display, .XC_xterm)
// zephr_ctx.cursors[.CROSSHAIR] = x11.XCreateFontCursor(x11_display, .XC_crosshair)
// zephr_ctx.cursors[.HAND] = x11.XCreateFontCursor(x11_display, .XC_hand1)
// zephr_ctx.cursors[.HRESIZE] = x11.XCreateFontCursor(x11_display, .XC_sb_h_double_arrow)
// zephr_ctx.cursors[.VRESIZE] = x11.XCreateFontCursor(x11_display, .XC_sb_v_double_arrow)
// non-standard cursors
zephr_ctx.cursors[.DISABLED] = xcursor.LibraryLoadCursor(x11_display, "crossed_circle")
// zephr_ctx.cursors[.DISABLED] = xcursor.LibraryLoadCursor(x11_display, "crossed_circle")
zephr_ctx.screen_size = x11_get_screen_size()
zephr_ctx.screen_size = backend_get_screen_size()
start_internal_timer()
}
deinit :: proc() {
x11_close()
backend_shutdown()
//audio_close()
}
@@ -1027,153 +722,157 @@ swap_buffers :: proc() {
zephr_ctx.ui.hovered_element = 0
}
glx.SwapBuffers(x11_display, x11_window)
x11.XDefineCursor(x11_display, x11_window, zephr_ctx.cursors[zephr_ctx.cursor])
backend_swapbuffers()
//x11.XDefineCursor(x11_display, x11_window, zephr_ctx.cursors[zephr_ctx.cursor])
}
iter_events :: proc(e_out: ^Event) -> bool {
context.logger = logger
xev: x11.XEvent
for (cast(bool)x11.XPending(x11_display)) {
x11.XNextEvent(x11_display, &xev)
if xev.type == .ConfigureNotify {
xce := xev.xconfigure
if (xce.width != cast(i32)zephr_ctx.window.size.x || xce.height != cast(i32)zephr_ctx.window.size.y) {
zephr_ctx.window.size = Vec2{cast(f32)xce.width, cast(f32)xce.height}
zephr_ctx.projection = orthographic_projection_2d(0, zephr_ctx.window.size.x, zephr_ctx.window.size.y, 0)
x11_resize_window()
e_out.type = .WINDOW_RESIZED
e_out.window.width = cast(u32)xce.width
e_out.window.height = cast(u32)xce.height
return true
}
} else if xev.type == .DestroyNotify {
// window destroy event
e_out.type = .WINDOW_CLOSED
return true
} else if xev.type == .ClientMessage {
// window close event
if (cast(x11.Atom)xev.xclient.data.l[0] == zephr_ctx.window_delete_atom) {
e_out.type = .WINDOW_CLOSED
return true
}
} else if xev.type == .KeyPress {
xke := xev.xkey
evdev_keycode := xke.keycode - 8
scancode := evdev_scancode_to_zephr_scancode_map[evdev_keycode]
e_out.type = .KEY_PRESSED
e_out.key.scancode = scancode
//e_out.key.code = keycode;
e_out.key.mods = x11_mods_to_zephr_mods(scancode, true)
return true
} else if xev.type == .KeyRelease {
xke := xev.xkey
evdev_keycode := xke.keycode - 8
scancode := evdev_scancode_to_zephr_scancode_map[evdev_keycode]
e_out.type = .KEY_RELEASED
e_out.key.scancode = scancode
//e_out.key.code = keycode;
e_out.key.mods = x11_mods_to_zephr_mods(scancode, false)
return true
} else if xev.type == .ButtonPress {
e_out.type = .MOUSE_BUTTON_PRESSED
e_out.mouse.pos = Vec2{cast(f32)xev.xbutton.x, cast(f32)xev.xbutton.y}
zephr_ctx.mouse.pressed = true
switch (xev.xbutton.button) {
case .Button1:
e_out.mouse.button = .BUTTON_LEFT
zephr_ctx.mouse.button = .BUTTON_LEFT
case .Button2:
e_out.mouse.button = .BUTTON_MIDDLE
zephr_ctx.mouse.button = .BUTTON_MIDDLE
case .Button3:
e_out.mouse.button = .BUTTON_RIGHT
zephr_ctx.mouse.button = .BUTTON_RIGHT
case .Button4:
e_out.type = .MOUSE_SCROLL
e_out.mouse.scroll_direction = .UP
case .Button5:
e_out.type = .MOUSE_SCROLL
e_out.mouse.scroll_direction = .DOWN
case cast(x11.MouseButton)8: // Back
e_out.mouse.button = .BUTTON_BACK
zephr_ctx.mouse.button = .BUTTON_BACK
case cast(x11.MouseButton)9: // Forward
e_out.mouse.button = .BUTTON_FORWARD
zephr_ctx.mouse.button = .BUTTON_FORWARD
case:
log.warnf("Unknown mouse button pressed: %d", xev.xbutton.button)
}
return true
} else if xev.type == .ButtonRelease {
e_out.type = .MOUSE_BUTTON_RELEASED
e_out.mouse.pos = Vec2{cast(f32)xev.xbutton.x, cast(f32)xev.xbutton.y}
zephr_ctx.mouse.released = true
zephr_ctx.mouse.pressed = false
switch (xev.xbutton.button) {
case .Button1:
e_out.mouse.button = .BUTTON_LEFT
case .Button2:
e_out.mouse.button = .BUTTON_MIDDLE
case .Button3:
e_out.mouse.button = .BUTTON_RIGHT
case .Button4:
e_out.type = .MOUSE_SCROLL
e_out.mouse.scroll_direction = .UP
case .Button5:
e_out.type = .MOUSE_SCROLL
e_out.mouse.scroll_direction = .DOWN
case cast(x11.MouseButton)8: // Back
e_out.mouse.button = .BUTTON_BACK
zephr_ctx.mouse.button = .BUTTON_BACK
case cast(x11.MouseButton)9: // Forward
e_out.mouse.button = .BUTTON_FORWARD
zephr_ctx.mouse.button = .BUTTON_FORWARD
}
return true
} else if xev.type == .MappingNotify {
// input device mapping changed
if (xev.xmapping.request != .MappingKeyboard) {
break
}
x11.XRefreshKeyboardMapping(&xev.xmapping)
/* x11_keyboard_map_update(); */
break
} else if xev.type == .MotionNotify {
e_out.type = .MOUSE_MOVED
e_out.mouse.pos = Vec2{cast(f32)xev.xmotion.x, cast(f32)xev.xmotion.y}
zephr_ctx.mouse.pos = e_out.mouse.pos
return true
}
}
return false
return backend_get_os_events(e_out)
}
// iter_events :: proc(e_out: ^Event) -> bool {
// context.logger = logger
// xev: x11.XEvent
// for (cast(bool)x11.XPending(x11_display)) {
// x11.XNextEvent(x11_display, &xev)
// if xev.type == .ConfigureNotify {
// xce := xev.xconfigure
// if (xce.width != cast(i32)zephr_ctx.window.size.x || xce.height != cast(i32)zephr_ctx.window.size.y) {
// zephr_ctx.window.size = Vec2{cast(f32)xce.width, cast(f32)xce.height}
// zephr_ctx.projection = orthographic_projection_2d(0, zephr_ctx.window.size.x, zephr_ctx.window.size.y, 0)
// x11_resize_window()
// e_out.type = .WINDOW_RESIZED
// e_out.window.width = cast(u32)xce.width
// e_out.window.height = cast(u32)xce.height
// return true
// }
// } else if xev.type == .DestroyNotify {
// // window destroy event
// e_out.type = .WINDOW_CLOSED
// return true
// } else if xev.type == .ClientMessage {
// // window close event
// if (cast(x11.Atom)xev.xclient.data.l[0] == zephr_ctx.window_delete_atom) {
// e_out.type = .WINDOW_CLOSED
// return true
// }
// } else if xev.type == .KeyPress {
// xke := xev.xkey
// evdev_keycode := xke.keycode - 8
// scancode := evdev_scancode_to_zephr_scancode_map[evdev_keycode]
// e_out.type = .KEY_PRESSED
// e_out.key.scancode = scancode
// //e_out.key.code = keycode;
// e_out.key.mods = x11_mods_to_zephr_mods(scancode, true)
// return true
// } else if xev.type == .KeyRelease {
// xke := xev.xkey
// evdev_keycode := xke.keycode - 8
// scancode := evdev_scancode_to_zephr_scancode_map[evdev_keycode]
// e_out.type = .KEY_RELEASED
// e_out.key.scancode = scancode
// //e_out.key.code = keycode;
// e_out.key.mods = x11_mods_to_zephr_mods(scancode, false)
// return true
// } else if xev.type == .ButtonPress {
// e_out.type = .MOUSE_BUTTON_PRESSED
// e_out.mouse.pos = Vec2{cast(f32)xev.xbutton.x, cast(f32)xev.xbutton.y}
// zephr_ctx.mouse.pressed = true
// switch (xev.xbutton.button) {
// case .Button1:
// e_out.mouse.button = .BUTTON_LEFT
// zephr_ctx.mouse.button = .BUTTON_LEFT
// case .Button2:
// e_out.mouse.button = .BUTTON_MIDDLE
// zephr_ctx.mouse.button = .BUTTON_MIDDLE
// case .Button3:
// e_out.mouse.button = .BUTTON_RIGHT
// zephr_ctx.mouse.button = .BUTTON_RIGHT
// case .Button4:
// e_out.type = .MOUSE_SCROLL
// e_out.mouse.scroll_direction = .UP
// case .Button5:
// e_out.type = .MOUSE_SCROLL
// e_out.mouse.scroll_direction = .DOWN
// case cast(x11.MouseButton)8: // Back
// e_out.mouse.button = .BUTTON_BACK
// zephr_ctx.mouse.button = .BUTTON_BACK
// case cast(x11.MouseButton)9: // Forward
// e_out.mouse.button = .BUTTON_FORWARD
// zephr_ctx.mouse.button = .BUTTON_FORWARD
// case:
// log.warnf("Unknown mouse button pressed: %d", xev.xbutton.button)
// }
// return true
// } else if xev.type == .ButtonRelease {
// e_out.type = .MOUSE_BUTTON_RELEASED
// e_out.mouse.pos = Vec2{cast(f32)xev.xbutton.x, cast(f32)xev.xbutton.y}
// zephr_ctx.mouse.released = true
// zephr_ctx.mouse.pressed = false
// switch (xev.xbutton.button) {
// case .Button1:
// e_out.mouse.button = .BUTTON_LEFT
// case .Button2:
// e_out.mouse.button = .BUTTON_MIDDLE
// case .Button3:
// e_out.mouse.button = .BUTTON_RIGHT
// case .Button4:
// e_out.type = .MOUSE_SCROLL
// e_out.mouse.scroll_direction = .UP
// case .Button5:
// e_out.type = .MOUSE_SCROLL
// e_out.mouse.scroll_direction = .DOWN
// case cast(x11.MouseButton)8: // Back
// e_out.mouse.button = .BUTTON_BACK
// zephr_ctx.mouse.button = .BUTTON_BACK
// case cast(x11.MouseButton)9: // Forward
// e_out.mouse.button = .BUTTON_FORWARD
// zephr_ctx.mouse.button = .BUTTON_FORWARD
// }
// return true
// } else if xev.type == .MappingNotify {
// // input device mapping changed
// if (xev.xmapping.request != .MappingKeyboard) {
// break
// }
// x11.XRefreshKeyboardMapping(&xev.xmapping)
// /* x11_keyboard_map_update(); */
// break
// } else if xev.type == .MotionNotify {
// e_out.type = .MOUSE_MOVED
// e_out.mouse.pos = Vec2{cast(f32)xev.xmotion.x, cast(f32)xev.xmotion.y}
// zephr_ctx.mouse.pos = e_out.mouse.pos
// return true
// }
// }
// return false
// }
get_window_size :: proc() -> Vec2 {
return zephr_ctx.window.size
}
toggle_fullscreen :: proc() {
x11_toggle_fullscreen(zephr_ctx.window.is_fullscreen)
backend_toggle_fullscreen(zephr_ctx.window.is_fullscreen)
zephr_ctx.window.is_fullscreen = !zephr_ctx.window.is_fullscreen
}
@@ -1205,94 +904,6 @@ fnv_hash32 :: proc(data: []byte, size: u32, hash: u32) -> u32 {
return hash
}
@private
x11_mods_to_zephr_mods :: proc(scancode: Scancode, is_press: bool) -> KeyMod {
mods := zephr_ctx.keyboard.mods
if (is_press) {
if (scancode == .LEFT_SHIFT) {
mods |= {.LEFT_SHIFT, .SHIFT}
}
if (scancode == .RIGHT_SHIFT) {
mods |= {.RIGHT_SHIFT, .SHIFT}
}
if (scancode == .LEFT_CTRL) {
mods |= {.LEFT_CTRL, .CTRL}
}
if (scancode == .RIGHT_CTRL) {
mods |= {.RIGHT_CTRL, .CTRL}
}
if (scancode == .LEFT_ALT) {
mods |= {.LEFT_ALT, .ALT}
}
if (scancode == .RIGHT_ALT) {
mods |= {.RIGHT_ALT, .ALT}
}
if (scancode == .LEFT_META) {
mods |= {.LEFT_META, .META}
}
if (scancode == .RIGHT_META) {
mods |= {.RIGHT_META, .META}
}
if (scancode == .CAPS_LOCK) {
mods |= {.CAPS_LOCK}
}
if (scancode == .NUM_LOCK_OR_CLEAR) {
mods |= {.NUM_LOCK}
}
} else {
if (scancode == .LEFT_SHIFT) {
mods &= ~{.LEFT_SHIFT}
}
if (scancode == .RIGHT_SHIFT) {
mods &= ~{.RIGHT_SHIFT}
}
if (!(.RIGHT_SHIFT in mods) && !(.LEFT_SHIFT in mods)) {
mods &= ~{.SHIFT}
}
if (scancode == .LEFT_CTRL) {
mods &= ~{.LEFT_CTRL}
}
if (scancode == .RIGHT_CTRL) {
mods &= ~{.RIGHT_CTRL}
}
if (!(.RIGHT_CTRL in mods) && !(.LEFT_CTRL in mods)) {
mods &= ~{.CTRL}
}
if (scancode == .LEFT_ALT) {
mods &= ~{.LEFT_ALT}
}
if (scancode == .RIGHT_ALT) {
mods &= ~{.RIGHT_ALT}
}
if (!(.RIGHT_ALT in mods) && !(.LEFT_ALT in mods)) {
mods &= ~{.ALT}
}
if (scancode == .LEFT_META) {
mods &= ~{.LEFT_META}
}
if (scancode == .RIGHT_META) {
mods &= ~{.RIGHT_META}
}
if (!(.RIGHT_META in mods) && !(.LEFT_META in mods)) {
mods &= ~{.META}
}
if (scancode == .CAPS_LOCK) {
mods &= ~{.CAPS_LOCK}
}
if (scancode == .NUM_LOCK_OR_CLEAR) {
mods &= ~{.NUM_LOCK}
}
}
zephr_ctx.keyboard.mods = mods
return mods
}
@private
logger_init :: proc() {
buf : [128]byte
@@ -1308,5 +919,4 @@ logger_init :: proc() {
term_logger := log.create_console_logger(opt = TerminalLoggerOpts)
logger = log.create_multi_logger(file_logger, term_logger)
}
}