From 76365322f2174abf096cf9e36ed58f1f02d42251 Mon Sep 17 00:00:00 2001 From: Louis Pearson Date: Wed, 7 Feb 2024 01:46:49 -0700 Subject: [PATCH] remove unneeded stuff --- build.zig | 45 +- deps/zig-xkbcommon/LICENSE | 19 - deps/zig-xkbcommon/README.md | 5 - deps/zig-xkbcommon/src/xkbcommon.zig | 341 --- deps/zig-xkbcommon/src/xkbcommon_keysyms.zig | 2606 ------------------ deps/zig-xkbcommon/src/xkbcommon_names.zig | 14 - examples/00_client_connect.zig | 556 ---- examples/01_client_connect.zig | 375 --- examples/02_text_editor.zig | 689 ----- examples/PieceTable.zig | 461 ---- src/main.zig | 1229 +++++---- src/root.zig | 646 +++++ 12 files changed, 1286 insertions(+), 5700 deletions(-) delete mode 100644 deps/zig-xkbcommon/LICENSE delete mode 100644 deps/zig-xkbcommon/README.md delete mode 100644 deps/zig-xkbcommon/src/xkbcommon.zig delete mode 100644 deps/zig-xkbcommon/src/xkbcommon_keysyms.zig delete mode 100644 deps/zig-xkbcommon/src/xkbcommon_names.zig delete mode 100644 examples/00_client_connect.zig delete mode 100644 examples/01_client_connect.zig delete mode 100644 examples/02_text_editor.zig delete mode 100644 examples/PieceTable.zig create mode 100644 src/root.zig diff --git a/build.zig b/build.zig index 452e355..121a518 100644 --- a/build.zig +++ b/build.zig @@ -4,22 +4,6 @@ pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); - const xkbcommon_module = b.createModule(.{ - .root_source_file = .{ .path = "deps/zig-xkbcommon/src/xkbcommon.zig" }, - }); - - const module = b.addModule("wayland", .{ - .root_source_file = .{ .path = "src/main.zig" }, - }); - - const lib = b.addStaticLibrary(.{ - .name = "zig-wayland-wire", - .root_source_file = .{ .path = "src/main.zig" }, - .target = target, - .optimize = optimize, - }); - b.installArtifact(lib); - const main_tests = b.addTest(.{ .root_source_file = .{ .path = "src/main.zig" }, .target = target, @@ -31,33 +15,14 @@ pub fn build(b: *std.Build) void { const test_step = b.step("test", "Run library tests"); test_step.dependOn(&run_main_tests.step); - const client_connect_raw_exe = b.addExecutable(.{ - .name = "00_client_connect", - .root_source_file = .{ .path = "examples/00_client_connect.zig" }, + const exe = b.addExecutable(.{ + .name = "pinephone-test", + .root_source_file = .{ .path = "src/main.zig" }, .target = target, .optimize = optimize, }); - b.installArtifact(client_connect_raw_exe); - const client_connect_exe = b.addExecutable(.{ - .name = "01_client_connect", - .root_source_file = .{ .path = "examples/01_client_connect.zig" }, - .target = target, - .optimize = optimize, - }); - client_connect_exe.root_module.addImport("wayland", module); - b.installArtifact(client_connect_exe); + exe.addIncludePath(.{ .path = "deps/font8x8/" }); - const text_editor_exe = b.addExecutable(.{ - .name = "02_text_editor", - .root_source_file = .{ .path = "examples/02_text_editor.zig" }, - .target = target, - .optimize = optimize, - }); - text_editor_exe.root_module.addImport("wayland", module); - text_editor_exe.root_module.addImport("xkbcommon", xkbcommon_module); - text_editor_exe.linkLibC(); - text_editor_exe.linkSystemLibrary("xkbcommon"); - text_editor_exe.addIncludePath(.{ .path = "deps/font8x8/" }); - b.installArtifact(text_editor_exe); + b.installArtifact(exe); } diff --git a/deps/zig-xkbcommon/LICENSE b/deps/zig-xkbcommon/LICENSE deleted file mode 100644 index 6588f3b..0000000 --- a/deps/zig-xkbcommon/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright 2020 Isaac Freund - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/deps/zig-xkbcommon/README.md b/deps/zig-xkbcommon/README.md deleted file mode 100644 index 9d6879e..0000000 --- a/deps/zig-xkbcommon/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# zig-xkbcommon - -[zig](https://ziglang.org/) 0.11 bindings for -[xkbcommon](https://xkbcommon.org) that are a little -nicer to use than the output of `zig translate-c`. diff --git a/deps/zig-xkbcommon/src/xkbcommon.zig b/deps/zig-xkbcommon/src/xkbcommon.zig deleted file mode 100644 index 67341da..0000000 --- a/deps/zig-xkbcommon/src/xkbcommon.zig +++ /dev/null @@ -1,341 +0,0 @@ -pub const names = @import("xkbcommon_names.zig"); - -pub const Keycode = u32; - -pub const Keysym = @import("xkbcommon_keysyms.zig").Keysym; - -pub const KeyDirection = enum(c_int) { - up, - down, -}; - -pub const LayoutIndex = u32; -pub const LayoutMask = u32; - -pub const LevelIndex = u32; - -pub const ModIndex = u32; -pub const ModMask = u32; - -pub const LED_Index = u32; -pub const LED_Mask = u32; - -pub const keycode_invalid = 0xffff_ffff; -pub const layout_invalid = 0xffff_ffff; -pub const level_invalid = 0xffff_ffff; -pub const mod_invalid = 0xffff_ffff; -pub const led_invalid = 0xffff_ffff; - -pub const keycode_max = 0xffff_ffff - 1; - -pub const RuleNames = extern struct { - rules: ?[*:0]const u8, - model: ?[*:0]const u8, - layout: ?[*:0]const u8, - variant: ?[*:0]const u8, - options: ?[*:0]const u8, -}; - -pub const LogLevel = enum(c_int) { - crit = 10, - err = 20, - warn = 30, - info = 40, - debug = 50, -}; - -pub const Context = opaque { - pub const Flags = enum(c_int) { - no_flags = 0, - no_default_includes = 1 << 0, - no_environment_names = 1 << 1, - }; - - extern fn xkb_context_new(flags: Flags) ?*Context; - pub const new = xkb_context_new; - - extern fn xkb_context_ref(context: *Context) *Context; - pub const ref = xkb_context_ref; - - extern fn xkb_context_unref(context: *Context) void; - pub const unref = xkb_context_unref; - - extern fn xkb_context_set_user_data(context: *Context, user_data: ?*anyopaque) void; - pub const setUserData = xkb_context_set_user_data; - - extern fn xkb_context_get_user_data(context: *Context) ?*anyopaque; - pub const getUserData = xkb_context_get_user_data; - - extern fn xkb_context_include_path_append(context: *Context, path: [*:0]const u8) c_int; - pub const includePathAppend = xkb_context_include_path_append; - - extern fn xkb_context_include_path_append_default(context: *Context) c_int; - pub const includePathAppendDefault = xkb_context_include_path_append_default; - - extern fn xkb_context_include_path_reset_defaults(context: *Context) c_int; - pub const includePathResetDefaults = xkb_context_include_path_reset_defaults; - - extern fn xkb_context_include_path_clear(context: *Context) void; - pub const includePathClear = xkb_context_include_path_clear; - - extern fn xkb_context_num_include_paths(context: *Context) c_uint; - pub const numIncludePaths = xkb_context_num_include_paths; - - extern fn xkb_context_include_path_get(context: *Context, index: c_uint) ?[*:0]const u8; - pub const includePathGet = xkb_context_include_path_get; - - extern fn xkb_context_set_log_level(context: *Context, level: LogLevel) void; - pub const setLogLevel = xkb_context_set_log_level; - - extern fn xkb_context_get_log_level(context: *Context) LogLevel; - pub const getLogLevel = xkb_context_get_log_level; - - extern fn xkb_context_set_log_verbosity(context: *Context, verbosity: c_int) void; - pub const setLogVerbosity = xkb_context_set_log_verbosity; - - extern fn xkb_context_get_log_verbosity(context: *Context) c_int; - pub const getLogVerbosity = xkb_context_get_log_verbosity; - - // TODO - //extern fn xkb_context_set_log_fn(context: *Context, log_fn: ?fn (?*Context, enum_xkb_log_level, [*c]const u8, [*c]struct___va_list_tag) callconv(.C) void) void; -}; - -pub const Keymap = opaque { - pub const CompileFlags = enum(c_int) { - no_flags = 0, - }; - - pub const Format = enum(c_int) { - text_v1 = 1, - }; - - extern fn xkb_keymap_new_from_names(context: *Context, names: ?*const RuleNames, flags: CompileFlags) ?*Keymap; - pub const newFromNames = xkb_keymap_new_from_names; - - // TODO - //extern fn xkb_keymap_new_from_file(context: *Context, file: *FILE, format: Format, flags: CompileFlags) ?*Keymap; - //pub const newFromFile = xkb_keymap_new_from_file; - - extern fn xkb_keymap_new_from_string(context: *Context, string: [*:0]const u8, format: Format, flags: CompileFlags) ?*Keymap; - pub const newFromString = xkb_keymap_new_from_string; - - extern fn xkb_keymap_new_from_buffer(context: *Context, buffer: [*]const u8, length: usize, format: Format, flags: CompileFlags) ?*Keymap; - pub const newFromBuffer = xkb_keymap_new_from_buffer; - - extern fn xkb_keymap_ref(keymap: *Keymap) *Keymap; - pub const ref = xkb_keymap_ref; - - extern fn xkb_keymap_unref(keymap: *Keymap) void; - pub const unref = xkb_keymap_unref; - - extern fn xkb_keymap_get_as_string(keymap: *Keymap, format: Format) [*c]u8; - pub const getAsString = xkb_keymap_get_as_string; - - extern fn xkb_keymap_min_keycode(keymap: *Keymap) Keycode; - pub const minKeycode = xkb_keymap_min_keycode; - - extern fn xkb_keymap_max_keycode(keymap: *Keymap) Keycode; - pub const maxKeycode = xkb_keymap_max_keycode; - - extern fn xkb_keymap_key_for_each( - keymap: *Keymap, - iter: fn (keymap: *Keymap, key: Keycode, data: ?*anyopaque) callconv(.C) void, - data: ?*anyopaque, - ) void; - pub inline fn keyForEach( - keymap: *Keymap, - comptime T: type, - comptime iter: fn (keymap: *Keymap, key: Keycode, data: T) void, - data: T, - ) void { - xkb_keymap_key_for_each( - keymap, - struct { - fn _wrapper(_keymap: *Keymap, _key: Keycode, _data: ?*anyopaque) callconv(.C) void { - iter(_keymap, _key, @ptrCast(@alignCast(_data))); - } - }._wrapper, - data, - ); - } - - extern fn xkb_keymap_key_get_name(keymap: *Keymap, key: Keycode) ?[*:0]const u8; - pub const keyGetName = xkb_keymap_key_get_name; - - extern fn xkb_keymap_key_by_name(keymap: *Keymap, name: [*:0]const u8) Keycode; - pub const keyByName = xkb_keymap_key_by_name; - - extern fn xkb_keymap_num_mods(keymap: *Keymap) ModIndex; - pub const numMods = xkb_keymap_num_mods; - - extern fn xkb_keymap_mod_get_name(keymap: *Keymap, idx: ModIndex) ?[*:0]const u8; - pub const modGetName = xkb_keymap_mod_get_name; - - extern fn xkb_keymap_mod_get_index(keymap: *Keymap, name: [*:0]const u8) ModIndex; - pub const modGetIndex = xkb_keymap_mod_get_index; - - extern fn xkb_keymap_num_layouts(keymap: *Keymap) LayoutIndex; - pub const numLayouts = xkb_keymap_num_layouts; - - extern fn xkb_keymap_layout_get_name(keymap: *Keymap, idx: LayoutIndex) ?[*:0]const u8; - pub const layoutGetName = xkb_keymap_layout_get_name; - - extern fn xkb_keymap_layout_get_index(keymap: *Keymap, name: [*:0]const u8) LayoutIndex; - pub const layoutGetIndex = xkb_keymap_layout_get_index; - - extern fn xkb_keymap_num_leds(keymap: *Keymap) LED_Index; - pub const numLeds = xkb_keymap_num_leds; - - extern fn xkb_keymap_led_get_name(keymap: *Keymap, idx: LED_Index) ?[*:0]const u8; - pub const ledGetName = xkb_keymap_led_get_name; - - extern fn xkb_keymap_led_get_index(keymap: *Keymap, name: [*:0]const u8) LED_Index; - pub const ledGetIndex = xkb_keymap_led_get_index; - - extern fn xkb_keymap_num_layouts_for_key(keymap: *Keymap, key: Keycode) LayoutIndex; - pub const numLayoutsForKey = xkb_keymap_num_layouts_for_key; - - extern fn xkb_keymap_num_levels_for_key(keymap: *Keymap, key: Keycode, layout: LayoutIndex) LevelIndex; - pub const numLevelsForKey = xkb_keymap_num_levels_for_key; - - extern fn xkb_keymap_key_get_mods_for_level(keymap: *Keymap, key: Keycode, layout: LayoutIndex, level: LevelIndex, masks_out: [*]ModMask, masks_size: usize) usize; - pub const keyGetModsForLevel = xkb_keymap_key_get_mods_for_level; - - extern fn xkb_keymap_key_get_syms_by_level(keymap: *Keymap, key: Keycode, layout: LayoutIndex, level: LevelIndex, syms_out: *?[*]const Keysym) c_int; - pub fn keyGetSymsByLevel(keymap: *Keymap, key: Keycode, layout: LayoutIndex, level: LevelIndex) []const Keysym { - var ptr: ?[*]const Keysym = undefined; - const len = xkb_keymap_key_get_syms_by_level(keymap, key, layout, level, &ptr); - return if (len == 0) &[0]Keysym{} else ptr.?[0..@intCast(len)]; - } - - extern fn xkb_keymap_key_repeats(keymap: *Keymap, key: Keycode) c_int; - pub const keyRepeats = xkb_keymap_key_repeats; -}; - -pub const ConsumedMode = enum(c_int) { - xkb, - gtk, -}; - -pub const State = opaque { - pub const Component = enum(c_int) { - _, - pub const mods_depressed = 1 << 0; - pub const mods_latched = 1 << 1; - pub const mods_locked = 1 << 2; - pub const mods_effective = 1 << 3; - pub const layout_depressed = 1 << 4; - pub const layout_latched = 1 << 5; - pub const layout_locked = 1 << 6; - pub const layout_effective = 1 << 7; - pub const leds = 1 << 8; - }; - - pub const Match = enum(c_int) { - _, - pub const any = 1 << 0; - pub const all = 1 << 1; - pub const non_exclusive = 1 << 16; - }; - - extern fn xkb_state_new(keymap: *Keymap) ?*State; - pub const new = xkb_state_new; - - extern fn xkb_state_ref(state: *State) *State; - pub const ref = xkb_state_ref; - - extern fn xkb_state_unref(state: *State) void; - pub const unref = xkb_state_unref; - - extern fn xkb_state_get_keymap(state: *State) *Keymap; - pub const getKeymap = xkb_state_get_keymap; - - extern fn xkb_state_update_key(state: *State, key: Keycode, direction: KeyDirection) Component; - pub const updateKey = xkb_state_update_key; - - extern fn xkb_state_update_mask( - state: *State, - depressed_mods: ModMask, - latched_mods: ModMask, - locked_mods: ModMask, - depressed_layout: LayoutIndex, - latched_layout: LayoutIndex, - locked_layout: LayoutIndex, - ) Component; - pub const updateMask = xkb_state_update_mask; - - extern fn xkb_state_key_get_syms(state: *State, key: Keycode, syms_out: *?[*]const Keysym) c_int; - pub fn keyGetSyms(state: *State, key: Keycode) []const Keysym { - var ptr: ?[*]const Keysym = undefined; - const len = xkb_state_key_get_syms(state, key, &ptr); - return if (len == 0) &[0]Keysym{} else ptr.?[0..@intCast(len)]; - } - - extern fn xkb_state_key_get_utf8(state: *State, key: Keycode, buffer: [*]u8, size: usize) c_int; - pub fn keyGetUtf8(state: *State, key: Keycode, buffer: []u8) usize { - return @intCast(xkb_state_key_get_utf8(state, key, buffer.ptr, buffer.len)); - } - - extern fn xkb_state_key_get_utf32(state: *State, key: Keycode) u32; - pub const keyGetUtf32 = xkb_state_key_get_utf32; - - extern fn xkb_state_key_get_one_sym(state: *State, key: Keycode) Keysym; - pub const keyGetOneSym = xkb_state_key_get_one_sym; - - extern fn xkb_state_key_get_layout(state: *State, key: Keycode) LayoutIndex; - pub const keyGetLayout = xkb_state_key_get_layout; - - extern fn xkb_state_key_get_level(state: *State, key: Keycode, layout: LayoutIndex) LevelIndex; - pub const keyGetLevel = xkb_state_key_get_level; - - extern fn xkb_state_serialize_mods(state: *State, components: Component) ModMask; - pub const serializeMods = xkb_state_serialize_mods; - - extern fn xkb_state_serialize_layout(state: *State, components: Component) LayoutIndex; - pub const serializeLayout = xkb_state_serialize_layout; - - extern fn xkb_state_mod_name_is_active(state: *State, name: [*:0]const u8, kind: Component) c_int; - pub const modNameIsActive = xkb_state_mod_name_is_active; - - extern fn xkb_state_mod_names_are_active(state: *State, kind: Component, match: Match, ...) c_int; - pub const modNamesAreActive = xkb_state_mod_names_are_active; - - extern fn xkb_state_mod_index_is_active(state: *State, idx: ModIndex, kind: Component) c_int; - pub const modIndexIsActive = xkb_state_mod_index_is_active; - - extern fn xkb_state_mod_indices_are_active(state: *State, kind: Component, match: Match, ...) c_int; - pub const modIndicesAreActive = xkb_state_mod_indices_are_active; - - extern fn xkb_state_key_get_consumed_mods2(state: *State, key: Keycode, mode: ConsumedMode) ModMask; - pub const keyGetConsumedMods2 = xkb_state_key_get_consumed_mods2; - - extern fn xkb_state_key_get_consumed_mods(state: *State, key: Keycode) ModMask; - pub const keyGetConsumedMods = xkb_state_key_get_consumed_mods; - - extern fn xkb_state_mod_index_is_consumed2(state: *State, key: Keycode, idx: ModIndex, mode: ConsumedMode) c_int; - pub const modIndexIsConsumed2 = xkb_state_mod_index_is_consumed2; - - extern fn xkb_state_mod_index_is_consumed(state: *State, key: Keycode, idx: ModIndex) c_int; - pub const modIndexIsConsumed = xkb_state_mod_index_is_consumed; - - extern fn xkb_state_mod_mask_remove_consumed(state: *State, key: Keycode, mask: ModMask) ModMask; - pub const modMaskRemoveConsumed = xkb_state_mod_mask_remove_consumed; - - extern fn xkb_state_layout_name_is_active(state: *State, name: [*c]const u8, kind: Component) c_int; - pub const layoutNameIsActive = xkb_state_layout_name_is_active; - - extern fn xkb_state_layout_index_is_active(state: *State, idx: LayoutIndex, kind: Component) c_int; - pub const layoutIndexIsActive = xkb_state_layout_index_is_active; - - extern fn xkb_state_led_name_is_active(state: *State, name: [*c]const u8) c_int; - pub const ledNameIsActive = xkb_state_led_name_is_active; - - extern fn xkb_state_led_index_is_active(state: *State, idx: LED_Index) c_int; - pub const ledIndexIsActive = xkb_state_led_index_is_active; -}; - -test { - const std = @import("std"); - @setEvalBranchQuota(4000); - std.testing.refAllDeclsRecursive(@This()); -} diff --git a/deps/zig-xkbcommon/src/xkbcommon_keysyms.zig b/deps/zig-xkbcommon/src/xkbcommon_keysyms.zig deleted file mode 100644 index 4dcbc13..0000000 --- a/deps/zig-xkbcommon/src/xkbcommon_keysyms.zig +++ /dev/null @@ -1,2606 +0,0 @@ -// This file is generated by massaging the output of running zig translate-c -// on xkbcommon-keysyms.h, removing the XKB_KEY_ prefixes and manually -// wrapping invalid identifiers with @"" - -pub const Keysym = enum(u32) { - NoSymbol = 0x000000, - VoidSymbol = 0xffffff, - _, - - pub const BackSpace = 0xff08; - pub const Tab = 0xff09; - pub const Linefeed = 0xff0a; - pub const Clear = 0xff0b; - pub const Return = 0xff0d; - pub const Pause = 0xff13; - pub const Scroll_Lock = 0xff14; - pub const Sys_Req = 0xff15; - pub const Escape = 0xff1b; - pub const Delete = 0xffff; - pub const Multi_key = 0xff20; - pub const Codeinput = 0xff37; - pub const SingleCandidate = 0xff3c; - pub const MultipleCandidate = 0xff3d; - pub const PreviousCandidate = 0xff3e; - pub const Kanji = 0xff21; - pub const Muhenkan = 0xff22; - pub const Henkan_Mode = 0xff23; - pub const Henkan = 0xff23; - pub const Romaji = 0xff24; - pub const Hiragana = 0xff25; - pub const Katakana = 0xff26; - pub const Hiragana_Katakana = 0xff27; - pub const Zenkaku = 0xff28; - pub const Hankaku = 0xff29; - pub const Zenkaku_Hankaku = 0xff2a; - pub const Touroku = 0xff2b; - pub const Massyo = 0xff2c; - pub const Kana_Lock = 0xff2d; - pub const Kana_Shift = 0xff2e; - pub const Eisu_Shift = 0xff2f; - pub const Eisu_toggle = 0xff30; - pub const Kanji_Bangou = 0xff37; - pub const Zen_Koho = 0xff3d; - pub const Mae_Koho = 0xff3e; - pub const Home = 0xff50; - pub const Left = 0xff51; - pub const Up = 0xff52; - pub const Right = 0xff53; - pub const Down = 0xff54; - pub const Prior = 0xff55; - pub const Page_Up = 0xff55; - pub const Next = 0xff56; - pub const Page_Down = 0xff56; - pub const End = 0xff57; - pub const Begin = 0xff58; - pub const Select = 0xff60; - pub const Print = 0xff61; - pub const Execute = 0xff62; - pub const Insert = 0xff63; - pub const Undo = 0xff65; - pub const Redo = 0xff66; - pub const Menu = 0xff67; - pub const Find = 0xff68; - pub const Cancel = 0xff69; - pub const Help = 0xff6a; - pub const Break = 0xff6b; - pub const Mode_switch = 0xff7e; - pub const script_switch = 0xff7e; - pub const Num_Lock = 0xff7f; - pub const KP_Space = 0xff80; - pub const KP_Tab = 0xff89; - pub const KP_Enter = 0xff8d; - pub const KP_F1 = 0xff91; - pub const KP_F2 = 0xff92; - pub const KP_F3 = 0xff93; - pub const KP_F4 = 0xff94; - pub const KP_Home = 0xff95; - pub const KP_Left = 0xff96; - pub const KP_Up = 0xff97; - pub const KP_Right = 0xff98; - pub const KP_Down = 0xff99; - pub const KP_Prior = 0xff9a; - pub const KP_Page_Up = 0xff9a; - pub const KP_Next = 0xff9b; - pub const KP_Page_Down = 0xff9b; - pub const KP_End = 0xff9c; - pub const KP_Begin = 0xff9d; - pub const KP_Insert = 0xff9e; - pub const KP_Delete = 0xff9f; - pub const KP_Equal = 0xffbd; - pub const KP_Multiply = 0xffaa; - pub const KP_Add = 0xffab; - pub const KP_Separator = 0xffac; - pub const KP_Subtract = 0xffad; - pub const KP_Decimal = 0xffae; - pub const KP_Divide = 0xffaf; - pub const KP_0 = 0xffb0; - pub const KP_1 = 0xffb1; - pub const KP_2 = 0xffb2; - pub const KP_3 = 0xffb3; - pub const KP_4 = 0xffb4; - pub const KP_5 = 0xffb5; - pub const KP_6 = 0xffb6; - pub const KP_7 = 0xffb7; - pub const KP_8 = 0xffb8; - pub const KP_9 = 0xffb9; - pub const F1 = 0xffbe; - pub const F2 = 0xffbf; - pub const F3 = 0xffc0; - pub const F4 = 0xffc1; - pub const F5 = 0xffc2; - pub const F6 = 0xffc3; - pub const F7 = 0xffc4; - pub const F8 = 0xffc5; - pub const F9 = 0xffc6; - pub const F10 = 0xffc7; - pub const F11 = 0xffc8; - pub const L1 = 0xffc8; - pub const F12 = 0xffc9; - pub const L2 = 0xffc9; - pub const F13 = 0xffca; - pub const L3 = 0xffca; - pub const F14 = 0xffcb; - pub const L4 = 0xffcb; - pub const F15 = 0xffcc; - pub const L5 = 0xffcc; - pub const F16 = 0xffcd; - pub const L6 = 0xffcd; - pub const F17 = 0xffce; - pub const L7 = 0xffce; - pub const F18 = 0xffcf; - pub const L8 = 0xffcf; - pub const F19 = 0xffd0; - pub const L9 = 0xffd0; - pub const F20 = 0xffd1; - pub const L10 = 0xffd1; - pub const F21 = 0xffd2; - pub const R1 = 0xffd2; - pub const F22 = 0xffd3; - pub const R2 = 0xffd3; - pub const F23 = 0xffd4; - pub const R3 = 0xffd4; - pub const F24 = 0xffd5; - pub const R4 = 0xffd5; - pub const F25 = 0xffd6; - pub const R5 = 0xffd6; - pub const F26 = 0xffd7; - pub const R6 = 0xffd7; - pub const F27 = 0xffd8; - pub const R7 = 0xffd8; - pub const F28 = 0xffd9; - pub const R8 = 0xffd9; - pub const F29 = 0xffda; - pub const R9 = 0xffda; - pub const F30 = 0xffdb; - pub const R10 = 0xffdb; - pub const F31 = 0xffdc; - pub const R11 = 0xffdc; - pub const F32 = 0xffdd; - pub const R12 = 0xffdd; - pub const F33 = 0xffde; - pub const R13 = 0xffde; - pub const F34 = 0xffdf; - pub const R14 = 0xffdf; - pub const F35 = 0xffe0; - pub const R15 = 0xffe0; - pub const Shift_L = 0xffe1; - pub const Shift_R = 0xffe2; - pub const Control_L = 0xffe3; - pub const Control_R = 0xffe4; - pub const Caps_Lock = 0xffe5; - pub const Shift_Lock = 0xffe6; - pub const Meta_L = 0xffe7; - pub const Meta_R = 0xffe8; - pub const Alt_L = 0xffe9; - pub const Alt_R = 0xffea; - pub const Super_L = 0xffeb; - pub const Super_R = 0xffec; - pub const Hyper_L = 0xffed; - pub const Hyper_R = 0xffee; - pub const ISO_Lock = 0xfe01; - pub const ISO_Level2_Latch = 0xfe02; - pub const ISO_Level3_Shift = 0xfe03; - pub const ISO_Level3_Latch = 0xfe04; - pub const ISO_Level3_Lock = 0xfe05; - pub const ISO_Level5_Shift = 0xfe11; - pub const ISO_Level5_Latch = 0xfe12; - pub const ISO_Level5_Lock = 0xfe13; - pub const ISO_Group_Shift = 0xff7e; - pub const ISO_Group_Latch = 0xfe06; - pub const ISO_Group_Lock = 0xfe07; - pub const ISO_Next_Group = 0xfe08; - pub const ISO_Next_Group_Lock = 0xfe09; - pub const ISO_Prev_Group = 0xfe0a; - pub const ISO_Prev_Group_Lock = 0xfe0b; - pub const ISO_First_Group = 0xfe0c; - pub const ISO_First_Group_Lock = 0xfe0d; - pub const ISO_Last_Group = 0xfe0e; - pub const ISO_Last_Group_Lock = 0xfe0f; - pub const ISO_Left_Tab = 0xfe20; - pub const ISO_Move_Line_Up = 0xfe21; - pub const ISO_Move_Line_Down = 0xfe22; - pub const ISO_Partial_Line_Up = 0xfe23; - pub const ISO_Partial_Line_Down = 0xfe24; - pub const ISO_Partial_Space_Left = 0xfe25; - pub const ISO_Partial_Space_Right = 0xfe26; - pub const ISO_Set_Margin_Left = 0xfe27; - pub const ISO_Set_Margin_Right = 0xfe28; - pub const ISO_Release_Margin_Left = 0xfe29; - pub const ISO_Release_Margin_Right = 0xfe2a; - pub const ISO_Release_Both_Margins = 0xfe2b; - pub const ISO_Fast_Cursor_Left = 0xfe2c; - pub const ISO_Fast_Cursor_Right = 0xfe2d; - pub const ISO_Fast_Cursor_Up = 0xfe2e; - pub const ISO_Fast_Cursor_Down = 0xfe2f; - pub const ISO_Continuous_Underline = 0xfe30; - pub const ISO_Discontinuous_Underline = 0xfe31; - pub const ISO_Emphasize = 0xfe32; - pub const ISO_Center_Object = 0xfe33; - pub const ISO_Enter = 0xfe34; - pub const dead_grave = 0xfe50; - pub const dead_acute = 0xfe51; - pub const dead_circumflex = 0xfe52; - pub const dead_tilde = 0xfe53; - pub const dead_perispomeni = 0xfe53; - pub const dead_macron = 0xfe54; - pub const dead_breve = 0xfe55; - pub const dead_abovedot = 0xfe56; - pub const dead_diaeresis = 0xfe57; - pub const dead_abovering = 0xfe58; - pub const dead_doubleacute = 0xfe59; - pub const dead_caron = 0xfe5a; - pub const dead_cedilla = 0xfe5b; - pub const dead_ogonek = 0xfe5c; - pub const dead_iota = 0xfe5d; - pub const dead_voiced_sound = 0xfe5e; - pub const dead_semivoiced_sound = 0xfe5f; - pub const dead_belowdot = 0xfe60; - pub const dead_hook = 0xfe61; - pub const dead_horn = 0xfe62; - pub const dead_stroke = 0xfe63; - pub const dead_abovecomma = 0xfe64; - pub const dead_psili = 0xfe64; - pub const dead_abovereversedcomma = 0xfe65; - pub const dead_dasia = 0xfe65; - pub const dead_doublegrave = 0xfe66; - pub const dead_belowring = 0xfe67; - pub const dead_belowmacron = 0xfe68; - pub const dead_belowcircumflex = 0xfe69; - pub const dead_belowtilde = 0xfe6a; - pub const dead_belowbreve = 0xfe6b; - pub const dead_belowdiaeresis = 0xfe6c; - pub const dead_invertedbreve = 0xfe6d; - pub const dead_belowcomma = 0xfe6e; - pub const dead_currency = 0xfe6f; - pub const dead_a = 0xfe80; - pub const dead_A = 0xfe81; - pub const dead_e = 0xfe82; - pub const dead_E = 0xfe83; - pub const dead_i = 0xfe84; - pub const dead_I = 0xfe85; - pub const dead_o = 0xfe86; - pub const dead_O = 0xfe87; - pub const dead_u = 0xfe88; - pub const dead_U = 0xfe89; - pub const dead_schwa = 0xfe8a; - pub const dead_SCHWA = 0xfe8b; - pub const dead_small_schwa = 0xfe8a; - pub const dead_capital_schwa = 0xfe8b; - pub const dead_greek = 0xfe8c; - pub const dead_hamza = 0xfe8d; - pub const First_Virtual_Screen = 0xfed0; - pub const Prev_Virtual_Screen = 0xfed1; - pub const Next_Virtual_Screen = 0xfed2; - pub const Last_Virtual_Screen = 0xfed4; - pub const Terminate_Server = 0xfed5; - pub const AccessX_Enable = 0xfe70; - pub const AccessX_Feedback_Enable = 0xfe71; - pub const RepeatKeys_Enable = 0xfe72; - pub const SlowKeys_Enable = 0xfe73; - pub const BounceKeys_Enable = 0xfe74; - pub const StickyKeys_Enable = 0xfe75; - pub const MouseKeys_Enable = 0xfe76; - pub const MouseKeys_Accel_Enable = 0xfe77; - pub const Overlay1_Enable = 0xfe78; - pub const Overlay2_Enable = 0xfe79; - pub const AudibleBell_Enable = 0xfe7a; - pub const Pointer_Left = 0xfee0; - pub const Pointer_Right = 0xfee1; - pub const Pointer_Up = 0xfee2; - pub const Pointer_Down = 0xfee3; - pub const Pointer_UpLeft = 0xfee4; - pub const Pointer_UpRight = 0xfee5; - pub const Pointer_DownLeft = 0xfee6; - pub const Pointer_DownRight = 0xfee7; - pub const Pointer_Button_Dflt = 0xfee8; - pub const Pointer_Button1 = 0xfee9; - pub const Pointer_Button2 = 0xfeea; - pub const Pointer_Button3 = 0xfeeb; - pub const Pointer_Button4 = 0xfeec; - pub const Pointer_Button5 = 0xfeed; - pub const Pointer_DblClick_Dflt = 0xfeee; - pub const Pointer_DblClick1 = 0xfeef; - pub const Pointer_DblClick2 = 0xfef0; - pub const Pointer_DblClick3 = 0xfef1; - pub const Pointer_DblClick4 = 0xfef2; - pub const Pointer_DblClick5 = 0xfef3; - pub const Pointer_Drag_Dflt = 0xfef4; - pub const Pointer_Drag1 = 0xfef5; - pub const Pointer_Drag2 = 0xfef6; - pub const Pointer_Drag3 = 0xfef7; - pub const Pointer_Drag4 = 0xfef8; - pub const Pointer_Drag5 = 0xfefd; - pub const Pointer_EnableKeys = 0xfef9; - pub const Pointer_Accelerate = 0xfefa; - pub const Pointer_DfltBtnNext = 0xfefb; - pub const Pointer_DfltBtnPrev = 0xfefc; - pub const ch = 0xfea0; - pub const Ch = 0xfea1; - pub const CH = 0xfea2; - pub const c_h = 0xfea3; - pub const C_h = 0xfea4; - pub const C_H = 0xfea5; - pub const @"3270_Duplicate" = 0xfd01; - pub const @"3270_FieldMark" = 0xfd02; - pub const @"3270_Right2" = 0xfd03; - pub const @"3270_Left2" = 0xfd04; - pub const @"3270_BackTab" = 0xfd05; - pub const @"3270_EraseEOF" = 0xfd06; - pub const @"3270_EraseInput" = 0xfd07; - pub const @"3270_Reset" = 0xfd08; - pub const @"3270_Quit" = 0xfd09; - pub const @"3270_PA1" = 0xfd0a; - pub const @"3270_PA2" = 0xfd0b; - pub const @"3270_PA3" = 0xfd0c; - pub const @"3270_Test" = 0xfd0d; - pub const @"3270_Attn" = 0xfd0e; - pub const @"3270_CursorBlink" = 0xfd0f; - pub const @"3270_AltCursor" = 0xfd10; - pub const @"3270_KeyClick" = 0xfd11; - pub const @"3270_Jump" = 0xfd12; - pub const @"3270_Ident" = 0xfd13; - pub const @"3270_Rule" = 0xfd14; - pub const @"3270_Copy" = 0xfd15; - pub const @"3270_Play" = 0xfd16; - pub const @"3270_Setup" = 0xfd17; - pub const @"3270_Record" = 0xfd18; - pub const @"3270_ChangeScreen" = 0xfd19; - pub const @"3270_DeleteWord" = 0xfd1a; - pub const @"3270_ExSelect" = 0xfd1b; - pub const @"3270_CursorSelect" = 0xfd1c; - pub const @"3270_PrintScreen" = 0xfd1d; - pub const @"3270_Enter" = 0xfd1e; - pub const space = 0x0020; - pub const exclam = 0x0021; - pub const quotedbl = 0x0022; - pub const numbersign = 0x0023; - pub const dollar = 0x0024; - pub const percent = 0x0025; - pub const ampersand = 0x0026; - pub const apostrophe = 0x0027; - pub const quoteright = 0x0027; - pub const parenleft = 0x0028; - pub const parenright = 0x0029; - pub const asterisk = 0x002a; - pub const plus = 0x002b; - pub const comma = 0x002c; - pub const minus = 0x002d; - pub const period = 0x002e; - pub const slash = 0x002f; - pub const @"0" = 0x0030; - pub const @"1" = 0x0031; - pub const @"2" = 0x0032; - pub const @"3" = 0x0033; - pub const @"4" = 0x0034; - pub const @"5" = 0x0035; - pub const @"6" = 0x0036; - pub const @"7" = 0x0037; - pub const @"8" = 0x0038; - pub const @"9" = 0x0039; - pub const colon = 0x003a; - pub const semicolon = 0x003b; - pub const less = 0x003c; - pub const equal = 0x003d; - pub const greater = 0x003e; - pub const question = 0x003f; - pub const at = 0x0040; - pub const A = 0x0041; - pub const B = 0x0042; - pub const C = 0x0043; - pub const D = 0x0044; - pub const E = 0x0045; - pub const F = 0x0046; - pub const G = 0x0047; - pub const H = 0x0048; - pub const I = 0x0049; - pub const J = 0x004a; - pub const K = 0x004b; - pub const L = 0x004c; - pub const M = 0x004d; - pub const N = 0x004e; - pub const O = 0x004f; - pub const P = 0x0050; - pub const Q = 0x0051; - pub const R = 0x0052; - pub const S = 0x0053; - pub const T = 0x0054; - pub const U = 0x0055; - pub const V = 0x0056; - pub const W = 0x0057; - pub const X = 0x0058; - pub const Y = 0x0059; - pub const Z = 0x005a; - pub const bracketleft = 0x005b; - pub const backslash = 0x005c; - pub const bracketright = 0x005d; - pub const asciicircum = 0x005e; - pub const underscore = 0x005f; - pub const grave = 0x0060; - pub const quoteleft = 0x0060; - pub const a = 0x0061; - pub const b = 0x0062; - pub const c = 0x0063; - pub const d = 0x0064; - pub const e = 0x0065; - pub const f = 0x0066; - pub const g = 0x0067; - pub const h = 0x0068; - pub const i = 0x0069; - pub const j = 0x006a; - pub const k = 0x006b; - pub const l = 0x006c; - pub const m = 0x006d; - pub const n = 0x006e; - pub const o = 0x006f; - pub const p = 0x0070; - pub const q = 0x0071; - pub const r = 0x0072; - pub const s = 0x0073; - pub const t = 0x0074; - pub const u = 0x0075; - pub const v = 0x0076; - pub const w = 0x0077; - pub const x = 0x0078; - pub const y = 0x0079; - pub const z = 0x007a; - pub const braceleft = 0x007b; - pub const bar = 0x007c; - pub const braceright = 0x007d; - pub const asciitilde = 0x007e; - pub const nobreakspace = 0x00a0; - pub const exclamdown = 0x00a1; - pub const cent = 0x00a2; - pub const sterling = 0x00a3; - pub const currency = 0x00a4; - pub const yen = 0x00a5; - pub const brokenbar = 0x00a6; - pub const section = 0x00a7; - pub const diaeresis = 0x00a8; - pub const copyright = 0x00a9; - pub const ordfeminine = 0x00aa; - pub const guillemetleft = 0x00ab; - pub const guillemotleft = 0x00ab; - pub const notsign = 0x00ac; - pub const hyphen = 0x00ad; - pub const registered = 0x00ae; - pub const macron = 0x00af; - pub const degree = 0x00b0; - pub const plusminus = 0x00b1; - pub const twosuperior = 0x00b2; - pub const threesuperior = 0x00b3; - pub const acute = 0x00b4; - pub const mu = 0x00b5; - pub const paragraph = 0x00b6; - pub const periodcentered = 0x00b7; - pub const cedilla = 0x00b8; - pub const onesuperior = 0x00b9; - pub const ordmasculine = 0x00ba; - pub const masculine = 0x00ba; - pub const guillemetright = 0x00bb; - pub const guillemotright = 0x00bb; - pub const onequarter = 0x00bc; - pub const onehalf = 0x00bd; - pub const threequarters = 0x00be; - pub const questiondown = 0x00bf; - pub const Agrave = 0x00c0; - pub const Aacute = 0x00c1; - pub const Acircumflex = 0x00c2; - pub const Atilde = 0x00c3; - pub const Adiaeresis = 0x00c4; - pub const Aring = 0x00c5; - pub const AE = 0x00c6; - pub const Ccedilla = 0x00c7; - pub const Egrave = 0x00c8; - pub const Eacute = 0x00c9; - pub const Ecircumflex = 0x00ca; - pub const Ediaeresis = 0x00cb; - pub const Igrave = 0x00cc; - pub const Iacute = 0x00cd; - pub const Icircumflex = 0x00ce; - pub const Idiaeresis = 0x00cf; - pub const ETH = 0x00d0; - pub const Eth = 0x00d0; - pub const Ntilde = 0x00d1; - pub const Ograve = 0x00d2; - pub const Oacute = 0x00d3; - pub const Ocircumflex = 0x00d4; - pub const Otilde = 0x00d5; - pub const Odiaeresis = 0x00d6; - pub const multiply = 0x00d7; - pub const Oslash = 0x00d8; - pub const Ooblique = 0x00d8; - pub const Ugrave = 0x00d9; - pub const Uacute = 0x00da; - pub const Ucircumflex = 0x00db; - pub const Udiaeresis = 0x00dc; - pub const Yacute = 0x00dd; - pub const THORN = 0x00de; - pub const Thorn = 0x00de; - pub const ssharp = 0x00df; - pub const agrave = 0x00e0; - pub const aacute = 0x00e1; - pub const acircumflex = 0x00e2; - pub const atilde = 0x00e3; - pub const adiaeresis = 0x00e4; - pub const aring = 0x00e5; - pub const ae = 0x00e6; - pub const ccedilla = 0x00e7; - pub const egrave = 0x00e8; - pub const eacute = 0x00e9; - pub const ecircumflex = 0x00ea; - pub const ediaeresis = 0x00eb; - pub const igrave = 0x00ec; - pub const iacute = 0x00ed; - pub const icircumflex = 0x00ee; - pub const idiaeresis = 0x00ef; - pub const eth = 0x00f0; - pub const ntilde = 0x00f1; - pub const ograve = 0x00f2; - pub const oacute = 0x00f3; - pub const ocircumflex = 0x00f4; - pub const otilde = 0x00f5; - pub const odiaeresis = 0x00f6; - pub const division = 0x00f7; - pub const oslash = 0x00f8; - pub const ooblique = 0x00f8; - pub const ugrave = 0x00f9; - pub const uacute = 0x00fa; - pub const ucircumflex = 0x00fb; - pub const udiaeresis = 0x00fc; - pub const yacute = 0x00fd; - pub const thorn = 0x00fe; - pub const ydiaeresis = 0x00ff; - pub const Aogonek = 0x01a1; - pub const breve = 0x01a2; - pub const Lstroke = 0x01a3; - pub const Lcaron = 0x01a5; - pub const Sacute = 0x01a6; - pub const Scaron = 0x01a9; - pub const Scedilla = 0x01aa; - pub const Tcaron = 0x01ab; - pub const Zacute = 0x01ac; - pub const Zcaron = 0x01ae; - pub const Zabovedot = 0x01af; - pub const aogonek = 0x01b1; - pub const ogonek = 0x01b2; - pub const lstroke = 0x01b3; - pub const lcaron = 0x01b5; - pub const sacute = 0x01b6; - pub const caron = 0x01b7; - pub const scaron = 0x01b9; - pub const scedilla = 0x01ba; - pub const tcaron = 0x01bb; - pub const zacute = 0x01bc; - pub const doubleacute = 0x01bd; - pub const zcaron = 0x01be; - pub const zabovedot = 0x01bf; - pub const Racute = 0x01c0; - pub const Abreve = 0x01c3; - pub const Lacute = 0x01c5; - pub const Cacute = 0x01c6; - pub const Ccaron = 0x01c8; - pub const Eogonek = 0x01ca; - pub const Ecaron = 0x01cc; - pub const Dcaron = 0x01cf; - pub const Dstroke = 0x01d0; - pub const Nacute = 0x01d1; - pub const Ncaron = 0x01d2; - pub const Odoubleacute = 0x01d5; - pub const Rcaron = 0x01d8; - pub const Uring = 0x01d9; - pub const Udoubleacute = 0x01db; - pub const Tcedilla = 0x01de; - pub const racute = 0x01e0; - pub const abreve = 0x01e3; - pub const lacute = 0x01e5; - pub const cacute = 0x01e6; - pub const ccaron = 0x01e8; - pub const eogonek = 0x01ea; - pub const ecaron = 0x01ec; - pub const dcaron = 0x01ef; - pub const dstroke = 0x01f0; - pub const nacute = 0x01f1; - pub const ncaron = 0x01f2; - pub const odoubleacute = 0x01f5; - pub const rcaron = 0x01f8; - pub const uring = 0x01f9; - pub const udoubleacute = 0x01fb; - pub const tcedilla = 0x01fe; - pub const abovedot = 0x01ff; - pub const Hstroke = 0x02a1; - pub const Hcircumflex = 0x02a6; - pub const Iabovedot = 0x02a9; - pub const Gbreve = 0x02ab; - pub const Jcircumflex = 0x02ac; - pub const hstroke = 0x02b1; - pub const hcircumflex = 0x02b6; - pub const idotless = 0x02b9; - pub const gbreve = 0x02bb; - pub const jcircumflex = 0x02bc; - pub const Cabovedot = 0x02c5; - pub const Ccircumflex = 0x02c6; - pub const Gabovedot = 0x02d5; - pub const Gcircumflex = 0x02d8; - pub const Ubreve = 0x02dd; - pub const Scircumflex = 0x02de; - pub const cabovedot = 0x02e5; - pub const ccircumflex = 0x02e6; - pub const gabovedot = 0x02f5; - pub const gcircumflex = 0x02f8; - pub const ubreve = 0x02fd; - pub const scircumflex = 0x02fe; - pub const kra = 0x03a2; - pub const kappa = 0x03a2; - pub const Rcedilla = 0x03a3; - pub const Itilde = 0x03a5; - pub const Lcedilla = 0x03a6; - pub const Emacron = 0x03aa; - pub const Gcedilla = 0x03ab; - pub const Tslash = 0x03ac; - pub const rcedilla = 0x03b3; - pub const itilde = 0x03b5; - pub const lcedilla = 0x03b6; - pub const emacron = 0x03ba; - pub const gcedilla = 0x03bb; - pub const tslash = 0x03bc; - pub const ENG = 0x03bd; - pub const eng = 0x03bf; - pub const Amacron = 0x03c0; - pub const Iogonek = 0x03c7; - pub const Eabovedot = 0x03cc; - pub const Imacron = 0x03cf; - pub const Ncedilla = 0x03d1; - pub const Omacron = 0x03d2; - pub const Kcedilla = 0x03d3; - pub const Uogonek = 0x03d9; - pub const Utilde = 0x03dd; - pub const Umacron = 0x03de; - pub const amacron = 0x03e0; - pub const iogonek = 0x03e7; - pub const eabovedot = 0x03ec; - pub const imacron = 0x03ef; - pub const ncedilla = 0x03f1; - pub const omacron = 0x03f2; - pub const kcedilla = 0x03f3; - pub const uogonek = 0x03f9; - pub const utilde = 0x03fd; - pub const umacron = 0x03fe; - pub const Wcircumflex = 0x1000174; - pub const wcircumflex = 0x1000175; - pub const Ycircumflex = 0x1000176; - pub const ycircumflex = 0x1000177; - pub const Babovedot = 0x1001e02; - pub const babovedot = 0x1001e03; - pub const Dabovedot = 0x1001e0a; - pub const dabovedot = 0x1001e0b; - pub const Fabovedot = 0x1001e1e; - pub const fabovedot = 0x1001e1f; - pub const Mabovedot = 0x1001e40; - pub const mabovedot = 0x1001e41; - pub const Pabovedot = 0x1001e56; - pub const pabovedot = 0x1001e57; - pub const Sabovedot = 0x1001e60; - pub const sabovedot = 0x1001e61; - pub const Tabovedot = 0x1001e6a; - pub const tabovedot = 0x1001e6b; - pub const Wgrave = 0x1001e80; - pub const wgrave = 0x1001e81; - pub const Wacute = 0x1001e82; - pub const wacute = 0x1001e83; - pub const Wdiaeresis = 0x1001e84; - pub const wdiaeresis = 0x1001e85; - pub const Ygrave = 0x1001ef2; - pub const ygrave = 0x1001ef3; - pub const OE = 0x13bc; - pub const oe = 0x13bd; - pub const Ydiaeresis = 0x13be; - pub const overline = 0x047e; - pub const kana_fullstop = 0x04a1; - pub const kana_openingbracket = 0x04a2; - pub const kana_closingbracket = 0x04a3; - pub const kana_comma = 0x04a4; - pub const kana_conjunctive = 0x04a5; - pub const kana_middledot = 0x04a5; - pub const kana_WO = 0x04a6; - pub const kana_a = 0x04a7; - pub const kana_i = 0x04a8; - pub const kana_u = 0x04a9; - pub const kana_e = 0x04aa; - pub const kana_o = 0x04ab; - pub const kana_ya = 0x04ac; - pub const kana_yu = 0x04ad; - pub const kana_yo = 0x04ae; - pub const kana_tsu = 0x04af; - pub const kana_tu = 0x04af; - pub const prolongedsound = 0x04b0; - pub const kana_A = 0x04b1; - pub const kana_I = 0x04b2; - pub const kana_U = 0x04b3; - pub const kana_E = 0x04b4; - pub const kana_O = 0x04b5; - pub const kana_KA = 0x04b6; - pub const kana_KI = 0x04b7; - pub const kana_KU = 0x04b8; - pub const kana_KE = 0x04b9; - pub const kana_KO = 0x04ba; - pub const kana_SA = 0x04bb; - pub const kana_SHI = 0x04bc; - pub const kana_SU = 0x04bd; - pub const kana_SE = 0x04be; - pub const kana_SO = 0x04bf; - pub const kana_TA = 0x04c0; - pub const kana_CHI = 0x04c1; - pub const kana_TI = 0x04c1; - pub const kana_TSU = 0x04c2; - pub const kana_TU = 0x04c2; - pub const kana_TE = 0x04c3; - pub const kana_TO = 0x04c4; - pub const kana_NA = 0x04c5; - pub const kana_NI = 0x04c6; - pub const kana_NU = 0x04c7; - pub const kana_NE = 0x04c8; - pub const kana_NO = 0x04c9; - pub const kana_HA = 0x04ca; - pub const kana_HI = 0x04cb; - pub const kana_FU = 0x04cc; - pub const kana_HU = 0x04cc; - pub const kana_HE = 0x04cd; - pub const kana_HO = 0x04ce; - pub const kana_MA = 0x04cf; - pub const kana_MI = 0x04d0; - pub const kana_MU = 0x04d1; - pub const kana_ME = 0x04d2; - pub const kana_MO = 0x04d3; - pub const kana_YA = 0x04d4; - pub const kana_YU = 0x04d5; - pub const kana_YO = 0x04d6; - pub const kana_RA = 0x04d7; - pub const kana_RI = 0x04d8; - pub const kana_RU = 0x04d9; - pub const kana_RE = 0x04da; - pub const kana_RO = 0x04db; - pub const kana_WA = 0x04dc; - pub const kana_N = 0x04dd; - pub const voicedsound = 0x04de; - pub const semivoicedsound = 0x04df; - pub const kana_switch = 0xff7e; - pub const Farsi_0 = 0x10006f0; - pub const Farsi_1 = 0x10006f1; - pub const Farsi_2 = 0x10006f2; - pub const Farsi_3 = 0x10006f3; - pub const Farsi_4 = 0x10006f4; - pub const Farsi_5 = 0x10006f5; - pub const Farsi_6 = 0x10006f6; - pub const Farsi_7 = 0x10006f7; - pub const Farsi_8 = 0x10006f8; - pub const Farsi_9 = 0x10006f9; - pub const Arabic_percent = 0x100066a; - pub const Arabic_superscript_alef = 0x1000670; - pub const Arabic_tteh = 0x1000679; - pub const Arabic_peh = 0x100067e; - pub const Arabic_tcheh = 0x1000686; - pub const Arabic_ddal = 0x1000688; - pub const Arabic_rreh = 0x1000691; - pub const Arabic_comma = 0x05ac; - pub const Arabic_fullstop = 0x10006d4; - pub const Arabic_0 = 0x1000660; - pub const Arabic_1 = 0x1000661; - pub const Arabic_2 = 0x1000662; - pub const Arabic_3 = 0x1000663; - pub const Arabic_4 = 0x1000664; - pub const Arabic_5 = 0x1000665; - pub const Arabic_6 = 0x1000666; - pub const Arabic_7 = 0x1000667; - pub const Arabic_8 = 0x1000668; - pub const Arabic_9 = 0x1000669; - pub const Arabic_semicolon = 0x05bb; - pub const Arabic_question_mark = 0x05bf; - pub const Arabic_hamza = 0x05c1; - pub const Arabic_maddaonalef = 0x05c2; - pub const Arabic_hamzaonalef = 0x05c3; - pub const Arabic_hamzaonwaw = 0x05c4; - pub const Arabic_hamzaunderalef = 0x05c5; - pub const Arabic_hamzaonyeh = 0x05c6; - pub const Arabic_alef = 0x05c7; - pub const Arabic_beh = 0x05c8; - pub const Arabic_tehmarbuta = 0x05c9; - pub const Arabic_teh = 0x05ca; - pub const Arabic_theh = 0x05cb; - pub const Arabic_jeem = 0x05cc; - pub const Arabic_hah = 0x05cd; - pub const Arabic_khah = 0x05ce; - pub const Arabic_dal = 0x05cf; - pub const Arabic_thal = 0x05d0; - pub const Arabic_ra = 0x05d1; - pub const Arabic_zain = 0x05d2; - pub const Arabic_seen = 0x05d3; - pub const Arabic_sheen = 0x05d4; - pub const Arabic_sad = 0x05d5; - pub const Arabic_dad = 0x05d6; - pub const Arabic_tah = 0x05d7; - pub const Arabic_zah = 0x05d8; - pub const Arabic_ain = 0x05d9; - pub const Arabic_ghain = 0x05da; - pub const Arabic_tatweel = 0x05e0; - pub const Arabic_feh = 0x05e1; - pub const Arabic_qaf = 0x05e2; - pub const Arabic_kaf = 0x05e3; - pub const Arabic_lam = 0x05e4; - pub const Arabic_meem = 0x05e5; - pub const Arabic_noon = 0x05e6; - pub const Arabic_ha = 0x05e7; - pub const Arabic_heh = 0x05e7; - pub const Arabic_waw = 0x05e8; - pub const Arabic_alefmaksura = 0x05e9; - pub const Arabic_yeh = 0x05ea; - pub const Arabic_fathatan = 0x05eb; - pub const Arabic_dammatan = 0x05ec; - pub const Arabic_kasratan = 0x05ed; - pub const Arabic_fatha = 0x05ee; - pub const Arabic_damma = 0x05ef; - pub const Arabic_kasra = 0x05f0; - pub const Arabic_shadda = 0x05f1; - pub const Arabic_sukun = 0x05f2; - pub const Arabic_madda_above = 0x1000653; - pub const Arabic_hamza_above = 0x1000654; - pub const Arabic_hamza_below = 0x1000655; - pub const Arabic_jeh = 0x1000698; - pub const Arabic_veh = 0x10006a4; - pub const Arabic_keheh = 0x10006a9; - pub const Arabic_gaf = 0x10006af; - pub const Arabic_noon_ghunna = 0x10006ba; - pub const Arabic_heh_doachashmee = 0x10006be; - pub const Farsi_yeh = 0x10006cc; - pub const Arabic_farsi_yeh = 0x10006cc; - pub const Arabic_yeh_baree = 0x10006d2; - pub const Arabic_heh_goal = 0x10006c1; - pub const Arabic_switch = 0xff7e; - pub const Cyrillic_GHE_bar = 0x1000492; - pub const Cyrillic_ghe_bar = 0x1000493; - pub const Cyrillic_ZHE_descender = 0x1000496; - pub const Cyrillic_zhe_descender = 0x1000497; - pub const Cyrillic_KA_descender = 0x100049a; - pub const Cyrillic_ka_descender = 0x100049b; - pub const Cyrillic_KA_vertstroke = 0x100049c; - pub const Cyrillic_ka_vertstroke = 0x100049d; - pub const Cyrillic_EN_descender = 0x10004a2; - pub const Cyrillic_en_descender = 0x10004a3; - pub const Cyrillic_U_straight = 0x10004ae; - pub const Cyrillic_u_straight = 0x10004af; - pub const Cyrillic_U_straight_bar = 0x10004b0; - pub const Cyrillic_u_straight_bar = 0x10004b1; - pub const Cyrillic_HA_descender = 0x10004b2; - pub const Cyrillic_ha_descender = 0x10004b3; - pub const Cyrillic_CHE_descender = 0x10004b6; - pub const Cyrillic_che_descender = 0x10004b7; - pub const Cyrillic_CHE_vertstroke = 0x10004b8; - pub const Cyrillic_che_vertstroke = 0x10004b9; - pub const Cyrillic_SHHA = 0x10004ba; - pub const Cyrillic_shha = 0x10004bb; - pub const Cyrillic_SCHWA = 0x10004d8; - pub const Cyrillic_schwa = 0x10004d9; - pub const Cyrillic_I_macron = 0x10004e2; - pub const Cyrillic_i_macron = 0x10004e3; - pub const Cyrillic_O_bar = 0x10004e8; - pub const Cyrillic_o_bar = 0x10004e9; - pub const Cyrillic_U_macron = 0x10004ee; - pub const Cyrillic_u_macron = 0x10004ef; - pub const Serbian_dje = 0x06a1; - pub const Macedonia_gje = 0x06a2; - pub const Cyrillic_io = 0x06a3; - pub const Ukrainian_ie = 0x06a4; - pub const Ukranian_je = 0x06a4; - pub const Macedonia_dse = 0x06a5; - pub const Ukrainian_i = 0x06a6; - pub const Ukranian_i = 0x06a6; - pub const Ukrainian_yi = 0x06a7; - pub const Ukranian_yi = 0x06a7; - pub const Cyrillic_je = 0x06a8; - pub const Serbian_je = 0x06a8; - pub const Cyrillic_lje = 0x06a9; - pub const Serbian_lje = 0x06a9; - pub const Cyrillic_nje = 0x06aa; - pub const Serbian_nje = 0x06aa; - pub const Serbian_tshe = 0x06ab; - pub const Macedonia_kje = 0x06ac; - pub const Ukrainian_ghe_with_upturn = 0x06ad; - pub const Byelorussian_shortu = 0x06ae; - pub const Cyrillic_dzhe = 0x06af; - pub const Serbian_dze = 0x06af; - pub const numerosign = 0x06b0; - pub const Serbian_DJE = 0x06b1; - pub const Macedonia_GJE = 0x06b2; - pub const Cyrillic_IO = 0x06b3; - pub const Ukrainian_IE = 0x06b4; - pub const Ukranian_JE = 0x06b4; - pub const Macedonia_DSE = 0x06b5; - pub const Ukrainian_I = 0x06b6; - pub const Ukranian_I = 0x06b6; - pub const Ukrainian_YI = 0x06b7; - pub const Ukranian_YI = 0x06b7; - pub const Cyrillic_JE = 0x06b8; - pub const Serbian_JE = 0x06b8; - pub const Cyrillic_LJE = 0x06b9; - pub const Serbian_LJE = 0x06b9; - pub const Cyrillic_NJE = 0x06ba; - pub const Serbian_NJE = 0x06ba; - pub const Serbian_TSHE = 0x06bb; - pub const Macedonia_KJE = 0x06bc; - pub const Ukrainian_GHE_WITH_UPTURN = 0x06bd; - pub const Byelorussian_SHORTU = 0x06be; - pub const Cyrillic_DZHE = 0x06bf; - pub const Serbian_DZE = 0x06bf; - pub const Cyrillic_yu = 0x06c0; - pub const Cyrillic_a = 0x06c1; - pub const Cyrillic_be = 0x06c2; - pub const Cyrillic_tse = 0x06c3; - pub const Cyrillic_de = 0x06c4; - pub const Cyrillic_ie = 0x06c5; - pub const Cyrillic_ef = 0x06c6; - pub const Cyrillic_ghe = 0x06c7; - pub const Cyrillic_ha = 0x06c8; - pub const Cyrillic_i = 0x06c9; - pub const Cyrillic_shorti = 0x06ca; - pub const Cyrillic_ka = 0x06cb; - pub const Cyrillic_el = 0x06cc; - pub const Cyrillic_em = 0x06cd; - pub const Cyrillic_en = 0x06ce; - pub const Cyrillic_o = 0x06cf; - pub const Cyrillic_pe = 0x06d0; - pub const Cyrillic_ya = 0x06d1; - pub const Cyrillic_er = 0x06d2; - pub const Cyrillic_es = 0x06d3; - pub const Cyrillic_te = 0x06d4; - pub const Cyrillic_u = 0x06d5; - pub const Cyrillic_zhe = 0x06d6; - pub const Cyrillic_ve = 0x06d7; - pub const Cyrillic_softsign = 0x06d8; - pub const Cyrillic_yeru = 0x06d9; - pub const Cyrillic_ze = 0x06da; - pub const Cyrillic_sha = 0x06db; - pub const Cyrillic_e = 0x06dc; - pub const Cyrillic_shcha = 0x06dd; - pub const Cyrillic_che = 0x06de; - pub const Cyrillic_hardsign = 0x06df; - pub const Cyrillic_YU = 0x06e0; - pub const Cyrillic_A = 0x06e1; - pub const Cyrillic_BE = 0x06e2; - pub const Cyrillic_TSE = 0x06e3; - pub const Cyrillic_DE = 0x06e4; - pub const Cyrillic_IE = 0x06e5; - pub const Cyrillic_EF = 0x06e6; - pub const Cyrillic_GHE = 0x06e7; - pub const Cyrillic_HA = 0x06e8; - pub const Cyrillic_I = 0x06e9; - pub const Cyrillic_SHORTI = 0x06ea; - pub const Cyrillic_KA = 0x06eb; - pub const Cyrillic_EL = 0x06ec; - pub const Cyrillic_EM = 0x06ed; - pub const Cyrillic_EN = 0x06ee; - pub const Cyrillic_O = 0x06ef; - pub const Cyrillic_PE = 0x06f0; - pub const Cyrillic_YA = 0x06f1; - pub const Cyrillic_ER = 0x06f2; - pub const Cyrillic_ES = 0x06f3; - pub const Cyrillic_TE = 0x06f4; - pub const Cyrillic_U = 0x06f5; - pub const Cyrillic_ZHE = 0x06f6; - pub const Cyrillic_VE = 0x06f7; - pub const Cyrillic_SOFTSIGN = 0x06f8; - pub const Cyrillic_YERU = 0x06f9; - pub const Cyrillic_ZE = 0x06fa; - pub const Cyrillic_SHA = 0x06fb; - pub const Cyrillic_E = 0x06fc; - pub const Cyrillic_SHCHA = 0x06fd; - pub const Cyrillic_CHE = 0x06fe; - pub const Cyrillic_HARDSIGN = 0x06ff; - pub const Greek_ALPHAaccent = 0x07a1; - pub const Greek_EPSILONaccent = 0x07a2; - pub const Greek_ETAaccent = 0x07a3; - pub const Greek_IOTAaccent = 0x07a4; - pub const Greek_IOTAdieresis = 0x07a5; - pub const Greek_IOTAdiaeresis = 0x07a5; - pub const Greek_OMICRONaccent = 0x07a7; - pub const Greek_UPSILONaccent = 0x07a8; - pub const Greek_UPSILONdieresis = 0x07a9; - pub const Greek_OMEGAaccent = 0x07ab; - pub const Greek_accentdieresis = 0x07ae; - pub const Greek_horizbar = 0x07af; - pub const Greek_alphaaccent = 0x07b1; - pub const Greek_epsilonaccent = 0x07b2; - pub const Greek_etaaccent = 0x07b3; - pub const Greek_iotaaccent = 0x07b4; - pub const Greek_iotadieresis = 0x07b5; - pub const Greek_iotaaccentdieresis = 0x07b6; - pub const Greek_omicronaccent = 0x07b7; - pub const Greek_upsilonaccent = 0x07b8; - pub const Greek_upsilondieresis = 0x07b9; - pub const Greek_upsilonaccentdieresis = 0x07ba; - pub const Greek_omegaaccent = 0x07bb; - pub const Greek_ALPHA = 0x07c1; - pub const Greek_BETA = 0x07c2; - pub const Greek_GAMMA = 0x07c3; - pub const Greek_DELTA = 0x07c4; - pub const Greek_EPSILON = 0x07c5; - pub const Greek_ZETA = 0x07c6; - pub const Greek_ETA = 0x07c7; - pub const Greek_THETA = 0x07c8; - pub const Greek_IOTA = 0x07c9; - pub const Greek_KAPPA = 0x07ca; - pub const Greek_LAMDA = 0x07cb; - pub const Greek_LAMBDA = 0x07cb; - pub const Greek_MU = 0x07cc; - pub const Greek_NU = 0x07cd; - pub const Greek_XI = 0x07ce; - pub const Greek_OMICRON = 0x07cf; - pub const Greek_PI = 0x07d0; - pub const Greek_RHO = 0x07d1; - pub const Greek_SIGMA = 0x07d2; - pub const Greek_TAU = 0x07d4; - pub const Greek_UPSILON = 0x07d5; - pub const Greek_PHI = 0x07d6; - pub const Greek_CHI = 0x07d7; - pub const Greek_PSI = 0x07d8; - pub const Greek_OMEGA = 0x07d9; - pub const Greek_alpha = 0x07e1; - pub const Greek_beta = 0x07e2; - pub const Greek_gamma = 0x07e3; - pub const Greek_delta = 0x07e4; - pub const Greek_epsilon = 0x07e5; - pub const Greek_zeta = 0x07e6; - pub const Greek_eta = 0x07e7; - pub const Greek_theta = 0x07e8; - pub const Greek_iota = 0x07e9; - pub const Greek_kappa = 0x07ea; - pub const Greek_lamda = 0x07eb; - pub const Greek_lambda = 0x07eb; - pub const Greek_mu = 0x07ec; - pub const Greek_nu = 0x07ed; - pub const Greek_xi = 0x07ee; - pub const Greek_omicron = 0x07ef; - pub const Greek_pi = 0x07f0; - pub const Greek_rho = 0x07f1; - pub const Greek_sigma = 0x07f2; - pub const Greek_finalsmallsigma = 0x07f3; - pub const Greek_tau = 0x07f4; - pub const Greek_upsilon = 0x07f5; - pub const Greek_phi = 0x07f6; - pub const Greek_chi = 0x07f7; - pub const Greek_psi = 0x07f8; - pub const Greek_omega = 0x07f9; - pub const Greek_switch = 0xff7e; - pub const leftradical = 0x08a1; - pub const topleftradical = 0x08a2; - pub const horizconnector = 0x08a3; - pub const topintegral = 0x08a4; - pub const botintegral = 0x08a5; - pub const vertconnector = 0x08a6; - pub const topleftsqbracket = 0x08a7; - pub const botleftsqbracket = 0x08a8; - pub const toprightsqbracket = 0x08a9; - pub const botrightsqbracket = 0x08aa; - pub const topleftparens = 0x08ab; - pub const botleftparens = 0x08ac; - pub const toprightparens = 0x08ad; - pub const botrightparens = 0x08ae; - pub const leftmiddlecurlybrace = 0x08af; - pub const rightmiddlecurlybrace = 0x08b0; - pub const topleftsummation = 0x08b1; - pub const botleftsummation = 0x08b2; - pub const topvertsummationconnector = 0x08b3; - pub const botvertsummationconnector = 0x08b4; - pub const toprightsummation = 0x08b5; - pub const botrightsummation = 0x08b6; - pub const rightmiddlesummation = 0x08b7; - pub const lessthanequal = 0x08bc; - pub const notequal = 0x08bd; - pub const greaterthanequal = 0x08be; - pub const integral = 0x08bf; - pub const therefore = 0x08c0; - pub const variation = 0x08c1; - pub const infinity = 0x08c2; - pub const nabla = 0x08c5; - pub const approximate = 0x08c8; - pub const similarequal = 0x08c9; - pub const ifonlyif = 0x08cd; - pub const implies = 0x08ce; - pub const identical = 0x08cf; - pub const radical = 0x08d6; - pub const includedin = 0x08da; - pub const includes = 0x08db; - pub const intersection = 0x08dc; - pub const @"union" = 0x08dd; - pub const logicaland = 0x08de; - pub const logicalor = 0x08df; - pub const partialderivative = 0x08ef; - pub const function = 0x08f6; - pub const leftarrow = 0x08fb; - pub const uparrow = 0x08fc; - pub const rightarrow = 0x08fd; - pub const downarrow = 0x08fe; - pub const blank = 0x09df; - pub const soliddiamond = 0x09e0; - pub const checkerboard = 0x09e1; - pub const ht = 0x09e2; - pub const ff = 0x09e3; - pub const cr = 0x09e4; - pub const lf = 0x09e5; - pub const nl = 0x09e8; - pub const vt = 0x09e9; - pub const lowrightcorner = 0x09ea; - pub const uprightcorner = 0x09eb; - pub const upleftcorner = 0x09ec; - pub const lowleftcorner = 0x09ed; - pub const crossinglines = 0x09ee; - pub const horizlinescan1 = 0x09ef; - pub const horizlinescan3 = 0x09f0; - pub const horizlinescan5 = 0x09f1; - pub const horizlinescan7 = 0x09f2; - pub const horizlinescan9 = 0x09f3; - pub const leftt = 0x09f4; - pub const rightt = 0x09f5; - pub const bott = 0x09f6; - pub const topt = 0x09f7; - pub const vertbar = 0x09f8; - pub const emspace = 0x0aa1; - pub const enspace = 0x0aa2; - pub const em3space = 0x0aa3; - pub const em4space = 0x0aa4; - pub const digitspace = 0x0aa5; - pub const punctspace = 0x0aa6; - pub const thinspace = 0x0aa7; - pub const hairspace = 0x0aa8; - pub const emdash = 0x0aa9; - pub const endash = 0x0aaa; - pub const signifblank = 0x0aac; - pub const ellipsis = 0x0aae; - pub const doubbaselinedot = 0x0aaf; - pub const onethird = 0x0ab0; - pub const twothirds = 0x0ab1; - pub const onefifth = 0x0ab2; - pub const twofifths = 0x0ab3; - pub const threefifths = 0x0ab4; - pub const fourfifths = 0x0ab5; - pub const onesixth = 0x0ab6; - pub const fivesixths = 0x0ab7; - pub const careof = 0x0ab8; - pub const figdash = 0x0abb; - pub const leftanglebracket = 0x0abc; - pub const decimalpoint = 0x0abd; - pub const rightanglebracket = 0x0abe; - pub const marker = 0x0abf; - pub const oneeighth = 0x0ac3; - pub const threeeighths = 0x0ac4; - pub const fiveeighths = 0x0ac5; - pub const seveneighths = 0x0ac6; - pub const trademark = 0x0ac9; - pub const signaturemark = 0x0aca; - pub const trademarkincircle = 0x0acb; - pub const leftopentriangle = 0x0acc; - pub const rightopentriangle = 0x0acd; - pub const emopencircle = 0x0ace; - pub const emopenrectangle = 0x0acf; - pub const leftsinglequotemark = 0x0ad0; - pub const rightsinglequotemark = 0x0ad1; - pub const leftdoublequotemark = 0x0ad2; - pub const rightdoublequotemark = 0x0ad3; - pub const prescription = 0x0ad4; - pub const permille = 0x0ad5; - pub const minutes = 0x0ad6; - pub const seconds = 0x0ad7; - pub const latincross = 0x0ad9; - pub const hexagram = 0x0ada; - pub const filledrectbullet = 0x0adb; - pub const filledlefttribullet = 0x0adc; - pub const filledrighttribullet = 0x0add; - pub const emfilledcircle = 0x0ade; - pub const emfilledrect = 0x0adf; - pub const enopencircbullet = 0x0ae0; - pub const enopensquarebullet = 0x0ae1; - pub const openrectbullet = 0x0ae2; - pub const opentribulletup = 0x0ae3; - pub const opentribulletdown = 0x0ae4; - pub const openstar = 0x0ae5; - pub const enfilledcircbullet = 0x0ae6; - pub const enfilledsqbullet = 0x0ae7; - pub const filledtribulletup = 0x0ae8; - pub const filledtribulletdown = 0x0ae9; - pub const leftpointer = 0x0aea; - pub const rightpointer = 0x0aeb; - pub const club = 0x0aec; - pub const diamond = 0x0aed; - pub const heart = 0x0aee; - pub const maltesecross = 0x0af0; - pub const dagger = 0x0af1; - pub const doubledagger = 0x0af2; - pub const checkmark = 0x0af3; - pub const ballotcross = 0x0af4; - pub const musicalsharp = 0x0af5; - pub const musicalflat = 0x0af6; - pub const malesymbol = 0x0af7; - pub const femalesymbol = 0x0af8; - pub const telephone = 0x0af9; - pub const telephonerecorder = 0x0afa; - pub const phonographcopyright = 0x0afb; - pub const caret = 0x0afc; - pub const singlelowquotemark = 0x0afd; - pub const doublelowquotemark = 0x0afe; - pub const cursor = 0x0aff; - pub const leftcaret = 0x0ba3; - pub const rightcaret = 0x0ba6; - pub const downcaret = 0x0ba8; - pub const upcaret = 0x0ba9; - pub const overbar = 0x0bc0; - pub const downtack = 0x0bc2; - pub const upshoe = 0x0bc3; - pub const downstile = 0x0bc4; - pub const underbar = 0x0bc6; - pub const jot = 0x0bca; - pub const quad = 0x0bcc; - pub const uptack = 0x0bce; - pub const circle = 0x0bcf; - pub const upstile = 0x0bd3; - pub const downshoe = 0x0bd6; - pub const rightshoe = 0x0bd8; - pub const leftshoe = 0x0bda; - pub const lefttack = 0x0bdc; - pub const righttack = 0x0bfc; - pub const hebrew_doublelowline = 0x0cdf; - pub const hebrew_aleph = 0x0ce0; - pub const hebrew_bet = 0x0ce1; - pub const hebrew_beth = 0x0ce1; - pub const hebrew_gimel = 0x0ce2; - pub const hebrew_gimmel = 0x0ce2; - pub const hebrew_dalet = 0x0ce3; - pub const hebrew_daleth = 0x0ce3; - pub const hebrew_he = 0x0ce4; - pub const hebrew_waw = 0x0ce5; - pub const hebrew_zain = 0x0ce6; - pub const hebrew_zayin = 0x0ce6; - pub const hebrew_chet = 0x0ce7; - pub const hebrew_het = 0x0ce7; - pub const hebrew_tet = 0x0ce8; - pub const hebrew_teth = 0x0ce8; - pub const hebrew_yod = 0x0ce9; - pub const hebrew_finalkaph = 0x0cea; - pub const hebrew_kaph = 0x0ceb; - pub const hebrew_lamed = 0x0cec; - pub const hebrew_finalmem = 0x0ced; - pub const hebrew_mem = 0x0cee; - pub const hebrew_finalnun = 0x0cef; - pub const hebrew_nun = 0x0cf0; - pub const hebrew_samech = 0x0cf1; - pub const hebrew_samekh = 0x0cf1; - pub const hebrew_ayin = 0x0cf2; - pub const hebrew_finalpe = 0x0cf3; - pub const hebrew_pe = 0x0cf4; - pub const hebrew_finalzade = 0x0cf5; - pub const hebrew_finalzadi = 0x0cf5; - pub const hebrew_zade = 0x0cf6; - pub const hebrew_zadi = 0x0cf6; - pub const hebrew_qoph = 0x0cf7; - pub const hebrew_kuf = 0x0cf7; - pub const hebrew_resh = 0x0cf8; - pub const hebrew_shin = 0x0cf9; - pub const hebrew_taw = 0x0cfa; - pub const hebrew_taf = 0x0cfa; - pub const Hebrew_switch = 0xff7e; - pub const Thai_kokai = 0x0da1; - pub const Thai_khokhai = 0x0da2; - pub const Thai_khokhuat = 0x0da3; - pub const Thai_khokhwai = 0x0da4; - pub const Thai_khokhon = 0x0da5; - pub const Thai_khorakhang = 0x0da6; - pub const Thai_ngongu = 0x0da7; - pub const Thai_chochan = 0x0da8; - pub const Thai_choching = 0x0da9; - pub const Thai_chochang = 0x0daa; - pub const Thai_soso = 0x0dab; - pub const Thai_chochoe = 0x0dac; - pub const Thai_yoying = 0x0dad; - pub const Thai_dochada = 0x0dae; - pub const Thai_topatak = 0x0daf; - pub const Thai_thothan = 0x0db0; - pub const Thai_thonangmontho = 0x0db1; - pub const Thai_thophuthao = 0x0db2; - pub const Thai_nonen = 0x0db3; - pub const Thai_dodek = 0x0db4; - pub const Thai_totao = 0x0db5; - pub const Thai_thothung = 0x0db6; - pub const Thai_thothahan = 0x0db7; - pub const Thai_thothong = 0x0db8; - pub const Thai_nonu = 0x0db9; - pub const Thai_bobaimai = 0x0dba; - pub const Thai_popla = 0x0dbb; - pub const Thai_phophung = 0x0dbc; - pub const Thai_fofa = 0x0dbd; - pub const Thai_phophan = 0x0dbe; - pub const Thai_fofan = 0x0dbf; - pub const Thai_phosamphao = 0x0dc0; - pub const Thai_moma = 0x0dc1; - pub const Thai_yoyak = 0x0dc2; - pub const Thai_rorua = 0x0dc3; - pub const Thai_ru = 0x0dc4; - pub const Thai_loling = 0x0dc5; - pub const Thai_lu = 0x0dc6; - pub const Thai_wowaen = 0x0dc7; - pub const Thai_sosala = 0x0dc8; - pub const Thai_sorusi = 0x0dc9; - pub const Thai_sosua = 0x0dca; - pub const Thai_hohip = 0x0dcb; - pub const Thai_lochula = 0x0dcc; - pub const Thai_oang = 0x0dcd; - pub const Thai_honokhuk = 0x0dce; - pub const Thai_paiyannoi = 0x0dcf; - pub const Thai_saraa = 0x0dd0; - pub const Thai_maihanakat = 0x0dd1; - pub const Thai_saraaa = 0x0dd2; - pub const Thai_saraam = 0x0dd3; - pub const Thai_sarai = 0x0dd4; - pub const Thai_saraii = 0x0dd5; - pub const Thai_saraue = 0x0dd6; - pub const Thai_sarauee = 0x0dd7; - pub const Thai_sarau = 0x0dd8; - pub const Thai_sarauu = 0x0dd9; - pub const Thai_phinthu = 0x0dda; - pub const Thai_maihanakat_maitho = 0x0dde; - pub const Thai_baht = 0x0ddf; - pub const Thai_sarae = 0x0de0; - pub const Thai_saraae = 0x0de1; - pub const Thai_sarao = 0x0de2; - pub const Thai_saraaimaimuan = 0x0de3; - pub const Thai_saraaimaimalai = 0x0de4; - pub const Thai_lakkhangyao = 0x0de5; - pub const Thai_maiyamok = 0x0de6; - pub const Thai_maitaikhu = 0x0de7; - pub const Thai_maiek = 0x0de8; - pub const Thai_maitho = 0x0de9; - pub const Thai_maitri = 0x0dea; - pub const Thai_maichattawa = 0x0deb; - pub const Thai_thanthakhat = 0x0dec; - pub const Thai_nikhahit = 0x0ded; - pub const Thai_leksun = 0x0df0; - pub const Thai_leknung = 0x0df1; - pub const Thai_leksong = 0x0df2; - pub const Thai_leksam = 0x0df3; - pub const Thai_leksi = 0x0df4; - pub const Thai_lekha = 0x0df5; - pub const Thai_lekhok = 0x0df6; - pub const Thai_lekchet = 0x0df7; - pub const Thai_lekpaet = 0x0df8; - pub const Thai_lekkao = 0x0df9; - pub const Hangul = 0xff31; - pub const Hangul_Start = 0xff32; - pub const Hangul_End = 0xff33; - pub const Hangul_Hanja = 0xff34; - pub const Hangul_Jamo = 0xff35; - pub const Hangul_Romaja = 0xff36; - pub const Hangul_Codeinput = 0xff37; - pub const Hangul_Jeonja = 0xff38; - pub const Hangul_Banja = 0xff39; - pub const Hangul_PreHanja = 0xff3a; - pub const Hangul_PostHanja = 0xff3b; - pub const Hangul_SingleCandidate = 0xff3c; - pub const Hangul_MultipleCandidate = 0xff3d; - pub const Hangul_PreviousCandidate = 0xff3e; - pub const Hangul_Special = 0xff3f; - pub const Hangul_switch = 0xff7e; - pub const Hangul_Kiyeog = 0x0ea1; - pub const Hangul_SsangKiyeog = 0x0ea2; - pub const Hangul_KiyeogSios = 0x0ea3; - pub const Hangul_Nieun = 0x0ea4; - pub const Hangul_NieunJieuj = 0x0ea5; - pub const Hangul_NieunHieuh = 0x0ea6; - pub const Hangul_Dikeud = 0x0ea7; - pub const Hangul_SsangDikeud = 0x0ea8; - pub const Hangul_Rieul = 0x0ea9; - pub const Hangul_RieulKiyeog = 0x0eaa; - pub const Hangul_RieulMieum = 0x0eab; - pub const Hangul_RieulPieub = 0x0eac; - pub const Hangul_RieulSios = 0x0ead; - pub const Hangul_RieulTieut = 0x0eae; - pub const Hangul_RieulPhieuf = 0x0eaf; - pub const Hangul_RieulHieuh = 0x0eb0; - pub const Hangul_Mieum = 0x0eb1; - pub const Hangul_Pieub = 0x0eb2; - pub const Hangul_SsangPieub = 0x0eb3; - pub const Hangul_PieubSios = 0x0eb4; - pub const Hangul_Sios = 0x0eb5; - pub const Hangul_SsangSios = 0x0eb6; - pub const Hangul_Ieung = 0x0eb7; - pub const Hangul_Jieuj = 0x0eb8; - pub const Hangul_SsangJieuj = 0x0eb9; - pub const Hangul_Cieuc = 0x0eba; - pub const Hangul_Khieuq = 0x0ebb; - pub const Hangul_Tieut = 0x0ebc; - pub const Hangul_Phieuf = 0x0ebd; - pub const Hangul_Hieuh = 0x0ebe; - pub const Hangul_A = 0x0ebf; - pub const Hangul_AE = 0x0ec0; - pub const Hangul_YA = 0x0ec1; - pub const Hangul_YAE = 0x0ec2; - pub const Hangul_EO = 0x0ec3; - pub const Hangul_E = 0x0ec4; - pub const Hangul_YEO = 0x0ec5; - pub const Hangul_YE = 0x0ec6; - pub const Hangul_O = 0x0ec7; - pub const Hangul_WA = 0x0ec8; - pub const Hangul_WAE = 0x0ec9; - pub const Hangul_OE = 0x0eca; - pub const Hangul_YO = 0x0ecb; - pub const Hangul_U = 0x0ecc; - pub const Hangul_WEO = 0x0ecd; - pub const Hangul_WE = 0x0ece; - pub const Hangul_WI = 0x0ecf; - pub const Hangul_YU = 0x0ed0; - pub const Hangul_EU = 0x0ed1; - pub const Hangul_YI = 0x0ed2; - pub const Hangul_I = 0x0ed3; - pub const Hangul_J_Kiyeog = 0x0ed4; - pub const Hangul_J_SsangKiyeog = 0x0ed5; - pub const Hangul_J_KiyeogSios = 0x0ed6; - pub const Hangul_J_Nieun = 0x0ed7; - pub const Hangul_J_NieunJieuj = 0x0ed8; - pub const Hangul_J_NieunHieuh = 0x0ed9; - pub const Hangul_J_Dikeud = 0x0eda; - pub const Hangul_J_Rieul = 0x0edb; - pub const Hangul_J_RieulKiyeog = 0x0edc; - pub const Hangul_J_RieulMieum = 0x0edd; - pub const Hangul_J_RieulPieub = 0x0ede; - pub const Hangul_J_RieulSios = 0x0edf; - pub const Hangul_J_RieulTieut = 0x0ee0; - pub const Hangul_J_RieulPhieuf = 0x0ee1; - pub const Hangul_J_RieulHieuh = 0x0ee2; - pub const Hangul_J_Mieum = 0x0ee3; - pub const Hangul_J_Pieub = 0x0ee4; - pub const Hangul_J_PieubSios = 0x0ee5; - pub const Hangul_J_Sios = 0x0ee6; - pub const Hangul_J_SsangSios = 0x0ee7; - pub const Hangul_J_Ieung = 0x0ee8; - pub const Hangul_J_Jieuj = 0x0ee9; - pub const Hangul_J_Cieuc = 0x0eea; - pub const Hangul_J_Khieuq = 0x0eeb; - pub const Hangul_J_Tieut = 0x0eec; - pub const Hangul_J_Phieuf = 0x0eed; - pub const Hangul_J_Hieuh = 0x0eee; - pub const Hangul_RieulYeorinHieuh = 0x0eef; - pub const Hangul_SunkyeongeumMieum = 0x0ef0; - pub const Hangul_SunkyeongeumPieub = 0x0ef1; - pub const Hangul_PanSios = 0x0ef2; - pub const Hangul_KkogjiDalrinIeung = 0x0ef3; - pub const Hangul_SunkyeongeumPhieuf = 0x0ef4; - pub const Hangul_YeorinHieuh = 0x0ef5; - pub const Hangul_AraeA = 0x0ef6; - pub const Hangul_AraeAE = 0x0ef7; - pub const Hangul_J_PanSios = 0x0ef8; - pub const Hangul_J_KkogjiDalrinIeung = 0x0ef9; - pub const Hangul_J_YeorinHieuh = 0x0efa; - pub const Korean_Won = 0x0eff; - pub const Armenian_ligature_ew = 0x1000587; - pub const Armenian_full_stop = 0x1000589; - pub const Armenian_verjaket = 0x1000589; - pub const Armenian_separation_mark = 0x100055d; - pub const Armenian_but = 0x100055d; - pub const Armenian_hyphen = 0x100058a; - pub const Armenian_yentamna = 0x100058a; - pub const Armenian_exclam = 0x100055c; - pub const Armenian_amanak = 0x100055c; - pub const Armenian_accent = 0x100055b; - pub const Armenian_shesht = 0x100055b; - pub const Armenian_question = 0x100055e; - pub const Armenian_paruyk = 0x100055e; - pub const Armenian_AYB = 0x1000531; - pub const Armenian_ayb = 0x1000561; - pub const Armenian_BEN = 0x1000532; - pub const Armenian_ben = 0x1000562; - pub const Armenian_GIM = 0x1000533; - pub const Armenian_gim = 0x1000563; - pub const Armenian_DA = 0x1000534; - pub const Armenian_da = 0x1000564; - pub const Armenian_YECH = 0x1000535; - pub const Armenian_yech = 0x1000565; - pub const Armenian_ZA = 0x1000536; - pub const Armenian_za = 0x1000566; - pub const Armenian_E = 0x1000537; - pub const Armenian_e = 0x1000567; - pub const Armenian_AT = 0x1000538; - pub const Armenian_at = 0x1000568; - pub const Armenian_TO = 0x1000539; - pub const Armenian_to = 0x1000569; - pub const Armenian_ZHE = 0x100053a; - pub const Armenian_zhe = 0x100056a; - pub const Armenian_INI = 0x100053b; - pub const Armenian_ini = 0x100056b; - pub const Armenian_LYUN = 0x100053c; - pub const Armenian_lyun = 0x100056c; - pub const Armenian_KHE = 0x100053d; - pub const Armenian_khe = 0x100056d; - pub const Armenian_TSA = 0x100053e; - pub const Armenian_tsa = 0x100056e; - pub const Armenian_KEN = 0x100053f; - pub const Armenian_ken = 0x100056f; - pub const Armenian_HO = 0x1000540; - pub const Armenian_ho = 0x1000570; - pub const Armenian_DZA = 0x1000541; - pub const Armenian_dza = 0x1000571; - pub const Armenian_GHAT = 0x1000542; - pub const Armenian_ghat = 0x1000572; - pub const Armenian_TCHE = 0x1000543; - pub const Armenian_tche = 0x1000573; - pub const Armenian_MEN = 0x1000544; - pub const Armenian_men = 0x1000574; - pub const Armenian_HI = 0x1000545; - pub const Armenian_hi = 0x1000575; - pub const Armenian_NU = 0x1000546; - pub const Armenian_nu = 0x1000576; - pub const Armenian_SHA = 0x1000547; - pub const Armenian_sha = 0x1000577; - pub const Armenian_VO = 0x1000548; - pub const Armenian_vo = 0x1000578; - pub const Armenian_CHA = 0x1000549; - pub const Armenian_cha = 0x1000579; - pub const Armenian_PE = 0x100054a; - pub const Armenian_pe = 0x100057a; - pub const Armenian_JE = 0x100054b; - pub const Armenian_je = 0x100057b; - pub const Armenian_RA = 0x100054c; - pub const Armenian_ra = 0x100057c; - pub const Armenian_SE = 0x100054d; - pub const Armenian_se = 0x100057d; - pub const Armenian_VEV = 0x100054e; - pub const Armenian_vev = 0x100057e; - pub const Armenian_TYUN = 0x100054f; - pub const Armenian_tyun = 0x100057f; - pub const Armenian_RE = 0x1000550; - pub const Armenian_re = 0x1000580; - pub const Armenian_TSO = 0x1000551; - pub const Armenian_tso = 0x1000581; - pub const Armenian_VYUN = 0x1000552; - pub const Armenian_vyun = 0x1000582; - pub const Armenian_PYUR = 0x1000553; - pub const Armenian_pyur = 0x1000583; - pub const Armenian_KE = 0x1000554; - pub const Armenian_ke = 0x1000584; - pub const Armenian_O = 0x1000555; - pub const Armenian_o = 0x1000585; - pub const Armenian_FE = 0x1000556; - pub const Armenian_fe = 0x1000586; - pub const Armenian_apostrophe = 0x100055a; - pub const Georgian_an = 0x10010d0; - pub const Georgian_ban = 0x10010d1; - pub const Georgian_gan = 0x10010d2; - pub const Georgian_don = 0x10010d3; - pub const Georgian_en = 0x10010d4; - pub const Georgian_vin = 0x10010d5; - pub const Georgian_zen = 0x10010d6; - pub const Georgian_tan = 0x10010d7; - pub const Georgian_in = 0x10010d8; - pub const Georgian_kan = 0x10010d9; - pub const Georgian_las = 0x10010da; - pub const Georgian_man = 0x10010db; - pub const Georgian_nar = 0x10010dc; - pub const Georgian_on = 0x10010dd; - pub const Georgian_par = 0x10010de; - pub const Georgian_zhar = 0x10010df; - pub const Georgian_rae = 0x10010e0; - pub const Georgian_san = 0x10010e1; - pub const Georgian_tar = 0x10010e2; - pub const Georgian_un = 0x10010e3; - pub const Georgian_phar = 0x10010e4; - pub const Georgian_khar = 0x10010e5; - pub const Georgian_ghan = 0x10010e6; - pub const Georgian_qar = 0x10010e7; - pub const Georgian_shin = 0x10010e8; - pub const Georgian_chin = 0x10010e9; - pub const Georgian_can = 0x10010ea; - pub const Georgian_jil = 0x10010eb; - pub const Georgian_cil = 0x10010ec; - pub const Georgian_char = 0x10010ed; - pub const Georgian_xan = 0x10010ee; - pub const Georgian_jhan = 0x10010ef; - pub const Georgian_hae = 0x10010f0; - pub const Georgian_he = 0x10010f1; - pub const Georgian_hie = 0x10010f2; - pub const Georgian_we = 0x10010f3; - pub const Georgian_har = 0x10010f4; - pub const Georgian_hoe = 0x10010f5; - pub const Georgian_fi = 0x10010f6; - pub const Xabovedot = 0x1001e8a; - pub const Ibreve = 0x100012c; - pub const Zstroke = 0x10001b5; - pub const Gcaron = 0x10001e6; - pub const Ocaron = 0x10001d1; - pub const Obarred = 0x100019f; - pub const xabovedot = 0x1001e8b; - pub const ibreve = 0x100012d; - pub const zstroke = 0x10001b6; - pub const gcaron = 0x10001e7; - pub const ocaron = 0x10001d2; - pub const obarred = 0x1000275; - pub const SCHWA = 0x100018f; - pub const schwa = 0x1000259; - pub const EZH = 0x10001b7; - pub const ezh = 0x1000292; - pub const Lbelowdot = 0x1001e36; - pub const lbelowdot = 0x1001e37; - pub const Abelowdot = 0x1001ea0; - pub const abelowdot = 0x1001ea1; - pub const Ahook = 0x1001ea2; - pub const ahook = 0x1001ea3; - pub const Acircumflexacute = 0x1001ea4; - pub const acircumflexacute = 0x1001ea5; - pub const Acircumflexgrave = 0x1001ea6; - pub const acircumflexgrave = 0x1001ea7; - pub const Acircumflexhook = 0x1001ea8; - pub const acircumflexhook = 0x1001ea9; - pub const Acircumflextilde = 0x1001eaa; - pub const acircumflextilde = 0x1001eab; - pub const Acircumflexbelowdot = 0x1001eac; - pub const acircumflexbelowdot = 0x1001ead; - pub const Abreveacute = 0x1001eae; - pub const abreveacute = 0x1001eaf; - pub const Abrevegrave = 0x1001eb0; - pub const abrevegrave = 0x1001eb1; - pub const Abrevehook = 0x1001eb2; - pub const abrevehook = 0x1001eb3; - pub const Abrevetilde = 0x1001eb4; - pub const abrevetilde = 0x1001eb5; - pub const Abrevebelowdot = 0x1001eb6; - pub const abrevebelowdot = 0x1001eb7; - pub const Ebelowdot = 0x1001eb8; - pub const ebelowdot = 0x1001eb9; - pub const Ehook = 0x1001eba; - pub const ehook = 0x1001ebb; - pub const Etilde = 0x1001ebc; - pub const etilde = 0x1001ebd; - pub const Ecircumflexacute = 0x1001ebe; - pub const ecircumflexacute = 0x1001ebf; - pub const Ecircumflexgrave = 0x1001ec0; - pub const ecircumflexgrave = 0x1001ec1; - pub const Ecircumflexhook = 0x1001ec2; - pub const ecircumflexhook = 0x1001ec3; - pub const Ecircumflextilde = 0x1001ec4; - pub const ecircumflextilde = 0x1001ec5; - pub const Ecircumflexbelowdot = 0x1001ec6; - pub const ecircumflexbelowdot = 0x1001ec7; - pub const Ihook = 0x1001ec8; - pub const ihook = 0x1001ec9; - pub const Ibelowdot = 0x1001eca; - pub const ibelowdot = 0x1001ecb; - pub const Obelowdot = 0x1001ecc; - pub const obelowdot = 0x1001ecd; - pub const Ohook = 0x1001ece; - pub const ohook = 0x1001ecf; - pub const Ocircumflexacute = 0x1001ed0; - pub const ocircumflexacute = 0x1001ed1; - pub const Ocircumflexgrave = 0x1001ed2; - pub const ocircumflexgrave = 0x1001ed3; - pub const Ocircumflexhook = 0x1001ed4; - pub const ocircumflexhook = 0x1001ed5; - pub const Ocircumflextilde = 0x1001ed6; - pub const ocircumflextilde = 0x1001ed7; - pub const Ocircumflexbelowdot = 0x1001ed8; - pub const ocircumflexbelowdot = 0x1001ed9; - pub const Ohornacute = 0x1001eda; - pub const ohornacute = 0x1001edb; - pub const Ohorngrave = 0x1001edc; - pub const ohorngrave = 0x1001edd; - pub const Ohornhook = 0x1001ede; - pub const ohornhook = 0x1001edf; - pub const Ohorntilde = 0x1001ee0; - pub const ohorntilde = 0x1001ee1; - pub const Ohornbelowdot = 0x1001ee2; - pub const ohornbelowdot = 0x1001ee3; - pub const Ubelowdot = 0x1001ee4; - pub const ubelowdot = 0x1001ee5; - pub const Uhook = 0x1001ee6; - pub const uhook = 0x1001ee7; - pub const Uhornacute = 0x1001ee8; - pub const uhornacute = 0x1001ee9; - pub const Uhorngrave = 0x1001eea; - pub const uhorngrave = 0x1001eeb; - pub const Uhornhook = 0x1001eec; - pub const uhornhook = 0x1001eed; - pub const Uhorntilde = 0x1001eee; - pub const uhorntilde = 0x1001eef; - pub const Uhornbelowdot = 0x1001ef0; - pub const uhornbelowdot = 0x1001ef1; - pub const Ybelowdot = 0x1001ef4; - pub const ybelowdot = 0x1001ef5; - pub const Yhook = 0x1001ef6; - pub const yhook = 0x1001ef7; - pub const Ytilde = 0x1001ef8; - pub const ytilde = 0x1001ef9; - pub const Ohorn = 0x10001a0; - pub const ohorn = 0x10001a1; - pub const Uhorn = 0x10001af; - pub const uhorn = 0x10001b0; - pub const combining_tilde = 0x1000303; - pub const combining_grave = 0x1000300; - pub const combining_acute = 0x1000301; - pub const combining_hook = 0x1000309; - pub const combining_belowdot = 0x1000323; - pub const EcuSign = 0x10020a0; - pub const ColonSign = 0x10020a1; - pub const CruzeiroSign = 0x10020a2; - pub const FFrancSign = 0x10020a3; - pub const LiraSign = 0x10020a4; - pub const MillSign = 0x10020a5; - pub const NairaSign = 0x10020a6; - pub const PesetaSign = 0x10020a7; - pub const RupeeSign = 0x10020a8; - pub const WonSign = 0x10020a9; - pub const NewSheqelSign = 0x10020aa; - pub const DongSign = 0x10020ab; - pub const EuroSign = 0x20ac; - pub const zerosuperior = 0x1002070; - pub const foursuperior = 0x1002074; - pub const fivesuperior = 0x1002075; - pub const sixsuperior = 0x1002076; - pub const sevensuperior = 0x1002077; - pub const eightsuperior = 0x1002078; - pub const ninesuperior = 0x1002079; - pub const zerosubscript = 0x1002080; - pub const onesubscript = 0x1002081; - pub const twosubscript = 0x1002082; - pub const threesubscript = 0x1002083; - pub const foursubscript = 0x1002084; - pub const fivesubscript = 0x1002085; - pub const sixsubscript = 0x1002086; - pub const sevensubscript = 0x1002087; - pub const eightsubscript = 0x1002088; - pub const ninesubscript = 0x1002089; - pub const partdifferential = 0x1002202; - pub const emptyset = 0x1002205; - pub const elementof = 0x1002208; - pub const notelementof = 0x1002209; - pub const containsas = 0x100220b; - pub const squareroot = 0x100221a; - pub const cuberoot = 0x100221b; - pub const fourthroot = 0x100221c; - pub const dintegral = 0x100222c; - pub const tintegral = 0x100222d; - pub const because = 0x1002235; - pub const approxeq = 0x1002248; - pub const notapproxeq = 0x1002247; - pub const notidentical = 0x1002262; - pub const stricteq = 0x1002263; - pub const braille_dot_1 = 0xfff1; - pub const braille_dot_2 = 0xfff2; - pub const braille_dot_3 = 0xfff3; - pub const braille_dot_4 = 0xfff4; - pub const braille_dot_5 = 0xfff5; - pub const braille_dot_6 = 0xfff6; - pub const braille_dot_7 = 0xfff7; - pub const braille_dot_8 = 0xfff8; - pub const braille_dot_9 = 0xfff9; - pub const braille_dot_10 = 0xfffa; - pub const braille_blank = 0x1002800; - pub const braille_dots_1 = 0x1002801; - pub const braille_dots_2 = 0x1002802; - pub const braille_dots_12 = 0x1002803; - pub const braille_dots_3 = 0x1002804; - pub const braille_dots_13 = 0x1002805; - pub const braille_dots_23 = 0x1002806; - pub const braille_dots_123 = 0x1002807; - pub const braille_dots_4 = 0x1002808; - pub const braille_dots_14 = 0x1002809; - pub const braille_dots_24 = 0x100280a; - pub const braille_dots_124 = 0x100280b; - pub const braille_dots_34 = 0x100280c; - pub const braille_dots_134 = 0x100280d; - pub const braille_dots_234 = 0x100280e; - pub const braille_dots_1234 = 0x100280f; - pub const braille_dots_5 = 0x1002810; - pub const braille_dots_15 = 0x1002811; - pub const braille_dots_25 = 0x1002812; - pub const braille_dots_125 = 0x1002813; - pub const braille_dots_35 = 0x1002814; - pub const braille_dots_135 = 0x1002815; - pub const braille_dots_235 = 0x1002816; - pub const braille_dots_1235 = 0x1002817; - pub const braille_dots_45 = 0x1002818; - pub const braille_dots_145 = 0x1002819; - pub const braille_dots_245 = 0x100281a; - pub const braille_dots_1245 = 0x100281b; - pub const braille_dots_345 = 0x100281c; - pub const braille_dots_1345 = 0x100281d; - pub const braille_dots_2345 = 0x100281e; - pub const braille_dots_12345 = 0x100281f; - pub const braille_dots_6 = 0x1002820; - pub const braille_dots_16 = 0x1002821; - pub const braille_dots_26 = 0x1002822; - pub const braille_dots_126 = 0x1002823; - pub const braille_dots_36 = 0x1002824; - pub const braille_dots_136 = 0x1002825; - pub const braille_dots_236 = 0x1002826; - pub const braille_dots_1236 = 0x1002827; - pub const braille_dots_46 = 0x1002828; - pub const braille_dots_146 = 0x1002829; - pub const braille_dots_246 = 0x100282a; - pub const braille_dots_1246 = 0x100282b; - pub const braille_dots_346 = 0x100282c; - pub const braille_dots_1346 = 0x100282d; - pub const braille_dots_2346 = 0x100282e; - pub const braille_dots_12346 = 0x100282f; - pub const braille_dots_56 = 0x1002830; - pub const braille_dots_156 = 0x1002831; - pub const braille_dots_256 = 0x1002832; - pub const braille_dots_1256 = 0x1002833; - pub const braille_dots_356 = 0x1002834; - pub const braille_dots_1356 = 0x1002835; - pub const braille_dots_2356 = 0x1002836; - pub const braille_dots_12356 = 0x1002837; - pub const braille_dots_456 = 0x1002838; - pub const braille_dots_1456 = 0x1002839; - pub const braille_dots_2456 = 0x100283a; - pub const braille_dots_12456 = 0x100283b; - pub const braille_dots_3456 = 0x100283c; - pub const braille_dots_13456 = 0x100283d; - pub const braille_dots_23456 = 0x100283e; - pub const braille_dots_123456 = 0x100283f; - pub const braille_dots_7 = 0x1002840; - pub const braille_dots_17 = 0x1002841; - pub const braille_dots_27 = 0x1002842; - pub const braille_dots_127 = 0x1002843; - pub const braille_dots_37 = 0x1002844; - pub const braille_dots_137 = 0x1002845; - pub const braille_dots_237 = 0x1002846; - pub const braille_dots_1237 = 0x1002847; - pub const braille_dots_47 = 0x1002848; - pub const braille_dots_147 = 0x1002849; - pub const braille_dots_247 = 0x100284a; - pub const braille_dots_1247 = 0x100284b; - pub const braille_dots_347 = 0x100284c; - pub const braille_dots_1347 = 0x100284d; - pub const braille_dots_2347 = 0x100284e; - pub const braille_dots_12347 = 0x100284f; - pub const braille_dots_57 = 0x1002850; - pub const braille_dots_157 = 0x1002851; - pub const braille_dots_257 = 0x1002852; - pub const braille_dots_1257 = 0x1002853; - pub const braille_dots_357 = 0x1002854; - pub const braille_dots_1357 = 0x1002855; - pub const braille_dots_2357 = 0x1002856; - pub const braille_dots_12357 = 0x1002857; - pub const braille_dots_457 = 0x1002858; - pub const braille_dots_1457 = 0x1002859; - pub const braille_dots_2457 = 0x100285a; - pub const braille_dots_12457 = 0x100285b; - pub const braille_dots_3457 = 0x100285c; - pub const braille_dots_13457 = 0x100285d; - pub const braille_dots_23457 = 0x100285e; - pub const braille_dots_123457 = 0x100285f; - pub const braille_dots_67 = 0x1002860; - pub const braille_dots_167 = 0x1002861; - pub const braille_dots_267 = 0x1002862; - pub const braille_dots_1267 = 0x1002863; - pub const braille_dots_367 = 0x1002864; - pub const braille_dots_1367 = 0x1002865; - pub const braille_dots_2367 = 0x1002866; - pub const braille_dots_12367 = 0x1002867; - pub const braille_dots_467 = 0x1002868; - pub const braille_dots_1467 = 0x1002869; - pub const braille_dots_2467 = 0x100286a; - pub const braille_dots_12467 = 0x100286b; - pub const braille_dots_3467 = 0x100286c; - pub const braille_dots_13467 = 0x100286d; - pub const braille_dots_23467 = 0x100286e; - pub const braille_dots_123467 = 0x100286f; - pub const braille_dots_567 = 0x1002870; - pub const braille_dots_1567 = 0x1002871; - pub const braille_dots_2567 = 0x1002872; - pub const braille_dots_12567 = 0x1002873; - pub const braille_dots_3567 = 0x1002874; - pub const braille_dots_13567 = 0x1002875; - pub const braille_dots_23567 = 0x1002876; - pub const braille_dots_123567 = 0x1002877; - pub const braille_dots_4567 = 0x1002878; - pub const braille_dots_14567 = 0x1002879; - pub const braille_dots_24567 = 0x100287a; - pub const braille_dots_124567 = 0x100287b; - pub const braille_dots_34567 = 0x100287c; - pub const braille_dots_134567 = 0x100287d; - pub const braille_dots_234567 = 0x100287e; - pub const braille_dots_1234567 = 0x100287f; - pub const braille_dots_8 = 0x1002880; - pub const braille_dots_18 = 0x1002881; - pub const braille_dots_28 = 0x1002882; - pub const braille_dots_128 = 0x1002883; - pub const braille_dots_38 = 0x1002884; - pub const braille_dots_138 = 0x1002885; - pub const braille_dots_238 = 0x1002886; - pub const braille_dots_1238 = 0x1002887; - pub const braille_dots_48 = 0x1002888; - pub const braille_dots_148 = 0x1002889; - pub const braille_dots_248 = 0x100288a; - pub const braille_dots_1248 = 0x100288b; - pub const braille_dots_348 = 0x100288c; - pub const braille_dots_1348 = 0x100288d; - pub const braille_dots_2348 = 0x100288e; - pub const braille_dots_12348 = 0x100288f; - pub const braille_dots_58 = 0x1002890; - pub const braille_dots_158 = 0x1002891; - pub const braille_dots_258 = 0x1002892; - pub const braille_dots_1258 = 0x1002893; - pub const braille_dots_358 = 0x1002894; - pub const braille_dots_1358 = 0x1002895; - pub const braille_dots_2358 = 0x1002896; - pub const braille_dots_12358 = 0x1002897; - pub const braille_dots_458 = 0x1002898; - pub const braille_dots_1458 = 0x1002899; - pub const braille_dots_2458 = 0x100289a; - pub const braille_dots_12458 = 0x100289b; - pub const braille_dots_3458 = 0x100289c; - pub const braille_dots_13458 = 0x100289d; - pub const braille_dots_23458 = 0x100289e; - pub const braille_dots_123458 = 0x100289f; - pub const braille_dots_68 = 0x10028a0; - pub const braille_dots_168 = 0x10028a1; - pub const braille_dots_268 = 0x10028a2; - pub const braille_dots_1268 = 0x10028a3; - pub const braille_dots_368 = 0x10028a4; - pub const braille_dots_1368 = 0x10028a5; - pub const braille_dots_2368 = 0x10028a6; - pub const braille_dots_12368 = 0x10028a7; - pub const braille_dots_468 = 0x10028a8; - pub const braille_dots_1468 = 0x10028a9; - pub const braille_dots_2468 = 0x10028aa; - pub const braille_dots_12468 = 0x10028ab; - pub const braille_dots_3468 = 0x10028ac; - pub const braille_dots_13468 = 0x10028ad; - pub const braille_dots_23468 = 0x10028ae; - pub const braille_dots_123468 = 0x10028af; - pub const braille_dots_568 = 0x10028b0; - pub const braille_dots_1568 = 0x10028b1; - pub const braille_dots_2568 = 0x10028b2; - pub const braille_dots_12568 = 0x10028b3; - pub const braille_dots_3568 = 0x10028b4; - pub const braille_dots_13568 = 0x10028b5; - pub const braille_dots_23568 = 0x10028b6; - pub const braille_dots_123568 = 0x10028b7; - pub const braille_dots_4568 = 0x10028b8; - pub const braille_dots_14568 = 0x10028b9; - pub const braille_dots_24568 = 0x10028ba; - pub const braille_dots_124568 = 0x10028bb; - pub const braille_dots_34568 = 0x10028bc; - pub const braille_dots_134568 = 0x10028bd; - pub const braille_dots_234568 = 0x10028be; - pub const braille_dots_1234568 = 0x10028bf; - pub const braille_dots_78 = 0x10028c0; - pub const braille_dots_178 = 0x10028c1; - pub const braille_dots_278 = 0x10028c2; - pub const braille_dots_1278 = 0x10028c3; - pub const braille_dots_378 = 0x10028c4; - pub const braille_dots_1378 = 0x10028c5; - pub const braille_dots_2378 = 0x10028c6; - pub const braille_dots_12378 = 0x10028c7; - pub const braille_dots_478 = 0x10028c8; - pub const braille_dots_1478 = 0x10028c9; - pub const braille_dots_2478 = 0x10028ca; - pub const braille_dots_12478 = 0x10028cb; - pub const braille_dots_3478 = 0x10028cc; - pub const braille_dots_13478 = 0x10028cd; - pub const braille_dots_23478 = 0x10028ce; - pub const braille_dots_123478 = 0x10028cf; - pub const braille_dots_578 = 0x10028d0; - pub const braille_dots_1578 = 0x10028d1; - pub const braille_dots_2578 = 0x10028d2; - pub const braille_dots_12578 = 0x10028d3; - pub const braille_dots_3578 = 0x10028d4; - pub const braille_dots_13578 = 0x10028d5; - pub const braille_dots_23578 = 0x10028d6; - pub const braille_dots_123578 = 0x10028d7; - pub const braille_dots_4578 = 0x10028d8; - pub const braille_dots_14578 = 0x10028d9; - pub const braille_dots_24578 = 0x10028da; - pub const braille_dots_124578 = 0x10028db; - pub const braille_dots_34578 = 0x10028dc; - pub const braille_dots_134578 = 0x10028dd; - pub const braille_dots_234578 = 0x10028de; - pub const braille_dots_1234578 = 0x10028df; - pub const braille_dots_678 = 0x10028e0; - pub const braille_dots_1678 = 0x10028e1; - pub const braille_dots_2678 = 0x10028e2; - pub const braille_dots_12678 = 0x10028e3; - pub const braille_dots_3678 = 0x10028e4; - pub const braille_dots_13678 = 0x10028e5; - pub const braille_dots_23678 = 0x10028e6; - pub const braille_dots_123678 = 0x10028e7; - pub const braille_dots_4678 = 0x10028e8; - pub const braille_dots_14678 = 0x10028e9; - pub const braille_dots_24678 = 0x10028ea; - pub const braille_dots_124678 = 0x10028eb; - pub const braille_dots_34678 = 0x10028ec; - pub const braille_dots_134678 = 0x10028ed; - pub const braille_dots_234678 = 0x10028ee; - pub const braille_dots_1234678 = 0x10028ef; - pub const braille_dots_5678 = 0x10028f0; - pub const braille_dots_15678 = 0x10028f1; - pub const braille_dots_25678 = 0x10028f2; - pub const braille_dots_125678 = 0x10028f3; - pub const braille_dots_35678 = 0x10028f4; - pub const braille_dots_135678 = 0x10028f5; - pub const braille_dots_235678 = 0x10028f6; - pub const braille_dots_1235678 = 0x10028f7; - pub const braille_dots_45678 = 0x10028f8; - pub const braille_dots_145678 = 0x10028f9; - pub const braille_dots_245678 = 0x10028fa; - pub const braille_dots_1245678 = 0x10028fb; - pub const braille_dots_345678 = 0x10028fc; - pub const braille_dots_1345678 = 0x10028fd; - pub const braille_dots_2345678 = 0x10028fe; - pub const braille_dots_12345678 = 0x10028ff; - pub const Sinh_ng = 0x1000d82; - pub const Sinh_h2 = 0x1000d83; - pub const Sinh_a = 0x1000d85; - pub const Sinh_aa = 0x1000d86; - pub const Sinh_ae = 0x1000d87; - pub const Sinh_aee = 0x1000d88; - pub const Sinh_i = 0x1000d89; - pub const Sinh_ii = 0x1000d8a; - pub const Sinh_u = 0x1000d8b; - pub const Sinh_uu = 0x1000d8c; - pub const Sinh_ri = 0x1000d8d; - pub const Sinh_rii = 0x1000d8e; - pub const Sinh_lu = 0x1000d8f; - pub const Sinh_luu = 0x1000d90; - pub const Sinh_e = 0x1000d91; - pub const Sinh_ee = 0x1000d92; - pub const Sinh_ai = 0x1000d93; - pub const Sinh_o = 0x1000d94; - pub const Sinh_oo = 0x1000d95; - pub const Sinh_au = 0x1000d96; - pub const Sinh_ka = 0x1000d9a; - pub const Sinh_kha = 0x1000d9b; - pub const Sinh_ga = 0x1000d9c; - pub const Sinh_gha = 0x1000d9d; - pub const Sinh_ng2 = 0x1000d9e; - pub const Sinh_nga = 0x1000d9f; - pub const Sinh_ca = 0x1000da0; - pub const Sinh_cha = 0x1000da1; - pub const Sinh_ja = 0x1000da2; - pub const Sinh_jha = 0x1000da3; - pub const Sinh_nya = 0x1000da4; - pub const Sinh_jnya = 0x1000da5; - pub const Sinh_nja = 0x1000da6; - pub const Sinh_tta = 0x1000da7; - pub const Sinh_ttha = 0x1000da8; - pub const Sinh_dda = 0x1000da9; - pub const Sinh_ddha = 0x1000daa; - pub const Sinh_nna = 0x1000dab; - pub const Sinh_ndda = 0x1000dac; - pub const Sinh_tha = 0x1000dad; - pub const Sinh_thha = 0x1000dae; - pub const Sinh_dha = 0x1000daf; - pub const Sinh_dhha = 0x1000db0; - pub const Sinh_na = 0x1000db1; - pub const Sinh_ndha = 0x1000db3; - pub const Sinh_pa = 0x1000db4; - pub const Sinh_pha = 0x1000db5; - pub const Sinh_ba = 0x1000db6; - pub const Sinh_bha = 0x1000db7; - pub const Sinh_ma = 0x1000db8; - pub const Sinh_mba = 0x1000db9; - pub const Sinh_ya = 0x1000dba; - pub const Sinh_ra = 0x1000dbb; - pub const Sinh_la = 0x1000dbd; - pub const Sinh_va = 0x1000dc0; - pub const Sinh_sha = 0x1000dc1; - pub const Sinh_ssha = 0x1000dc2; - pub const Sinh_sa = 0x1000dc3; - pub const Sinh_ha = 0x1000dc4; - pub const Sinh_lla = 0x1000dc5; - pub const Sinh_fa = 0x1000dc6; - pub const Sinh_al = 0x1000dca; - pub const Sinh_aa2 = 0x1000dcf; - pub const Sinh_ae2 = 0x1000dd0; - pub const Sinh_aee2 = 0x1000dd1; - pub const Sinh_i2 = 0x1000dd2; - pub const Sinh_ii2 = 0x1000dd3; - pub const Sinh_u2 = 0x1000dd4; - pub const Sinh_uu2 = 0x1000dd6; - pub const Sinh_ru2 = 0x1000dd8; - pub const Sinh_e2 = 0x1000dd9; - pub const Sinh_ee2 = 0x1000dda; - pub const Sinh_ai2 = 0x1000ddb; - pub const Sinh_o2 = 0x1000ddc; - pub const Sinh_oo2 = 0x1000ddd; - pub const Sinh_au2 = 0x1000dde; - pub const Sinh_lu2 = 0x1000ddf; - pub const Sinh_ruu2 = 0x1000df2; - pub const Sinh_luu2 = 0x1000df3; - pub const Sinh_kunddaliya = 0x1000df4; - pub const XF86ModeLock = 0x1008ff01; - pub const XF86MonBrightnessUp = 0x1008ff02; - pub const XF86MonBrightnessDown = 0x1008ff03; - pub const XF86KbdLightOnOff = 0x1008ff04; - pub const XF86KbdBrightnessUp = 0x1008ff05; - pub const XF86KbdBrightnessDown = 0x1008ff06; - pub const XF86MonBrightnessCycle = 0x1008ff07; - pub const XF86Standby = 0x1008ff10; - pub const XF86AudioLowerVolume = 0x1008ff11; - pub const XF86AudioMute = 0x1008ff12; - pub const XF86AudioRaiseVolume = 0x1008ff13; - pub const XF86AudioPlay = 0x1008ff14; - pub const XF86AudioStop = 0x1008ff15; - pub const XF86AudioPrev = 0x1008ff16; - pub const XF86AudioNext = 0x1008ff17; - pub const XF86HomePage = 0x1008ff18; - pub const XF86Mail = 0x1008ff19; - pub const XF86Start = 0x1008ff1a; - pub const XF86Search = 0x1008ff1b; - pub const XF86AudioRecord = 0x1008ff1c; - pub const XF86Calculator = 0x1008ff1d; - pub const XF86Memo = 0x1008ff1e; - pub const XF86ToDoList = 0x1008ff1f; - pub const XF86Calendar = 0x1008ff20; - pub const XF86PowerDown = 0x1008ff21; - pub const XF86ContrastAdjust = 0x1008ff22; - pub const XF86RockerUp = 0x1008ff23; - pub const XF86RockerDown = 0x1008ff24; - pub const XF86RockerEnter = 0x1008ff25; - pub const XF86Back = 0x1008ff26; - pub const XF86Forward = 0x1008ff27; - pub const XF86Stop = 0x1008ff28; - pub const XF86Refresh = 0x1008ff29; - pub const XF86PowerOff = 0x1008ff2a; - pub const XF86WakeUp = 0x1008ff2b; - pub const XF86Eject = 0x1008ff2c; - pub const XF86ScreenSaver = 0x1008ff2d; - pub const XF86WWW = 0x1008ff2e; - pub const XF86Sleep = 0x1008ff2f; - pub const XF86Favorites = 0x1008ff30; - pub const XF86AudioPause = 0x1008ff31; - pub const XF86AudioMedia = 0x1008ff32; - pub const XF86MyComputer = 0x1008ff33; - pub const XF86VendorHome = 0x1008ff34; - pub const XF86LightBulb = 0x1008ff35; - pub const XF86Shop = 0x1008ff36; - pub const XF86History = 0x1008ff37; - pub const XF86OpenURL = 0x1008ff38; - pub const XF86AddFavorite = 0x1008ff39; - pub const XF86HotLinks = 0x1008ff3a; - pub const XF86BrightnessAdjust = 0x1008ff3b; - pub const XF86Finance = 0x1008ff3c; - pub const XF86Community = 0x1008ff3d; - pub const XF86AudioRewind = 0x1008ff3e; - pub const XF86BackForward = 0x1008ff3f; - pub const XF86Launch0 = 0x1008ff40; - pub const XF86Launch1 = 0x1008ff41; - pub const XF86Launch2 = 0x1008ff42; - pub const XF86Launch3 = 0x1008ff43; - pub const XF86Launch4 = 0x1008ff44; - pub const XF86Launch5 = 0x1008ff45; - pub const XF86Launch6 = 0x1008ff46; - pub const XF86Launch7 = 0x1008ff47; - pub const XF86Launch8 = 0x1008ff48; - pub const XF86Launch9 = 0x1008ff49; - pub const XF86LaunchA = 0x1008ff4a; - pub const XF86LaunchB = 0x1008ff4b; - pub const XF86LaunchC = 0x1008ff4c; - pub const XF86LaunchD = 0x1008ff4d; - pub const XF86LaunchE = 0x1008ff4e; - pub const XF86LaunchF = 0x1008ff4f; - pub const XF86ApplicationLeft = 0x1008ff50; - pub const XF86ApplicationRight = 0x1008ff51; - pub const XF86Book = 0x1008ff52; - pub const XF86CD = 0x1008ff53; - pub const XF86Calculater = 0x1008ff54; - pub const XF86Clear = 0x1008ff55; - pub const XF86Close = 0x1008ff56; - pub const XF86Copy = 0x1008ff57; - pub const XF86Cut = 0x1008ff58; - pub const XF86Display = 0x1008ff59; - pub const XF86DOS = 0x1008ff5a; - pub const XF86Documents = 0x1008ff5b; - pub const XF86Excel = 0x1008ff5c; - pub const XF86Explorer = 0x1008ff5d; - pub const XF86Game = 0x1008ff5e; - pub const XF86Go = 0x1008ff5f; - pub const XF86iTouch = 0x1008ff60; - pub const XF86LogOff = 0x1008ff61; - pub const XF86Market = 0x1008ff62; - pub const XF86Meeting = 0x1008ff63; - pub const XF86MenuKB = 0x1008ff65; - pub const XF86MenuPB = 0x1008ff66; - pub const XF86MySites = 0x1008ff67; - pub const XF86New = 0x1008ff68; - pub const XF86News = 0x1008ff69; - pub const XF86OfficeHome = 0x1008ff6a; - pub const XF86Open = 0x1008ff6b; - pub const XF86Option = 0x1008ff6c; - pub const XF86Paste = 0x1008ff6d; - pub const XF86Phone = 0x1008ff6e; - pub const XF86Q = 0x1008ff70; - pub const XF86Reply = 0x1008ff72; - pub const XF86Reload = 0x1008ff73; - pub const XF86RotateWindows = 0x1008ff74; - pub const XF86RotationPB = 0x1008ff75; - pub const XF86RotationKB = 0x1008ff76; - pub const XF86Save = 0x1008ff77; - pub const XF86ScrollUp = 0x1008ff78; - pub const XF86ScrollDown = 0x1008ff79; - pub const XF86ScrollClick = 0x1008ff7a; - pub const XF86Send = 0x1008ff7b; - pub const XF86Spell = 0x1008ff7c; - pub const XF86SplitScreen = 0x1008ff7d; - pub const XF86Support = 0x1008ff7e; - pub const XF86TaskPane = 0x1008ff7f; - pub const XF86Terminal = 0x1008ff80; - pub const XF86Tools = 0x1008ff81; - pub const XF86Travel = 0x1008ff82; - pub const XF86UserPB = 0x1008ff84; - pub const XF86User1KB = 0x1008ff85; - pub const XF86User2KB = 0x1008ff86; - pub const XF86Video = 0x1008ff87; - pub const XF86WheelButton = 0x1008ff88; - pub const XF86Word = 0x1008ff89; - pub const XF86Xfer = 0x1008ff8a; - pub const XF86ZoomIn = 0x1008ff8b; - pub const XF86ZoomOut = 0x1008ff8c; - pub const XF86Away = 0x1008ff8d; - pub const XF86Messenger = 0x1008ff8e; - pub const XF86WebCam = 0x1008ff8f; - pub const XF86MailForward = 0x1008ff90; - pub const XF86Pictures = 0x1008ff91; - pub const XF86Music = 0x1008ff92; - pub const XF86Battery = 0x1008ff93; - pub const XF86Bluetooth = 0x1008ff94; - pub const XF86WLAN = 0x1008ff95; - pub const XF86UWB = 0x1008ff96; - pub const XF86AudioForward = 0x1008ff97; - pub const XF86AudioRepeat = 0x1008ff98; - pub const XF86AudioRandomPlay = 0x1008ff99; - pub const XF86Subtitle = 0x1008ff9a; - pub const XF86AudioCycleTrack = 0x1008ff9b; - pub const XF86CycleAngle = 0x1008ff9c; - pub const XF86FrameBack = 0x1008ff9d; - pub const XF86FrameForward = 0x1008ff9e; - pub const XF86Time = 0x1008ff9f; - pub const XF86Select = 0x1008ffa0; - pub const XF86View = 0x1008ffa1; - pub const XF86TopMenu = 0x1008ffa2; - pub const XF86Red = 0x1008ffa3; - pub const XF86Green = 0x1008ffa4; - pub const XF86Yellow = 0x1008ffa5; - pub const XF86Blue = 0x1008ffa6; - pub const XF86Suspend = 0x1008ffa7; - pub const XF86Hibernate = 0x1008ffa8; - pub const XF86TouchpadToggle = 0x1008ffa9; - pub const XF86TouchpadOn = 0x1008ffb0; - pub const XF86TouchpadOff = 0x1008ffb1; - pub const XF86AudioMicMute = 0x1008ffb2; - pub const XF86Keyboard = 0x1008ffb3; - pub const XF86WWAN = 0x1008ffb4; - pub const XF86RFKill = 0x1008ffb5; - pub const XF86AudioPreset = 0x1008ffb6; - pub const XF86RotationLockToggle = 0x1008ffb7; - pub const XF86FullScreen = 0x1008ffb8; - pub const XF86Switch_VT_1 = 0x1008fe01; - pub const XF86Switch_VT_2 = 0x1008fe02; - pub const XF86Switch_VT_3 = 0x1008fe03; - pub const XF86Switch_VT_4 = 0x1008fe04; - pub const XF86Switch_VT_5 = 0x1008fe05; - pub const XF86Switch_VT_6 = 0x1008fe06; - pub const XF86Switch_VT_7 = 0x1008fe07; - pub const XF86Switch_VT_8 = 0x1008fe08; - pub const XF86Switch_VT_9 = 0x1008fe09; - pub const XF86Switch_VT_10 = 0x1008fe0a; - pub const XF86Switch_VT_11 = 0x1008fe0b; - pub const XF86Switch_VT_12 = 0x1008fe0c; - pub const XF86Ungrab = 0x1008fe20; - pub const XF86ClearGrab = 0x1008fe21; - pub const XF86Next_VMode = 0x1008fe22; - pub const XF86Prev_VMode = 0x1008fe23; - pub const XF86LogWindowTree = 0x1008fe24; - pub const XF86LogGrabInfo = 0x1008fe25; - pub const XF86BrightnessAuto = 0x100810f4; - pub const XF86DisplayOff = 0x100810f5; - pub const XF86Info = 0x10081166; - pub const XF86AspectRatio = 0x10081177; - pub const XF86DVD = 0x10081185; - pub const XF86Audio = 0x10081188; - pub const XF86ChannelUp = 0x10081192; - pub const XF86ChannelDown = 0x10081193; - pub const XF86Break = 0x1008119b; - pub const XF86VideoPhone = 0x100811a0; - pub const XF86ZoomReset = 0x100811a4; - pub const XF86Editor = 0x100811a6; - pub const XF86GraphicsEditor = 0x100811a8; - pub const XF86Presentation = 0x100811a9; - pub const XF86Database = 0x100811aa; - pub const XF86Voicemail = 0x100811ac; - pub const XF86Addressbook = 0x100811ad; - pub const XF86DisplayToggle = 0x100811af; - pub const XF86SpellCheck = 0x100811b0; - pub const XF86ContextMenu = 0x100811b6; - pub const XF86MediaRepeat = 0x100811b7; - pub const XF8610ChannelsUp = 0x100811b8; - pub const XF8610ChannelsDown = 0x100811b9; - pub const XF86Images = 0x100811ba; - pub const XF86NotificationCenter = 0x100811bc; - pub const XF86PickupPhone = 0x100811bd; - pub const XF86HangupPhone = 0x100811be; - pub const XF86Fn = 0x100811d0; - pub const XF86Fn_Esc = 0x100811d1; - pub const XF86FnRightShift = 0x100811e5; - pub const XF86Numeric0 = 0x10081200; - pub const XF86Numeric1 = 0x10081201; - pub const XF86Numeric2 = 0x10081202; - pub const XF86Numeric3 = 0x10081203; - pub const XF86Numeric4 = 0x10081204; - pub const XF86Numeric5 = 0x10081205; - pub const XF86Numeric6 = 0x10081206; - pub const XF86Numeric7 = 0x10081207; - pub const XF86Numeric8 = 0x10081208; - pub const XF86Numeric9 = 0x10081209; - pub const XF86NumericStar = 0x1008120a; - pub const XF86NumericPound = 0x1008120b; - pub const XF86NumericA = 0x1008120c; - pub const XF86NumericB = 0x1008120d; - pub const XF86NumericC = 0x1008120e; - pub const XF86NumericD = 0x1008120f; - pub const XF86CameraFocus = 0x10081210; - pub const XF86WPSButton = 0x10081211; - pub const XF86CameraZoomIn = 0x10081215; - pub const XF86CameraZoomOut = 0x10081216; - pub const XF86CameraUp = 0x10081217; - pub const XF86CameraDown = 0x10081218; - pub const XF86CameraLeft = 0x10081219; - pub const XF86CameraRight = 0x1008121a; - pub const XF86AttendantOn = 0x1008121b; - pub const XF86AttendantOff = 0x1008121c; - pub const XF86AttendantToggle = 0x1008121d; - pub const XF86LightsToggle = 0x1008121e; - pub const XF86ALSToggle = 0x10081230; - pub const XF86Buttonconfig = 0x10081240; - pub const XF86Taskmanager = 0x10081241; - pub const XF86Journal = 0x10081242; - pub const XF86ControlPanel = 0x10081243; - pub const XF86AppSelect = 0x10081244; - pub const XF86Screensaver = 0x10081245; - pub const XF86VoiceCommand = 0x10081246; - pub const XF86Assistant = 0x10081247; - pub const XF86EmojiPicker = 0x10081249; - pub const XF86Dictate = 0x1008124a; - pub const XF86CameraAccessEnable = 0x1008124b; - pub const XF86CameraAccessDisable = 0x1008124c; - pub const XF86CameraAccessToggle = 0x1008124d; - pub const XF86BrightnessMin = 0x10081250; - pub const XF86BrightnessMax = 0x10081251; - pub const XF86KbdInputAssistPrev = 0x10081260; - pub const XF86KbdInputAssistNext = 0x10081261; - pub const XF86KbdInputAssistPrevgroup = 0x10081262; - pub const XF86KbdInputAssistNextgroup = 0x10081263; - pub const XF86KbdInputAssistAccept = 0x10081264; - pub const XF86KbdInputAssistCancel = 0x10081265; - pub const XF86RightUp = 0x10081266; - pub const XF86RightDown = 0x10081267; - pub const XF86LeftUp = 0x10081268; - pub const XF86LeftDown = 0x10081269; - pub const XF86RootMenu = 0x1008126a; - pub const XF86MediaTopMenu = 0x1008126b; - pub const XF86Numeric11 = 0x1008126c; - pub const XF86Numeric12 = 0x1008126d; - pub const XF86AudioDesc = 0x1008126e; - pub const XF863DMode = 0x1008126f; - pub const XF86NextFavorite = 0x10081270; - pub const XF86StopRecord = 0x10081271; - pub const XF86PauseRecord = 0x10081272; - pub const XF86VOD = 0x10081273; - pub const XF86Unmute = 0x10081274; - pub const XF86FastReverse = 0x10081275; - pub const XF86SlowReverse = 0x10081276; - pub const XF86Data = 0x10081277; - pub const XF86OnScreenKeyboard = 0x10081278; - pub const XF86PrivacyScreenToggle = 0x10081279; - pub const XF86SelectiveScreenshot = 0x1008127a; - pub const XF86NextElement = 0x1008127b; - pub const XF86PreviousElement = 0x1008127c; - pub const XF86AutopilotEngageToggle = 0x1008127d; - pub const XF86MarkWaypoint = 0x1008127e; - pub const XF86Sos = 0x1008127f; - pub const XF86NavChart = 0x10081280; - pub const XF86FishingChart = 0x10081281; - pub const XF86SingleRangeRadar = 0x10081282; - pub const XF86DualRangeRadar = 0x10081283; - pub const XF86RadarOverlay = 0x10081284; - pub const XF86TraditionalSonar = 0x10081285; - pub const XF86ClearvuSonar = 0x10081286; - pub const XF86SidevuSonar = 0x10081287; - pub const XF86NavInfo = 0x10081288; - pub const XF86Macro1 = 0x10081290; - pub const XF86Macro2 = 0x10081291; - pub const XF86Macro3 = 0x10081292; - pub const XF86Macro4 = 0x10081293; - pub const XF86Macro5 = 0x10081294; - pub const XF86Macro6 = 0x10081295; - pub const XF86Macro7 = 0x10081296; - pub const XF86Macro8 = 0x10081297; - pub const XF86Macro9 = 0x10081298; - pub const XF86Macro10 = 0x10081299; - pub const XF86Macro11 = 0x1008129a; - pub const XF86Macro12 = 0x1008129b; - pub const XF86Macro13 = 0x1008129c; - pub const XF86Macro14 = 0x1008129d; - pub const XF86Macro15 = 0x1008129e; - pub const XF86Macro16 = 0x1008129f; - pub const XF86Macro17 = 0x100812a0; - pub const XF86Macro18 = 0x100812a1; - pub const XF86Macro19 = 0x100812a2; - pub const XF86Macro20 = 0x100812a3; - pub const XF86Macro21 = 0x100812a4; - pub const XF86Macro22 = 0x100812a5; - pub const XF86Macro23 = 0x100812a6; - pub const XF86Macro24 = 0x100812a7; - pub const XF86Macro25 = 0x100812a8; - pub const XF86Macro26 = 0x100812a9; - pub const XF86Macro27 = 0x100812aa; - pub const XF86Macro28 = 0x100812ab; - pub const XF86Macro29 = 0x100812ac; - pub const XF86Macro30 = 0x100812ad; - pub const XF86MacroRecordStart = 0x100812b0; - pub const XF86MacroRecordStop = 0x100812b1; - pub const XF86MacroPresetCycle = 0x100812b2; - pub const XF86MacroPreset1 = 0x100812b3; - pub const XF86MacroPreset2 = 0x100812b4; - pub const XF86MacroPreset3 = 0x100812b5; - pub const XF86KbdLcdMenu1 = 0x100812b8; - pub const XF86KbdLcdMenu2 = 0x100812b9; - pub const XF86KbdLcdMenu3 = 0x100812ba; - pub const XF86KbdLcdMenu4 = 0x100812bb; - pub const XF86KbdLcdMenu5 = 0x100812bc; - pub const SunFA_Grave = 0x1005ff00; - pub const SunFA_Circum = 0x1005ff01; - pub const SunFA_Tilde = 0x1005ff02; - pub const SunFA_Acute = 0x1005ff03; - pub const SunFA_Diaeresis = 0x1005ff04; - pub const SunFA_Cedilla = 0x1005ff05; - pub const SunF36 = 0x1005ff10; - pub const SunF37 = 0x1005ff11; - pub const SunSys_Req = 0x1005ff60; - pub const SunPrint_Screen = 0x0000ff61; - pub const SunCompose = 0x0000ff20; - pub const SunAltGraph = 0x0000ff7e; - pub const SunPageUp = 0x0000ff55; - pub const SunPageDown = 0x0000ff56; - pub const SunUndo = 0x0000ff65; - pub const SunAgain = 0x0000ff66; - pub const SunFind = 0x0000ff68; - pub const SunStop = 0x0000ff69; - pub const SunProps = 0x1005ff70; - pub const SunFront = 0x1005ff71; - pub const SunCopy = 0x1005ff72; - pub const SunOpen = 0x1005ff73; - pub const SunPaste = 0x1005ff74; - pub const SunCut = 0x1005ff75; - pub const SunPowerSwitch = 0x1005ff76; - pub const SunAudioLowerVolume = 0x1005ff77; - pub const SunAudioMute = 0x1005ff78; - pub const SunAudioRaiseVolume = 0x1005ff79; - pub const SunVideoDegauss = 0x1005ff7a; - pub const SunVideoLowerBrightness = 0x1005ff7b; - pub const SunVideoRaiseBrightness = 0x1005ff7c; - pub const SunPowerSwitchShift = 0x1005ff7d; - pub const Dring_accent = 0x1000feb0; - pub const Dcircumflex_accent = 0x1000fe5e; - pub const Dcedilla_accent = 0x1000fe2c; - pub const Dacute_accent = 0x1000fe27; - pub const Dgrave_accent = 0x1000fe60; - pub const Dtilde = 0x1000fe7e; - pub const Ddiaeresis = 0x1000fe22; - pub const DRemove = 0x1000ff00; - pub const hpClearLine = 0x1000ff6f; - pub const hpInsertLine = 0x1000ff70; - pub const hpDeleteLine = 0x1000ff71; - pub const hpInsertChar = 0x1000ff72; - pub const hpDeleteChar = 0x1000ff73; - pub const hpBackTab = 0x1000ff74; - pub const hpKP_BackTab = 0x1000ff75; - pub const hpModelock1 = 0x1000ff48; - pub const hpModelock2 = 0x1000ff49; - pub const hpReset = 0x1000ff6c; - pub const hpSystem = 0x1000ff6d; - pub const hpUser = 0x1000ff6e; - pub const hpmute_acute = 0x100000a8; - pub const hpmute_grave = 0x100000a9; - pub const hpmute_asciicircum = 0x100000aa; - pub const hpmute_diaeresis = 0x100000ab; - pub const hpmute_asciitilde = 0x100000ac; - pub const hplira = 0x100000af; - pub const hpguilder = 0x100000be; - pub const hpYdiaeresis = 0x100000ee; - pub const hpIO = 0x100000ee; - pub const hplongminus = 0x100000f6; - pub const hpblock = 0x100000fc; - pub const osfCopy = 0x1004ff02; - pub const osfCut = 0x1004ff03; - pub const osfPaste = 0x1004ff04; - pub const osfBackTab = 0x1004ff07; - pub const osfBackSpace = 0x1004ff08; - pub const osfClear = 0x1004ff0b; - pub const osfEscape = 0x1004ff1b; - pub const osfAddMode = 0x1004ff31; - pub const osfPrimaryPaste = 0x1004ff32; - pub const osfQuickPaste = 0x1004ff33; - pub const osfPageLeft = 0x1004ff40; - pub const osfPageUp = 0x1004ff41; - pub const osfPageDown = 0x1004ff42; - pub const osfPageRight = 0x1004ff43; - pub const osfActivate = 0x1004ff44; - pub const osfMenuBar = 0x1004ff45; - pub const osfLeft = 0x1004ff51; - pub const osfUp = 0x1004ff52; - pub const osfRight = 0x1004ff53; - pub const osfDown = 0x1004ff54; - pub const osfEndLine = 0x1004ff57; - pub const osfBeginLine = 0x1004ff58; - pub const osfEndData = 0x1004ff59; - pub const osfBeginData = 0x1004ff5a; - pub const osfPrevMenu = 0x1004ff5b; - pub const osfNextMenu = 0x1004ff5c; - pub const osfPrevField = 0x1004ff5d; - pub const osfNextField = 0x1004ff5e; - pub const osfSelect = 0x1004ff60; - pub const osfInsert = 0x1004ff63; - pub const osfUndo = 0x1004ff65; - pub const osfMenu = 0x1004ff67; - pub const osfCancel = 0x1004ff69; - pub const osfHelp = 0x1004ff6a; - pub const osfSelectAll = 0x1004ff71; - pub const osfDeselectAll = 0x1004ff72; - pub const osfReselect = 0x1004ff73; - pub const osfExtend = 0x1004ff74; - pub const osfRestore = 0x1004ff78; - pub const osfDelete = 0x1004ffff; - pub const Reset = 0x1000ff6c; - pub const System = 0x1000ff6d; - pub const User = 0x1000ff6e; - pub const ClearLine = 0x1000ff6f; - pub const InsertLine = 0x1000ff70; - pub const DeleteLine = 0x1000ff71; - pub const InsertChar = 0x1000ff72; - pub const DeleteChar = 0x1000ff73; - pub const BackTab = 0x1000ff74; - pub const KP_BackTab = 0x1000ff75; - pub const Ext16bit_L = 0x1000ff76; - pub const Ext16bit_R = 0x1000ff77; - pub const mute_acute = 0x100000a8; - pub const mute_grave = 0x100000a9; - pub const mute_asciicircum = 0x100000aa; - pub const mute_diaeresis = 0x100000ab; - pub const mute_asciitilde = 0x100000ac; - pub const lira = 0x100000af; - pub const guilder = 0x100000be; - pub const IO = 0x100000ee; - pub const longminus = 0x100000f6; - pub const block = 0x100000fc; - - pub const Flags = enum(c_int) { - no_flags = 0, - case_insensitive = 1 << 0, - }; - - extern fn xkb_keysym_get_name(keysym: Keysym, buffer: [*]u8, size: usize) c_int; - pub const getName = xkb_keysym_get_name; - - extern fn xkb_keysym_from_name(name: [*:0]const u8, flags: Flags) Keysym; - pub const fromName = xkb_keysym_from_name; - - extern fn xkb_keysym_to_utf8(keysym: Keysym, buffer: [*]u8, size: usize) c_int; - pub const toUTF8 = xkb_keysym_to_utf8; - - extern fn xkb_keysym_to_utf32(keysym: Keysym) u32; - pub const toUTF32 = xkb_keysym_to_utf32; - - extern fn xkb_utf32_to_keysym(ucs: u32) Keysym; - pub const fromUTF32 = xkb_utf32_to_keysym; - - extern fn xkb_keysym_to_upper(ks: Keysym) Keysym; - pub const toUpper = xkb_keysym_to_upper; - - extern fn xkb_keysym_to_lower(ks: Keysym) Keysym; - pub const toLower = xkb_keysym_to_lower; -}; diff --git a/deps/zig-xkbcommon/src/xkbcommon_names.zig b/deps/zig-xkbcommon/src/xkbcommon_names.zig deleted file mode 100644 index 51ddd51..0000000 --- a/deps/zig-xkbcommon/src/xkbcommon_names.zig +++ /dev/null @@ -1,14 +0,0 @@ -pub const mod = struct { - pub const shift = "Shift"; - pub const caps = "Lock"; - pub const ctrl = "Control"; - pub const alt = "Mod1"; - pub const num = "Mod2"; - pub const logo = "Mod4"; -}; - -pub const led = struct { - pub const caps = "Caps Lock"; - pub const num = "Num Lock"; - pub const scroll = "Scroll Lock"; -}; diff --git a/examples/00_client_connect.zig b/examples/00_client_connect.zig deleted file mode 100644 index 730ee4d..0000000 --- a/examples/00_client_connect.zig +++ /dev/null @@ -1,556 +0,0 @@ -const std = @import("std"); - -/// The version of the wl_shm protocol we will be targeting. -const WL_SHM_VERSION = 1; -/// The version of the wl_compositor protocol we will be targeting. -const WL_COMPOSITOR_VERSION = 5; -/// The version of the xdg_wm_base protocol we will be targeting. -const XDG_WM_BASE_VERSION = 2; - -/// https://wayland.app/protocols/xdg-shell#xdg_surface:request:ack_configure -const XDG_SURFACE_REQUEST_ACK_CONFIGURE = 4; - -// https://wayland.app/protocols/wayland#wl_registry:event:global -const WL_REGISTRY_EVENT_GLOBAL = 0; - -pub fn main() !void { - var general_allocator = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = general_allocator.deinit(); - const gpa = general_allocator.allocator(); - - const display_path = try getDisplayPath(gpa); - defer gpa.free(display_path); - - const socket = try std.net.connectUnixSocket(display_path); - defer socket.close(); - - const display_id = 1; - var next_id: u32 = 2; - - // reserve an object id for the registry - const registry_id = next_id; - next_id += 1; - - try socket.writeAll(std.mem.sliceAsBytes(&[_]u32{ - // ID of the object; in this case the default wl_display object at 1 - 1, - - // The size (in bytes) of the message and the opcode, which is object specific. - // In this case we are using opcode 1, which corresponds to `wl_display::get_registry`. - // - // The size includes the size of the header. - (0x000C << 16) | (0x0001), - - // Finally, we pass in the only argument that this opcode takes: an id for the `wl_registry` - // we are creating. - registry_id, - })); - - // create a sync callback so we know when we are caught up with the server - const registry_done_callback_id = next_id; - next_id += 1; - - try socket.writeAll(std.mem.sliceAsBytes(&[_]u32{ - display_id, - - // The size (in bytes) of the message and the opcode. - // In this case we are using opcode 0, which corresponds to `wl_display::sync`. - // - // The size includes the size of the header. - (0x000C << 16) | (0x0000), - - // Finally, we pass in the only argument that this opcode takes: an id for the `wl_registry` - // we are creating. - registry_done_callback_id, - })); - - var shm_id_opt: ?u32 = null; - var compositor_id_opt: ?u32 = null; - var xdg_wm_base_id_opt: ?u32 = null; - - // How do we know that the opcode for WL_REGISTRY_REQUEST is 0? Because it is the first `request` in the protocol for `wl_registry`. - const WL_REGISTRY_REQUEST_BIND = 0; - - var message_buffer = std.ArrayList(u8).init(gpa); - defer message_buffer.deinit(); - while (true) { - const event = try Event.read(socket, &message_buffer); - - // Parse event messages based on which object it is for - if (event.header.object_id == registry_done_callback_id) { - // No need to parse the message body, there is only one possible opcode - break; - } - - if (event.header.object_id == registry_id and event.header.opcode == WL_REGISTRY_EVENT_GLOBAL) { - // Parse out the fields of the global event - const name: u32 = @bitCast(event.body[0..4].*); - - const interface_str_len: u32 = @bitCast(event.body[4..8].*); - // The interface_str is `interface_str_len - 1` because `interface_str_len` includes the null pointer - const interface_str: [:0]const u8 = event.body[8..][0 .. interface_str_len - 1 :0]; - - const interface_str_len_u32_align = std.mem.alignForward(u32, interface_str_len, @alignOf(u32)); - const version: u32 = @bitCast(event.body[8 + interface_str_len_u32_align ..][0..4].*); - - // Check to see if the interface is one of the globals we are looking for - if (std.mem.eql(u8, interface_str, "wl_shm")) { - if (version < WL_SHM_VERSION) { - std.log.err("compositor supports only {s} version {}, client expected version >= {}", .{ interface_str, version, WL_SHM_VERSION }); - return error.WaylandInterfaceOutOfDate; - } - shm_id_opt = next_id; - next_id += 1; - - try writeRequest(socket, registry_id, WL_REGISTRY_REQUEST_BIND, &[_]u32{ - // The numeric name of the global we want to bind. - name, - - // `new_id` arguments have three parts when the sub-type is not specified by the protocol: - // 1. A string specifying the textual name of the interface - "wl_shm".len + 1, // length of "wl_shm" plus one for the required null byte - @bitCast(@as([4]u8, "wl_s".*)), - @bitCast(@as([4]u8, "hm\x00\x00".*)), // we have two 0x00 bytes to align the string with u32 - - // 2. The version you are using, affects which functions you can access - WL_SHM_VERSION, - - // 3. And the `new_id` part, where we tell it which client id we are giving it - shm_id_opt.?, - }); - } else if (std.mem.eql(u8, interface_str, "wl_compositor")) { - if (version < WL_COMPOSITOR_VERSION) { - std.log.err("compositor supports only {s} version {}, client expected version >= {}", .{ interface_str, version, WL_COMPOSITOR_VERSION }); - return error.WaylandInterfaceOutOfDate; - } - compositor_id_opt = next_id; - next_id += 1; - - try writeRequest(socket, registry_id, WL_REGISTRY_REQUEST_BIND, &[_]u32{ - name, - "wl_compositor".len + 1, // add one for the required null byte - @bitCast(@as([4]u8, "wl_c".*)), - @bitCast(@as([4]u8, "ompo".*)), - @bitCast(@as([4]u8, "sito".*)), - @bitCast(@as([4]u8, "r\x00\x00\x00".*)), - WL_COMPOSITOR_VERSION, - compositor_id_opt.?, - }); - } else if (std.mem.eql(u8, interface_str, "xdg_wm_base")) { - if (version < XDG_WM_BASE_VERSION) { - std.log.err("compositor supports only {s} version {}, client expected version >= {}", .{ interface_str, version, XDG_WM_BASE_VERSION }); - return error.WaylandInterfaceOutOfDate; - } - xdg_wm_base_id_opt = next_id; - next_id += 1; - - try writeRequest(socket, registry_id, WL_REGISTRY_REQUEST_BIND, &[_]u32{ - name, - "xdg_wm_base".len + 1, - @bitCast(@as([4]u8, "xdg_".*)), - @bitCast(@as([4]u8, "wm_b".*)), - @bitCast(@as([4]u8, "ase\x00".*)), - XDG_WM_BASE_VERSION, - xdg_wm_base_id_opt.?, - }); - } - continue; - } - } - - const shm_id = shm_id_opt orelse return error.NeccessaryWaylandExtensionMissing; - const compositor_id = compositor_id_opt orelse return error.NeccessaryWaylandExtensionMissing; - const xdg_wm_base_id = xdg_wm_base_id_opt orelse return error.NeccessaryWaylandExtensionMissing; - - std.log.debug("wl_shm client id = {}; wl_compositor client id = {}; xdg_wm_base client id = {}", .{ shm_id, compositor_id, xdg_wm_base_id }); - - // Create a surface using wl_compositor::create_surface - const surface_id = next_id; - next_id += 1; - // https://wayland.app/protocols/wayland#wl_compositor:request:create_surface - const WL_COMPOSITOR_REQUEST_CREATE_SURFACE = 0; - try writeRequest(socket, compositor_id, WL_COMPOSITOR_REQUEST_CREATE_SURFACE, &[_]u32{ - // id: new_id - surface_id, - }); - - // Create an xdg_surface - const xdg_surface_id = next_id; - next_id += 1; - // https://wayland.app/protocols/xdg-shell#xdg_wm_base:request:get_xdg_surface - const XDG_WM_BASE_REQUEST_GET_XDG_SURFACE = 2; - try writeRequest(socket, xdg_wm_base_id, XDG_WM_BASE_REQUEST_GET_XDG_SURFACE, &[_]u32{ - // id: new_id - xdg_surface_id, - // surface: object - surface_id, - }); - - // Get the xdg_surface as an xdg_toplevel object - const xdg_toplevel_id = next_id; - next_id += 1; - // https://wayland.app/protocols/xdg-shell#xdg_surface:request:get_toplevel - const XDG_SURFACE_REQUEST_GET_TOPLEVEL = 1; - try writeRequest(socket, xdg_surface_id, XDG_SURFACE_REQUEST_GET_TOPLEVEL, &[_]u32{ - // id: new_id - xdg_toplevel_id, - }); - - // Commit the surface. This tells the compositor that the current batch of - // changes is ready, and they can now be applied. - - // https://wayland.app/protocols/wayland#wl_surface:request:commit - const WL_SURFACE_REQUEST_COMMIT = 6; - try writeRequest(socket, surface_id, WL_SURFACE_REQUEST_COMMIT, &[_]u32{}); - - // Wait for the surface to be configured before moving on - while (true) { - const event = try Event.read(socket, &message_buffer); - - if (event.header.object_id == xdg_surface_id) { - switch (event.header.opcode) { - // https://wayland.app/protocols/xdg-shell#xdg_surface:event:configure - 0 => { - // The configure event acts as a heartbeat. Every once in a while the compositor will send us - // a `configure` event, and if our application doesn't respond with an `ack_configure` response - // it will assume our program has died and destroy the window. - const serial: u32 = @bitCast(event.body[0..4].*); - - try writeRequest(socket, xdg_surface_id, XDG_SURFACE_REQUEST_ACK_CONFIGURE, &[_]u32{ - // We respond with the number it sent us, so it knows which configure we are responding to. - serial, - }); - - try writeRequest(socket, surface_id, WL_SURFACE_REQUEST_COMMIT, &[_]u32{}); - - // The surface has been configured! We can move on - break; - }, - else => return error.InvalidOpcode, - } - } else { - std.log.warn("unknown event {{ .object_id = {}, .opcode = {x}, .message = \"{}\" }}", .{ event.header.object_id, event.header.opcode, std.zig.fmtEscapes(std.mem.sliceAsBytes(event.body)) }); - } - } - - // allocate a shared memory file, which we will use as a framebuffer to write pixels into - const Pixel = [4]u8; - const framebuffer_size = [2]usize{ 128, 128 }; - const shared_memory_pool_len = framebuffer_size[0] * framebuffer_size[1] * @sizeOf(Pixel); - - const shared_memory_pool_fd = try std.os.memfd_create("my-wayland-framebuffer", 0); - try std.os.ftruncate(shared_memory_pool_fd, shared_memory_pool_len); - - // Create a wl_shm_pool (wayland shared memory pool). This will be used to create framebuffers, - // though in this article we only plan on creating one. - const wl_shm_pool_id = try writeWlShmRequestCreatePool( - socket, - shm_id, - &next_id, - shared_memory_pool_fd, - @intCast(shared_memory_pool_len), - ); - - // Now we allocate a framebuffer from the shared memory pool - const wl_buffer_id = next_id; - next_id += 1; - - // https://wayland.app/protocols/wayland#wl_shm_pool:request:create_buffer - const WL_SHM_POOL_REQUEST_CREATE_BUFFER = 0; - // https://wayland.app/protocols/wayland#wl_shm:enum:format - const WL_SHM_POOL_ENUM_FORMAT_ARGB8888 = 0; - try writeRequest(socket, wl_shm_pool_id, WL_SHM_POOL_REQUEST_CREATE_BUFFER, &[_]u32{ - // id: new_id, - wl_buffer_id, - // Byte offset of the framebuffer in the pool. In this case we allocate it at the very start of the file. - 0, - // Width of the framebuffer. - framebuffer_size[0], - // Height of the framebuffer. - framebuffer_size[1], - // Stride of the framebuffer, or rather, how many bytes are in a single row of pixels. - framebuffer_size[0] * @sizeOf(Pixel), - // The format of the framebuffer. In this case we choose argb8888. - WL_SHM_POOL_ENUM_FORMAT_ARGB8888, - }); - - // Now we turn the shared memory pool and the framebuffer we just allocated into slices on our side for ease of use. - const shared_memory_pool_bytes = try std.os.mmap(null, shared_memory_pool_len, std.os.PROT.READ | std.os.PROT.WRITE, std.os.MAP.SHARED, shared_memory_pool_fd, 0); - const framebuffer = @as([*]Pixel, @ptrCast(shared_memory_pool_bytes.ptr))[0 .. shared_memory_pool_bytes.len / @sizeOf(Pixel)]; - - // put some interesting colors into the framebuffer - for (0..framebuffer_size[1]) |y| { - const row = framebuffer[y * framebuffer_size[0] .. (y + 1) * framebuffer_size[0]]; - for (row, 0..framebuffer_size[0]) |*pixel, x| { - pixel.* = .{ - @truncate(x), - @truncate(y), - 0x00, - 0xFF, - }; - } - } - - // Now we attach the framebuffer to the surface at <0, 0>. The x and y MUST be <0, 0> since version 5 of WL_SURFACE, - // which we are using. - - // https://wayland.app/protocols/wayland#wl_surface:request:attach - const WL_SURFACE_REQUEST_ATTACH = 1; - try writeRequest(socket, surface_id, WL_SURFACE_REQUEST_ATTACH, &[_]u32{ - // buffer: object, - wl_buffer_id, - // The x offset of the buffer. - 0, - // The y offset of the buffer. - 0, - }); - - // We mark the surface as damaged, meaning that the compositor should update what is rendered on the window. - // You can specify specific damage regions; but in this case we just damage the entire surface. - - // https://wayland.app/protocols/wayland#wl_surface:request:damage - const WL_SURFACE_REQUEST_DAMAGE = 2; - try writeRequest(socket, surface_id, WL_SURFACE_REQUEST_DAMAGE, &[_]u32{ - // The x offset of the damage region. - 0, - // The y offset of the damage region. - 0, - // The width of the damage region. - @bitCast(@as(i32, std.math.maxInt(i32))), - // The height of the damage region. - @bitCast(@as(i32, std.math.maxInt(i32))), - }); - - // Commit the surface. This tells wayland that we are done making changes, and it can display all the changes that have been - // made so far. - // const WL_SURFACE_REQUEST_COMMIT = 6; - try writeRequest(socket, surface_id, WL_SURFACE_REQUEST_COMMIT, &[_]u32{}); - - // Now we finally, finally, get to the main loop of the program. - var running = true; - while (running) { - const event = try Event.read(socket, &message_buffer); - - if (event.header.object_id == xdg_surface_id) { - switch (event.header.opcode) { - // https://wayland.app/protocols/xdg-shell#xdg_surface:event:configure - 0 => { - // The configure event acts as a heartbeat. Every once in a while the compositor will send us - // a `configure` event, and if our application doesn't respond with an `ack_configure` response - // it will assume our program has died and destroy the window. - const serial: u32 = @bitCast(event.body[0..4].*); - - try writeRequest(socket, xdg_surface_id, XDG_SURFACE_REQUEST_ACK_CONFIGURE, &[_]u32{ - // We respond with the number it sent us, so it knows which configure we are responding to. - serial, - }); - try writeRequest(socket, surface_id, WL_SURFACE_REQUEST_COMMIT, &[_]u32{}); - }, - else => return error.InvalidOpcode, - } - } else if (event.header.object_id == xdg_toplevel_id) { - switch (event.header.opcode) { - // https://wayland.app/protocols/xdg-shell#xdg_toplevel:event:configure - 0 => { - // The xdg_toplevel:configure event asks us to resize the window. For now, we will ignore it expect to - // log it. - const width: u32 = @bitCast(event.body[0..4].*); - const height: u32 = @bitCast(event.body[4..8].*); - const states_len: u32 = @bitCast(event.body[8..12].*); - const states = @as([*]const u32, @ptrCast(@alignCast(event.body[12..].ptr)))[0..states_len]; - - std.log.debug("xdg_toplevel:configure({}, {}, {any})", .{ width, height, states }); - }, - // https://wayland.app/protocols/xdg-shell#xdg_toplevel:event:close - 1 => { - // The compositor asked us to close the window. - running = false; - std.log.debug("xdg_toplevel:close()", .{}); - }, - // https://wayland.app/protocols/xdg-shell#xdg_toplevel:event:configure_bounds - 2 => std.log.debug("xdg_toplevel:configure_bounds()", .{}), - // https://wayland.app/protocols/xdg-shell#xdg_toplevel:event:wm_capabilities - 3 => std.log.debug("xdg_toplevel:wm_capabilities()", .{}), - else => return error.InvalidOpcode, - } - } else if (event.header.object_id == wl_buffer_id) { - switch (event.header.opcode) { - // https://wayland.app/protocols/wayland#wl_buffer:event:release - 0 => { - // The xdg_toplevel:release event let's us know that it is safe to reuse the buffer now. - std.log.debug("wl_buffer:release()", .{}); - }, - else => return error.InvalidOpcode, - } - } else if (event.header.object_id == display_id) { - switch (event.header.opcode) { - // https://wayland.app/protocols/wayland#wl_display:event:error - 0 => { - const object_id: u32 = @bitCast(event.body[0..4].*); - const error_code: u32 = @bitCast(event.body[4..8].*); - const error_message_len: u32 = @bitCast(event.body[8..12].*); - const error_message = event.body[12 .. error_message_len - 1 :0]; - std.log.warn("wl_display:error({}, {}, \"{}\")", .{ object_id, error_code, std.zig.fmtEscapes(error_message) }); - }, - // https://wayland.app/protocols/wayland#wl_display:event:delete_id - 1 => { - // wl_display:delete_id tells us that we can reuse an id. In this article we log it, but - // otherwise ignore it. - const name: u32 = @bitCast(event.body[0..4].*); - std.log.debug("wl_display:delete_id({})", .{name}); - }, - else => return error.InvalidOpcode, - } - } else { - std.log.warn("unknown event {{ .object_id = {}, .opcode = {x}, .message = \"{}\" }}", .{ event.header.object_id, event.header.opcode, std.zig.fmtEscapes(std.mem.sliceAsBytes(event.body)) }); - } - } -} - -pub fn getDisplayPath(gpa: std.mem.Allocator) ![]u8 { - const xdg_runtime_dir_path = try std.process.getEnvVarOwned(gpa, "XDG_RUNTIME_DIR"); - defer gpa.free(xdg_runtime_dir_path); - const display_name = std.process.getEnvVarOwned(gpa, "WAYLAND_DISPLAY") catch |err| switch (err) { - error.EnvironmentVariableNotFound => return try std.fs.path.join(gpa, &.{ xdg_runtime_dir_path, "wayland-0" }), - else => return err, - }; - defer gpa.free(display_name); - - return try std.fs.path.join(gpa, &.{ xdg_runtime_dir_path, display_name }); -} - -/// A wayland packet header -const Header = extern struct { - object_id: u32 align(1), - opcode: u16 align(1), - size: u16 align(1), - - pub fn read(socket: std.net.Stream) !Header { - var header: Header = undefined; - const header_bytes_read = try socket.readAll(std.mem.asBytes(&header)); - if (header_bytes_read < @sizeOf(Header)) { - return error.UnexpectedEOF; - } - return header; - } -}; - -/// This is the general shape of a Wayland `Event` (a message from the compositor to the client). -const Event = struct { - header: Header, - body: []const u8, - - pub fn read(socket: std.net.Stream, body_buffer: *std.ArrayList(u8)) !Event { - const header = try Header.read(socket); - - // read bytes until we match the size in the header, not including the bytes in the header. - try body_buffer.resize(header.size - @sizeOf(Header)); - const message_bytes_read = try socket.readAll(body_buffer.items); - if (message_bytes_read < body_buffer.items.len) { - return error.UnexpectedEOF; - } - - return Event{ - .header = header, - .body = body_buffer.items, - }; - } -}; - -/// Handles creating a header and writing the request to the socket. -pub fn writeRequest(socket: std.net.Stream, object_id: u32, opcode: u16, message: []const u32) !void { - const message_bytes = std.mem.sliceAsBytes(message); - const header = Header{ - .object_id = object_id, - .opcode = opcode, - .size = @sizeOf(Header) + @as(u16, @intCast(message_bytes.len)), - }; - - try socket.writeAll(std.mem.asBytes(&header)); - try socket.writeAll(message_bytes); -} - -/// https://wayland.app/protocols/wayland#wl_shm:request:create_pool -const WL_SHM_REQUEST_CREATE_POOL = 0; - -/// This request is more complicated that most other requests, because it has to send the file descriptor to the -/// compositor using a control message. -/// -/// Returns the id of the newly create wl_shm_pool -pub fn writeWlShmRequestCreatePool(socket: std.net.Stream, wl_shm_id: u32, next_id: *u32, fd: std.os.fd_t, fd_len: i32) !u32 { - const wl_shm_pool_id = next_id.*; - - const message = [_]u32{ - // id: new_id - wl_shm_pool_id, - // size: int - @intCast(fd_len), - }; - // If you're paying close attention, you'll notice that our message only has two parameters in it, despite the - // documentation calling for 3: wl_shm_pool_id, fd, and size. This is because `fd` is sent in the control message, - // and so not included in the regular message body. - - // Create the message header as usual - const message_bytes = std.mem.sliceAsBytes(&message); - const header = Header{ - .object_id = wl_shm_id, - .opcode = WL_SHM_REQUEST_CREATE_POOL, - .size = @sizeOf(Header) + @as(u16, @intCast(message_bytes.len)), - }; - const header_bytes = std.mem.asBytes(&header); - - // we'll be using `std.os.sendmsg` to send a control message, so we may as well use the vectorized - // IO to send the header and the message body while we're at it. - const msg_iov = [_]std.os.iovec_const{ - .{ - .iov_base = header_bytes.ptr, - .iov_len = header_bytes.len, - }, - .{ - .iov_base = message_bytes.ptr, - .iov_len = message_bytes.len, - }, - }; - - // Send the file descriptor through a control message - - // This is the control message! It is not a fixed size struct. Instead it varies depending on the message you want to send. - // C uses macros to define it, here we make a comptime function instead. - const control_message = cmsg(std.os.fd_t){ - .level = std.os.SOL.SOCKET, - .type = 0x01, // value of SCM_RIGHTS - .data = fd, - }; - const control_message_bytes = std.mem.asBytes(&control_message); - - const socket_message = std.os.msghdr_const{ - .name = null, - .namelen = 0, - .iov = &msg_iov, - .iovlen = msg_iov.len, - .control = control_message_bytes.ptr, - // This is the size of the control message in bytes - .controllen = control_message_bytes.len, - .flags = 0, - }; - - const bytes_sent = try std.os.sendmsg(socket.handle, &socket_message, 0); - if (bytes_sent < header_bytes.len + message_bytes.len) { - return error.ConnectionClosed; - } - - // Wait to increment until we know the message has been sent - next_id.* += 1; - return wl_shm_pool_id; -} - -fn cmsg(comptime T: type) type { - const padding_size = (@sizeOf(T) + @sizeOf(c_long) - 1) & ~(@as(usize, @sizeOf(c_long)) - 1); - return extern struct { - len: c_ulong = @sizeOf(@This()) - padding_size, - level: c_int, - type: c_int, - data: T, - _padding: [padding_size]u8 align(1) = [_]u8{0} ** padding_size, - }; -} diff --git a/examples/01_client_connect.zig b/examples/01_client_connect.zig deleted file mode 100644 index f9393f8..0000000 --- a/examples/01_client_connect.zig +++ /dev/null @@ -1,375 +0,0 @@ -const std = @import("std"); -const wayland = @import("wayland"); - -const Pixel = [4]u8; -const Theme = struct { - const background = 0x282A36; - const current_line = 0x44475A; - const foreground = 0xF8F8F2; - const comment = 0x6272A4; - - const cyan = 0x8BE9FD; - const green = 0x50FA7B; - const orange = 0xFFB86C; - const pink = 0xFF79C6; - const purple = 0xBD93F9; - const red = 0xFF5555; - const yellow = 0xF1FA8C; -}; - -fn toPixel(color: u24) Pixel { - return .{ - @intCast(color & 0xFF), - @intCast(color >> 8 & 0xFF), - @intCast(color >> 16 & 0xFF), - 0xFF, - }; -} - -pub fn main() !void { - var general_allocator = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = general_allocator.deinit(); - const gpa = general_allocator.allocator(); - - const display_path = try wayland.getDisplayPath(gpa); - defer gpa.free(display_path); - - var conn = try wayland.Conn.init(gpa, display_path); - defer conn.deinit(); - - // Create an id pool to allocate ids for us - var id_pool = wayland.IdPool{}; - - const ids = try wayland.registerGlobals(gpa, &id_pool, conn.socket, &.{ - wayland.core.Shm, - wayland.core.Compositor, - wayland.xdg.WmBase, - wayland.core.Seat, - wayland.zxdg.DecorationManagerV1, - wayland.zwp.TextInputManagerV3, - }); - - const DISPLAY_ID = 1; - const shm_id = ids[0] orelse return error.NeccessaryWaylandExtensionMissing; - const compositor_id = ids[1] orelse return error.NeccessaryWaylandExtensionMissing; - const xdg_wm_base_id = ids[2] orelse return error.NeccessaryWaylandExtensionMissing; - - const surface_id = id_pool.create(); - try conn.send( - wayland.core.Compositor.Request, - compositor_id, - .{ .create_surface = .{ - .new_id = surface_id, - } }, - ); - - const xdg_surface_id = id_pool.create(); - try conn.send( - wayland.xdg.WmBase.Request, - xdg_wm_base_id, - .{ .get_xdg_surface = .{ - .id = xdg_surface_id, - .surface = surface_id, - } }, - ); - - const xdg_toplevel_id = id_pool.create(); - try conn.send( - wayland.xdg.Surface.Request, - xdg_surface_id, - .{ .get_toplevel = .{ - .id = xdg_toplevel_id, - } }, - ); - - var zxdg_toplevel_decoration_id_opt: ?u32 = null; - if (ids[4]) |zxdg_decoration_manager_id| { - zxdg_toplevel_decoration_id_opt = id_pool.create(); - try conn.send( - wayland.zxdg.DecorationManagerV1.Request, - zxdg_decoration_manager_id, - .{ .get_toplevel_decoration = .{ - .new_id = zxdg_toplevel_decoration_id_opt.?, - .toplevel = xdg_toplevel_id, - } }, - ); - } - - try conn.send( - wayland.core.Surface.Request, - surface_id, - wayland.core.Surface.Request.commit, - ); - - const registry_done_id = id_pool.create(); - try conn.send( - wayland.core.Display.Request, - DISPLAY_ID, - .{ .sync = .{ .callback = registry_done_id } }, - ); - - var done = false; - var surface_configured = false; - while (!done or !surface_configured) { - const header, const body = try conn.recv(); - - if (header.object_id == xdg_surface_id) { - const event = try wayland.deserialize(wayland.xdg.Surface.Event, header, body); - switch (event) { - .configure => |conf| { - try conn.send( - wayland.xdg.Surface.Request, - xdg_surface_id, - .{ .ack_configure = .{ - .serial = conf.serial, - } }, - ); - surface_configured = true; - }, - } - } else if (zxdg_toplevel_decoration_id_opt != null and header.object_id == zxdg_toplevel_decoration_id_opt.?) { - const event = try wayland.deserialize(wayland.zxdg.ToplevelDecorationV1.Event, header, body); - std.debug.print("<- zxdg_toplevel_decoration@{}\n", .{event}); - } else if (header.object_id == xdg_toplevel_id) { - const event = try wayland.deserialize(wayland.xdg.Toplevel.Event, header, body); - std.debug.print("<- {}\n", .{event}); - } else if (header.object_id == registry_done_id) { - done = true; - } else if (header.object_id == shm_id) { - const event = try wayland.deserialize(wayland.core.Shm.Event, header, body); - switch (event) { - .format => |format| std.debug.print("<- format {} {}\n", .{ format.format, std.zig.fmtEscapes(std.mem.asBytes(&format.format)) }), - } - } else if (header.object_id == DISPLAY_ID) { - const event = try wayland.deserialize(wayland.core.Display.Event, header, body); - switch (event) { - .@"error" => |err| std.debug.print("<- error({}): {} {s}\n", .{ err.object_id, err.code, err.message }), - .delete_id => |id| { - std.debug.print("id {} deleted\n", .{id}); - id_pool.destroy(id.id); - }, - } - } else { - std.debug.print("{} {x} \"{}\"\n", .{ header.object_id, header.size_and_opcode.opcode, std.zig.fmtEscapes(std.mem.sliceAsBytes(body)) }); - } - } - - // allocate a shared memory file for display purposes - const framebuffer_size = [2]u32{ 128, 128 }; - const pool_file_len = 1024 * framebuffer_size[0] * framebuffer_size[1] * @sizeOf(Pixel); - - const pool_fd = try std.os.memfd_create("my-wayland-framebuffer", 0); - try std.os.ftruncate(pool_fd, pool_file_len); - const pool_bytes = try std.os.mmap(null, pool_file_len, std.os.PROT.READ | std.os.PROT.WRITE, std.os.MAP.SHARED, pool_fd, 0); - var pool_fixed_buffer_allocator = std.heap.FixedBufferAllocator.init(pool_bytes); - var pool_general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){ .backing_allocator = pool_fixed_buffer_allocator.allocator() }; - const pool_alloc = pool_general_purpose_allocator.allocator(); - - const framebuffer = try pool_alloc.alloc(Pixel, framebuffer_size[0] * framebuffer_size[1]); - - // put some interesting colors into the framebuffer - renderGradient(framebuffer, framebuffer_size); - - const wl_shm_pool_id = id_pool.create(); - { - std.debug.print("framebuffer_fd: {}\n", .{pool_fd}); - try conn.send( - wayland.core.Shm.Request, - shm_id, - .{ .create_pool = .{ - .new_id = wl_shm_pool_id, - .fd = @enumFromInt(pool_fd), - .size = pool_file_len, - } }, - ); - } - - var framebuffers = std.AutoHashMap(u32, []Pixel).init(gpa); - defer framebuffers.deinit(); - try framebuffers.put(wl_shm_pool_id, framebuffer); - - const wl_buffer_id = id_pool.create(); - try conn.send( - wayland.core.ShmPool.Request, - wl_shm_pool_id, - .{ .create_buffer = .{ - .new_id = wl_buffer_id, - .offset = 0, - .width = framebuffer_size[0], - .height = framebuffer_size[1], - .stride = framebuffer_size[0] * @sizeOf([4]u8), - .format = .argb8888, - } }, - ); - - try conn.send( - wayland.core.Surface.Request, - surface_id, - .{ .attach = .{ - .buffer = wl_buffer_id, - .x = 0, - .y = 0, - } }, - ); - - try conn.send( - wayland.core.Surface.Request, - surface_id, - .{ .damage = .{ - .x = 0, - .y = 0, - .width = std.math.maxInt(i32), - .height = std.math.maxInt(i32), - } }, - ); - - try conn.send( - wayland.core.Surface.Request, - surface_id, - wayland.core.Surface.Request.commit, - ); - - var window_size: [2]u32 = [2]u32{ @intCast(framebuffer_size[0]), @intCast(framebuffer_size[1]) }; - - var running = true; - while (running) { - const header, const body = try conn.recv(); - - if (header.object_id == xdg_surface_id) { - const event = try wayland.deserialize(wayland.xdg.Surface.Event, header, body); - switch (event) { - .configure => |conf| { - try conn.send( - wayland.xdg.Surface.Request, - xdg_surface_id, - .{ .ack_configure = .{ - .serial = conf.serial, - } }, - ); - - const new_buffer_id = id_pool.create(); - const new_framebuffer = try pool_alloc.alloc(Pixel, window_size[0] * window_size[1]); - try framebuffers.put(new_buffer_id, new_framebuffer); - - // put some interesting colors into the new_framebuffer - renderGradient(new_framebuffer, window_size); - - try conn.send( - wayland.core.ShmPool.Request, - wl_shm_pool_id, - .{ .create_buffer = .{ - .new_id = new_buffer_id, - .offset = @intCast(@intFromPtr(new_framebuffer.ptr) - @intFromPtr(pool_bytes.ptr)), - .width = @intCast(window_size[0]), - .height = @intCast(window_size[1]), - .stride = @as(i32, @intCast(window_size[0])) * @sizeOf([4]u8), - .format = .argb8888, - } }, - ); - - try conn.send( - wayland.core.Surface.Request, - surface_id, - .{ .attach = .{ - .buffer = new_buffer_id, - .x = 0, - .y = 0, - } }, - ); - - try conn.send( - wayland.core.Surface.Request, - surface_id, - .{ .damage = .{ - .x = 0, - .y = 0, - .width = std.math.maxInt(i32), - .height = std.math.maxInt(i32), - } }, - ); - - // commit the configuration - try conn.send( - wayland.core.Surface.Request, - surface_id, - wayland.core.Surface.Request.commit, - ); - }, - } - } else if (header.object_id == xdg_toplevel_id) { - const event = try wayland.deserialize(wayland.xdg.Toplevel.Event, header, body); - switch (event) { - .configure => |conf| { - std.debug.print("<- xdg_toplevel@{} configure <{}, {}> {any}\n", .{ header.object_id, conf.width, conf.height, conf.states }); - window_size = .{ - @intCast(conf.width), - @intCast(conf.height), - }; - }, - .close => running = false, - else => |tag| std.debug.print("<- xdg_toplevel@{} {s} {}\n", .{ header.object_id, @tagName(tag), event }), - } - } else if (header.object_id == xdg_wm_base_id) { - const event = try wayland.deserialize(wayland.xdg.WmBase.Event, header, body); - switch (event) { - .ping => |ping| { - try conn.send( - wayland.xdg.WmBase.Request, - xdg_wm_base_id, - .{ .pong = .{ - .serial = ping.serial, - } }, - ); - }, - } - } else if (framebuffers.get(header.object_id)) |framebuffer_slice| { - const event = try wayland.deserialize(wayland.core.Buffer.Event, header, body); - switch (event) { - .release => { - _ = framebuffers.remove(header.object_id); - pool_alloc.free(framebuffer_slice); - }, - } - } else if (header.object_id == DISPLAY_ID) { - const event = try wayland.deserialize(wayland.core.Display.Event, header, body); - switch (event) { - .@"error" => |err| std.debug.print("<- error({}): {} {s}\n", .{ err.object_id, err.code, err.message }), - .delete_id => |id| id_pool.destroy(id.id), - } - } else { - std.debug.print("{} {x} \"{}\"\n", .{ header.object_id, header.size_and_opcode.opcode, std.zig.fmtEscapes(std.mem.sliceAsBytes(body)) }); - } - } -} - -fn cmsg(comptime T: type) type { - const padding_size = (@sizeOf(T) + @sizeOf(c_long) - 1) & ~(@as(usize, @sizeOf(c_long)) - 1); - return extern struct { - len: c_ulong = @sizeOf(@This()) - padding_size, - level: c_int, - type: c_int, - data: T, - _padding: [padding_size]u8 align(1) = [_]u8{0} ** padding_size, - }; -} - -fn getFramebuffer(framebuffers: *std.AutoHashMap(u32, []Pixel), id_pool: *wayland.IdPool, pool_alloc: std.mem.Allocator, fb_size: [2]u32) !struct { u32, []Pixel } { - const new_buffer_id = id_pool.create(); - const new_framebuffer = try pool_alloc.alloc(Pixel, fb_size[0] * fb_size[1]); - try framebuffers.put(new_buffer_id, new_framebuffer); - return .{ new_buffer_id, new_framebuffer }; -} - -fn renderGradient(framebuffer: []Pixel, fb_size: [2]u32) void { - for (0..fb_size[1]) |y| { - const row = framebuffer[y * fb_size[0] .. (y + 1) * fb_size[0]]; - for (row, 0..fb_size[0]) |*pixel, x| { - pixel.* = .{ - @truncate(x), - @truncate(y), - 0x00, - 0xFF, - }; - } - } -} diff --git a/examples/02_text_editor.zig b/examples/02_text_editor.zig deleted file mode 100644 index 84aabf5..0000000 --- a/examples/02_text_editor.zig +++ /dev/null @@ -1,689 +0,0 @@ -const std = @import("std"); -const wayland = @import("wayland"); -const xkbcommon = @import("xkbcommon"); -const font8x8 = @cImport({ - @cInclude("font8x8.h"); -}); -const PieceTable = @import("PieceTable.zig").PieceTable; - -const Pixel = [4]u8; -const Theme = struct { - const background = 0x282A36; - const current_line = 0x44475A; - const foreground = 0xF8F8F2; - const comment = 0x6272A4; - - const cyan = 0x8BE9FD; - const green = 0x50FA7B; - const orange = 0xFFB86C; - const pink = 0xFF79C6; - const purple = 0xBD93F9; - const red = 0xFF5555; - const yellow = 0xF1FA8C; -}; - -fn toPixel(color: u24) Pixel { - return .{ - @intCast(color & 0xFF), - @intCast(color >> 8 & 0xFF), - @intCast(color >> 16 & 0xFF), - 0xFF, - }; -} - -pub fn main() !void { - var general_allocator = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = general_allocator.deinit(); - const gpa = general_allocator.allocator(); - - const display_path = try wayland.getDisplayPath(gpa); - defer gpa.free(display_path); - - var conn = try wayland.Conn.init(gpa, display_path); - defer conn.deinit(); - - // Create an id pool to allocate ids for us - var id_pool = wayland.IdPool{}; - - const ids = try wayland.registerGlobals(gpa, &id_pool, conn.socket, &.{ - wayland.core.Shm, - wayland.core.Compositor, - wayland.xdg.WmBase, - wayland.core.Seat, - wayland.zxdg.DecorationManagerV1, - wayland.zwp.TextInputManagerV3, - }); - - const DISPLAY_ID = 1; - const shm_id = ids[0] orelse return error.NeccessaryWaylandExtensionMissing; - const compositor_id = ids[1] orelse return error.NeccessaryWaylandExtensionMissing; - const xdg_wm_base_id = ids[2] orelse return error.NeccessaryWaylandExtensionMissing; - const wl_seat_id = ids[3] orelse return error.NeccessaryWaylandExtensionMissing; - const zwp_text_input_manager_v3 = ids[5] orelse return error.NeccessaryWaylandExtensionMissing; - - const surface_id = id_pool.create(); - try conn.send( - wayland.core.Compositor.Request, - compositor_id, - .{ .create_surface = .{ - .new_id = surface_id, - } }, - ); - - const xdg_surface_id = id_pool.create(); - try conn.send( - wayland.xdg.WmBase.Request, - xdg_wm_base_id, - .{ .get_xdg_surface = .{ - .id = xdg_surface_id, - .surface = surface_id, - } }, - ); - - const xdg_toplevel_id = id_pool.create(); - try conn.send( - wayland.xdg.Surface.Request, - xdg_surface_id, - .{ .get_toplevel = .{ - .id = xdg_toplevel_id, - } }, - ); - - const zwp_text_input_v3_id = id_pool.create(); - try conn.send( - wayland.zwp.TextInputManagerV3.Request, - zwp_text_input_manager_v3, - .{ .get_text_input = .{ - .id = zwp_text_input_v3_id, - .seat = wl_seat_id, - } }, - ); - - var zxdg_toplevel_decoration_id_opt: ?u32 = null; - if (ids[4]) |zxdg_decoration_manager_id| { - zxdg_toplevel_decoration_id_opt = id_pool.create(); - try conn.send( - wayland.zxdg.DecorationManagerV1.Request, - zxdg_decoration_manager_id, - .{ .get_toplevel_decoration = .{ - .new_id = zxdg_toplevel_decoration_id_opt.?, - .toplevel = xdg_toplevel_id, - } }, - ); - } - - try conn.send( - wayland.core.Surface.Request, - surface_id, - wayland.core.Surface.Request.commit, - ); - - const registry_done_id = id_pool.create(); - try conn.send( - wayland.core.Display.Request, - DISPLAY_ID, - .{ .sync = .{ .callback = registry_done_id } }, - ); - - var done = false; - var surface_configured = false; - var seat_capabilties: ?wayland.core.Seat.Capability = null; - while (!done or !surface_configured) { - const header, const body = try conn.recv(); - - if (header.object_id == xdg_surface_id) { - const event = try wayland.deserialize(wayland.xdg.Surface.Event, header, body); - switch (event) { - .configure => |conf| { - try conn.send( - wayland.xdg.Surface.Request, - xdg_surface_id, - .{ .ack_configure = .{ - .serial = conf.serial, - } }, - ); - surface_configured = true; - }, - } - } else if (zxdg_toplevel_decoration_id_opt != null and header.object_id == zxdg_toplevel_decoration_id_opt.?) { - const event = try wayland.deserialize(wayland.zxdg.ToplevelDecorationV1.Event, header, body); - std.debug.print("<- zxdg_toplevel_decoration@{}\n", .{event}); - } else if (header.object_id == xdg_toplevel_id) { - const event = try wayland.deserialize(wayland.xdg.Toplevel.Event, header, body); - std.debug.print("<- {}\n", .{event}); - } else if (header.object_id == registry_done_id) { - done = true; - } else if (header.object_id == shm_id) { - const event = try wayland.deserialize(wayland.core.Shm.Event, header, body); - switch (event) { - .format => |format| std.debug.print("<- format {} {}\n", .{ format.format, std.zig.fmtEscapes(std.mem.asBytes(&format.format)) }), - } - } else if (header.object_id == wl_seat_id) { - const event = try wayland.deserialize(wayland.core.Seat.Event, header, body); - switch (event) { - .capabilities => |capabilities| { - const cap: wayland.core.Seat.Capability = @bitCast(capabilities.capability); - std.debug.print("<- wl_seat.capabilties = {}\n", .{cap}); - seat_capabilties = cap; - }, - .name => |name| { - std.debug.print("<- wl_seat.name = {s}\n", .{name.name}); - }, - } - } else if (header.object_id == DISPLAY_ID) { - const event = try wayland.deserialize(wayland.core.Display.Event, header, body); - switch (event) { - .@"error" => |err| std.debug.print("<- error({}): {} {s}\n", .{ err.object_id, err.code, err.message }), - .delete_id => |id| { - std.debug.print("id {} deleted\n", .{id}); - id_pool.destroy(id.id); - }, - } - } else { - std.debug.print("{} {x} \"{}\"\n", .{ header.object_id, header.size_and_opcode.opcode, std.zig.fmtEscapes(std.mem.sliceAsBytes(body)) }); - } - } - - var wl_pointer_id_opt: ?u32 = null; - var wl_keyboard_id_opt: ?u32 = null; - if (seat_capabilties) |caps| { - if (caps.pointer) { - wl_pointer_id_opt = id_pool.create(); - std.debug.print("wl pointer id: {}\n", .{wl_pointer_id_opt.?}); - try conn.send( - wayland.core.Seat.Request, - wl_seat_id, - .{ .get_pointer = .{ - .new_id = wl_pointer_id_opt.?, - } }, - ); - } - if (caps.keyboard) { - wl_keyboard_id_opt = id_pool.create(); - std.debug.print("wl keyboard id: {}\n", .{wl_keyboard_id_opt.?}); - try conn.send( - wayland.core.Seat.Request, - wl_seat_id, - .{ .get_keyboard = .{ - .new_id = wl_keyboard_id_opt.?, - } }, - ); - } - } - const wl_pointer_id = wl_pointer_id_opt orelse return error.MissingPointer; - const wl_keyboard_id = wl_keyboard_id_opt orelse return error.MissingKeyboard; - - // allocate a shared memory file for display purposes - const framebuffer_size = [2]u32{ 128, 128 }; - const pool_file_len = 1024 * framebuffer_size[0] * framebuffer_size[1] * @sizeOf(Pixel); - - const pool_fd = try std.os.memfd_create("my-wayland-framebuffer", 0); - try std.os.ftruncate(pool_fd, pool_file_len); - const pool_bytes = try std.os.mmap(null, pool_file_len, std.os.PROT.READ | std.os.PROT.WRITE, std.os.MAP.SHARED, pool_fd, 0); - var pool_fixed_buffer_allocator = std.heap.FixedBufferAllocator.init(pool_bytes); - var pool_general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){ .backing_allocator = pool_fixed_buffer_allocator.allocator() }; - const pool_alloc = pool_general_purpose_allocator.allocator(); - - const framebuffer = try pool_alloc.alloc(Pixel, framebuffer_size[0] * framebuffer_size[1]); - - // put some interesting colors into the framebuffer - renderGradient(framebuffer, framebuffer_size); - - const wl_shm_pool_id = id_pool.create(); - { - std.debug.print("framebuffer_fd: {}\n", .{pool_fd}); - try conn.send( - wayland.core.Shm.Request, - shm_id, - .{ .create_pool = .{ - .new_id = wl_shm_pool_id, - .fd = @enumFromInt(pool_fd), - .size = pool_file_len, - } }, - ); - } - - var framebuffers = std.AutoHashMap(u32, []Pixel).init(gpa); - defer framebuffers.deinit(); - try framebuffers.put(wl_shm_pool_id, framebuffer); - - const wl_buffer_id = id_pool.create(); - try conn.send( - wayland.core.ShmPool.Request, - wl_shm_pool_id, - .{ .create_buffer = .{ - .new_id = wl_buffer_id, - .offset = 0, - .width = framebuffer_size[0], - .height = framebuffer_size[1], - .stride = framebuffer_size[0] * @sizeOf([4]u8), - .format = .argb8888, - } }, - ); - - try conn.send( - wayland.core.Surface.Request, - surface_id, - .{ .attach = .{ - .buffer = wl_buffer_id, - .x = 0, - .y = 0, - } }, - ); - - try conn.send( - wayland.core.Surface.Request, - surface_id, - .{ .damage = .{ - .x = 0, - .y = 0, - .width = std.math.maxInt(i32), - .height = std.math.maxInt(i32), - } }, - ); - - try conn.send( - wayland.core.Surface.Request, - surface_id, - wayland.core.Surface.Request.commit, - ); - - var window_size: [2]u32 = [2]u32{ @intCast(framebuffer_size[0]), @intCast(framebuffer_size[1]) }; - const xkb_ctx = xkbcommon.Context.new(.no_flags) orelse return error.XKBInit; - defer xkb_ctx.unref(); - - var xkb_keymap_opt: ?*xkbcommon.Keymap = null; - defer if (xkb_keymap_opt) |xkb_keymap| { - xkb_keymap.unref(); - }; - var xkb_state_opt: ?*xkbcommon.State = null; - defer if (xkb_state_opt) |xkb_state| { - xkb_state.unref(); - }; - - var piece_table = try PieceTable.init(gpa, "Hello, World!"); - defer piece_table.deinit(); - - var edit_buffer: [1024]u8 = [1]u8{0} ** 1024; - var edit_slice: ?[]u8 = null; - - var delete_before: usize = 0; - var delete_after: usize = 0; - - // var preedit_buffer: [1024]u8 = [1]u8{0} ** 1024; - // var preedit_slice: ?[]u8 = null; - - var cursor_pos: usize = piece_table.getTotalSize(); - - var running = true; - while (running) { - const header, const body = try conn.recv(); - - if (header.object_id == xdg_surface_id) { - const event = try wayland.deserialize(wayland.xdg.Surface.Event, header, body); - switch (event) { - .configure => |conf| { - try conn.send( - wayland.xdg.Surface.Request, - xdg_surface_id, - .{ .ack_configure = .{ - .serial = conf.serial, - } }, - ); - - const new_buffer_id = id_pool.create(); - const new_framebuffer = try pool_alloc.alloc(Pixel, window_size[0] * window_size[1]); - try framebuffers.put(new_buffer_id, new_framebuffer); - - // put some interesting colors into the new_framebuffer - renderGradient(new_framebuffer, window_size); - - const text = try piece_table.writeAllAlloc(); - defer gpa.free(text); - // blit some characters - renderText(new_framebuffer, window_size, .{ 10, 10 }, text); - - try conn.send( - wayland.core.ShmPool.Request, - wl_shm_pool_id, - .{ .create_buffer = .{ - .new_id = new_buffer_id, - .offset = @intCast(@intFromPtr(new_framebuffer.ptr) - @intFromPtr(pool_bytes.ptr)), - .width = @intCast(window_size[0]), - .height = @intCast(window_size[1]), - .stride = @as(i32, @intCast(window_size[0])) * @sizeOf([4]u8), - .format = .argb8888, - } }, - ); - - try conn.send( - wayland.core.Surface.Request, - surface_id, - .{ .attach = .{ - .buffer = new_buffer_id, - .x = 0, - .y = 0, - } }, - ); - - try conn.send( - wayland.core.Surface.Request, - surface_id, - .{ .damage = .{ - .x = 0, - .y = 0, - .width = std.math.maxInt(i32), - .height = std.math.maxInt(i32), - } }, - ); - - // commit the configuration - try conn.send( - wayland.core.Surface.Request, - surface_id, - wayland.core.Surface.Request.commit, - ); - }, - } - } else if (header.object_id == xdg_toplevel_id) { - const event = try wayland.deserialize(wayland.xdg.Toplevel.Event, header, body); - switch (event) { - .configure => |conf| { - std.debug.print("<- xdg_toplevel@{} configure <{}, {}> {any}\n", .{ header.object_id, conf.width, conf.height, conf.states }); - window_size = .{ - @intCast(conf.width), - @intCast(conf.height), - }; - }, - .close => running = false, - else => |tag| std.debug.print("<- xdg_toplevel@{} {s} {}\n", .{ header.object_id, @tagName(tag), event }), - } - } else if (header.object_id == xdg_wm_base_id) { - const event = try wayland.deserialize(wayland.xdg.WmBase.Event, header, body); - switch (event) { - .ping => |ping| { - try conn.send( - wayland.xdg.WmBase.Request, - xdg_wm_base_id, - .{ .pong = .{ - .serial = ping.serial, - } }, - ); - }, - } - } else if (header.object_id == wl_pointer_id) { - const event = try wayland.deserialize(wayland.core.Pointer.Event, header, body); - std.debug.print("<- wl_pointer@{}\n", .{event}); - } else if (header.object_id == wl_keyboard_id) { - const event = try wayland.deserialize(wayland.core.Keyboard.Event, header, body); - switch (event) { - .keymap => |keymap| { - const fd = conn.fd_queue.orderedRemove(0); - std.debug.print("keymap format={}, size={}, fd={}\n", .{ - keymap.format, - keymap.size, - fd, - }); - const mem = try std.os.mmap( - null, - keymap.size, - std.os.PROT.READ, - std.os.MAP.PRIVATE, - fd, - 0, - ); - std.debug.print("---START xkb file---\n{s}\n---END xkb file---\n", .{mem}); - xkb_keymap_opt = xkbcommon.Keymap.newFromString(xkb_ctx, @ptrCast(mem), .text_v1, .no_flags) orelse return error.XKBKeymap; - xkb_state_opt = xkbcommon.State.new(xkb_keymap_opt.?) orelse return error.XKBStateInit; - }, - .modifiers => |mods| { - if (xkb_state_opt) |xkb_state| { - _ = xkb_state.updateMask( - mods.mods_depressed, - mods.mods_latched, - mods.mods_locked, - 0, - 0, - 0, - ); - } - }, - .key => |key| { - if (xkb_state_opt) |xkb_state| { - const keycode: xkbcommon.Keycode = key.key + 8; - const keysym: xkbcommon.Keysym = xkb_state.keyGetOneSym(keycode); - var buf: [64]u8 = undefined; - // const name_len = keysym.getName(&buf, buf.len); - // std.debug.print("{s}\n", .{buf[0..@intCast(name_len)]}); - - if (key.state == .pressed) { - const sym = xkbcommon.Keysym; - switch (@as(u32, @intFromEnum(keysym))) { - sym.BackSpace => { - try piece_table.delete(cursor_pos - 1, 1); - cursor_pos -= 1; - }, - sym.Delete => { - piece_table.delete(cursor_pos, 1) catch |e| switch (e) { - error.OutOfBounds => {}, - else => return e, - }; - }, - sym.Left => { - cursor_pos -|= 1; - }, - sym.Right => { - cursor_pos += 1; - cursor_pos = @min(cursor_pos, piece_table.getTotalSize()); - }, - else => if (key.state == .pressed) { - const size = xkb_state.keyGetUtf8(keycode, &buf); - try piece_table.insert(cursor_pos, buf[0..size]); - cursor_pos += size; - }, - } - - const new_buffer_id, const new_framebuffer = try getFramebuffer(&framebuffers, &id_pool, pool_alloc, window_size); - - // put some interesting colors into the new_framebuffer - renderGradient(new_framebuffer, window_size); - - const text = try piece_table.writeAllAlloc(); - defer gpa.free(text); - // blit some characters - renderText(new_framebuffer, window_size, .{ 10, 10 }, text); - - try conn.send( - wayland.core.ShmPool.Request, - wl_shm_pool_id, - .{ .create_buffer = .{ - .new_id = new_buffer_id, - .offset = @intCast(@intFromPtr(new_framebuffer.ptr) - @intFromPtr(pool_bytes.ptr)), - .width = @intCast(window_size[0]), - .height = @intCast(window_size[1]), - .stride = @as(i32, @intCast(window_size[0])) * @sizeOf([4]u8), - .format = .argb8888, - } }, - ); - - try conn.send( - wayland.core.Surface.Request, - surface_id, - .{ .attach = .{ - .buffer = new_buffer_id, - .x = 0, - .y = 0, - } }, - ); - - try conn.send( - wayland.core.Surface.Request, - surface_id, - .{ .damage = .{ - .x = 0, - .y = 0, - .width = std.math.maxInt(i32), - .height = std.math.maxInt(i32), - } }, - ); - - // commit the configuration - try conn.send( - wayland.core.Surface.Request, - surface_id, - wayland.core.Surface.Request.commit, - ); - } - } - }, - else => { - std.debug.print("<- wl_keyboard@{}\n", .{event}); - }, - } - } else if (header.object_id == zwp_text_input_v3_id) { - const event = try wayland.deserialize(wayland.zwp.TextInputV3.Event, header, body); - std.debug.print("<- zwp_text_input_v3@{} event {}\n", .{ zwp_text_input_v3_id, event }); - switch (event) { - .enter => |e| { - _ = e; - - // if (e.surface == surface_id) { - try conn.send( - wayland.zwp.TextInputV3.Request, - zwp_text_input_v3_id, - .enable, - ); - - try conn.send( - wayland.zwp.TextInputV3.Request, - zwp_text_input_v3_id, - .{ .set_content_type = .{ - .hint = .multiline, - .purpose = .normal, - } }, - ); - - try conn.send( - wayland.zwp.TextInputV3.Request, - zwp_text_input_v3_id, - .commit, - ); - // } - }, - .leave => |e| { - _ = e; - - // if (e.surface == surface_id) { - try conn.send( - wayland.zwp.TextInputV3.Request, - zwp_text_input_v3_id, - .disable, - ); - // } - }, - .preedit_string => {}, - .commit_string => |commit| { - edit_slice = edit_buffer[0..commit.text.len]; - @memcpy(edit_slice.?, commit.text); - }, - .delete_surrounding_text => |offset| { - delete_before = offset.before_length; - delete_after = offset.after_length; - }, - .done => |_| { - // 1 replace existing pre-edit string with cursor - // 2 delete requested surrounding text - const start = cursor_pos - delete_before; - const end = cursor_pos + delete_after; - const length = end - start; - if (length != 0) { - try piece_table.delete(start, length); - } - // 3 insert commit string with cursor at its end - if (edit_slice) |slice| { - try piece_table.insert(cursor_pos, slice); - cursor_pos += slice.len; - edit_slice = null; - } - // 4 calculate surrounding text to send - // 5 insert new preedit text in cursor position - // 6 place cursor inside predit text - }, - } - } else if (framebuffers.get(header.object_id)) |framebuffer_slice| { - const event = try wayland.deserialize(wayland.core.Buffer.Event, header, body); - switch (event) { - .release => { - _ = framebuffers.remove(header.object_id); - pool_alloc.free(framebuffer_slice); - }, - } - } else if (header.object_id == DISPLAY_ID) { - const event = try wayland.deserialize(wayland.core.Display.Event, header, body); - switch (event) { - .@"error" => |err| std.debug.print("<- error({}): {} {s}\n", .{ err.object_id, err.code, err.message }), - .delete_id => |id| id_pool.destroy(id.id), - } - } else { - std.debug.print("{} {x} \"{}\"\n", .{ header.object_id, header.size_and_opcode.opcode, std.zig.fmtEscapes(std.mem.sliceAsBytes(body)) }); - } - } -} - -fn cmsg(comptime T: type) type { - const padding_size = (@sizeOf(T) + @sizeOf(c_long) - 1) & ~(@as(usize, @sizeOf(c_long)) - 1); - return extern struct { - len: c_ulong = @sizeOf(@This()) - padding_size, - level: c_int, - type: c_int, - data: T, - _padding: [padding_size]u8 align(1) = [_]u8{0} ** padding_size, - }; -} - -fn getFramebuffer(framebuffers: *std.AutoHashMap(u32, []Pixel), id_pool: *wayland.IdPool, pool_alloc: std.mem.Allocator, fb_size: [2]u32) !struct { u32, []Pixel } { - const new_buffer_id = id_pool.create(); - const new_framebuffer = try pool_alloc.alloc(Pixel, fb_size[0] * fb_size[1]); - try framebuffers.put(new_buffer_id, new_framebuffer); - return .{ new_buffer_id, new_framebuffer }; -} - -fn renderGradient(framebuffer: []Pixel, fb_size: [2]u32) void { - for (0..fb_size[1]) |y| { - const row = framebuffer[y * fb_size[0] .. (y + 1) * fb_size[0]]; - for (row, 0..fb_size[0]) |*pixel, x| { - pixel.* = .{ - @truncate(x), - @truncate(y), - 0x00, - 0xFF, - }; - } - } -} - -fn textWidth(str: []const u8) usize { - return std.unicode.utf8CountCodepoints(str) catch 0; // incorrect, but I'm going with it -} - -fn renderText(framebuffer: []Pixel, fb_size: [2]u32, pos: [2]usize, str: []const u8) void { - const top, const left = pos; - const bot = @min(top + 8, fb_size[1]); - const right = @min(left + textWidth(str) * 8, fb_size[0]); - - for (top..bot) |y| { - const row = framebuffer[y * fb_size[0] .. (y + 1) * fb_size[0]]; - for (row[left..right], left..right) |*pixel, x| { - const col = ((x - left) / 8); - const which_char = str[col]; - if (!std.ascii.isPrint(which_char)) continue; - const char = font8x8.font8x8_basic[which_char]; - const line = char[(y - top) % 8]; - if ((line >> @intCast((x - left) % 8)) & 0x1 != 0) { - pixel.* = toPixel(Theme.foreground); - } else { - pixel.* = toPixel(Theme.background); - } - } - } -} diff --git a/examples/PieceTable.zig b/examples/PieceTable.zig deleted file mode 100644 index 3ab0b6a..0000000 --- a/examples/PieceTable.zig +++ /dev/null @@ -1,461 +0,0 @@ -const std = @import("std"); -const testing = std.testing; - -/// Represents buffer and a set of changes to the buffer. -/// -/// All insertions are copied internally. Deletions to the buffer will not free memory. -/// -/// To initialize without text, use struct initialization syntax and specify an allocator -/// like so: `var table = PieceTable{ .allocator = allocator };` -pub const PieceTable = struct { - allocator: std.mem.Allocator, - original: []const u8 = &.{}, - buffer: std.ArrayListUnmanaged(u8) = .{}, - pieces: std.ArrayListUnmanaged(Piece) = .{}, - - pub const Piece = struct { - start: usize, - length: usize, - tag: Tag = .added, - pub const Tag = enum { - original, - added, - }; - }; - - pub fn init(allocator: std.mem.Allocator, original: []const u8) !PieceTable { - if (original.len == 0) { - // An empty string was passed, skip making a copy of it - return .{ - .allocator = allocator, - }; - } - - const original_copy = try allocator.dupe(u8, original); - - // Create piece pointing to original text - var pieces = try std.ArrayListUnmanaged(Piece).initCapacity(allocator, 1); - pieces.appendAssumeCapacity(.{ - .start = 0, - .length = original_copy.len, - .tag = .original, - }); - - return .{ - .allocator = allocator, - .original = original_copy, - .buffer = .{}, - .pieces = pieces, - }; - } - - pub fn deinit(table: *PieceTable) void { - table.allocator.free(table.original); - table.buffer.deinit(table.allocator); - table.pieces.deinit(table.allocator); - } - - /// Inserts `new_text` into buffer at `index`. - /// - /// `new_text` is owned by caller. - /// - /// It is an error to insert outside of the bounds of the piece table. If the - /// table is empty, 0 is the only valid argument for index. - pub fn insert(table: *PieceTable, index: usize, text: []const u8) !void { - const start = table.buffer.items.len; - const length = text.len; - try table.buffer.appendSlice(table.allocator, text); - - // Insert at the start of the file, catches empty tables - if (index == 0) { - try table.pieces.insert(table.allocator, 0, .{ .start = start, .length = length, .tag = .added }); - return; - } - - var p_i: usize = 0; - var b_i: usize = 0; - while (p_i < table.pieces.items.len) : (p_i += 1) { - const p = table.pieces.items[p_i]; - if (index == b_i + p.length) { - if (p_i + 1 == table.pieces.items.len) { - // The new index is the end of the file - try table.pieces.append(table.allocator, .{ .start = start, .length = length, .tag = .added }); - return; - } else { - // The new index is directly after an existing node, but not at the end of the file. - try table.pieces.insert(table.allocator, p_i + 1, .{ .start = start, .length = length, .tag = .added }); - return; - } - } else if (index < b_i + p.length) { - // new piece is within another piece; split the old one into 2 - // and insert the new piece between - - // ignore the returned slice since we will also want the - // piece right before the insertion - _ = try table.pieces.addManyAt(table.allocator, p_i + 1, 2); - const pieces = table.pieces.items[p_i..][0..3]; - - const sub_i = index - b_i; - - const start0 = pieces[0].start; - const length_original = pieces[0].length; - const length_rest = length_original - sub_i; - const length_first = length_original - length_rest; - - std.debug.assert(pieces[0].length == length_first + length_rest); - - pieces[0].length = length_first; - pieces[1].start = start; - pieces[1].length = length; - pieces[2].start = start0 + (length_first); - pieces[2].length = length_rest; - - // set the tag for the pieces 1 and 2 - // elide setting the tag for pieces[0], it should be correct already - pieces[1].tag = .added; - switch (p.tag) { - .original => pieces[2].tag = .original, - .added => pieces[2].tag = .added, - } - return; - } else { - b_i += p.length; - } - } - - @panic("Impossible state while inserting into PieceTable"); - } - - /// Deletes the data from start to start+length from the piece table. - /// Will not free any memory. - pub fn delete(table: *PieceTable, start: usize, length: usize) !void { - if (length == 0) return error.InvalidLength; - const endi = start + length; - - var b_i: usize = 0; // buffer index - const p_start, const start_subi, const start_piece = for (table.pieces.items, 0..) |piece, i| { - if (start < b_i + piece.length) { - // start found - break .{ i, start - b_i, piece }; - } - b_i += piece.length; - } else return error.OutOfBounds; - - // reuse b_i - const p_end, const end_subi, const end_piece = for (table.pieces.items[p_start..], p_start..) |piece, i| { - if (endi < b_i + piece.length) { - break .{ i, endi - b_i, piece }; - } - b_i += piece.length; - } else .{ p_start, start_piece.length, start_piece }; - - // Removal cases: - // 1. the deletion starts on one piece boundary and ends on another piece boundary - // - Delete all pieces between start and end - // 2. the deletion starts within a piece and ends on a boundary - // - Delete all but the start piece - // - modify slice end in start piece - // 3. the deletion starts on a bondary and ends within a piece - // - Delete all but the end piece - // - modify slice start in end piece - // 4. the deletion starts within a piece and ends within a piece - // - Delet all the start and end pieces - // - modify slice end in start piece - // - modify slice end in end piece - - const is_start_on_boundary = start_subi == 0; - const is_end_on_boundary = end_subi == end_piece.length; - - const remove_len = (p_end + 1) - p_start; - if (is_start_on_boundary and is_end_on_boundary) { - table.pieces.replaceRange(table.allocator, p_start, remove_len, &.{}) catch unreachable; - } else { - if (is_start_on_boundary) { - const new = &[_]PieceTable.Piece{ - .{ .start = end_piece.start + end_subi, .length = end_piece.length - end_subi, .tag = end_piece.tag }, - }; - table.pieces.replaceRange(table.allocator, p_start, remove_len, new) catch unreachable; - } else if (is_end_on_boundary) { - const new = &[_]PieceTable.Piece{ - .{ .start = start_piece.start, .length = start_piece.length - start_subi, .tag = start_piece.tag }, - }; - table.pieces.replaceRange(table.allocator, p_start, remove_len, new) catch unreachable; - } else { - const new = &[_]PieceTable.Piece{ - .{ .start = start_piece.start, .length = start_subi, .tag = start_piece.tag }, - .{ .start = end_piece.start + end_subi, .length = end_piece.length - end_subi, .tag = end_piece.tag }, - }; - table.pieces.replaceRange(table.allocator, p_start, remove_len, new) catch unreachable; - } - } - } - - pub fn getTotalSize(table: PieceTable) usize { - var length: usize = 0; - for (table.pieces.items) |piece| { - length += piece.length; - } - return length; - } - - fn getPiece(table: PieceTable, piece: Piece) []const u8 { - return switch (piece.tag) { - .original => table.original[piece.start..][0..piece.length], - .added => table.buffer.items[piece.start..][0..piece.length], - }; - } - - pub fn writeAll(table: PieceTable, buffer: []u8) void { - std.debug.assert(table.getTotalSize() == buffer.len); - var current_buffer = buffer[0..]; - for (table.pieces.items) |piece| { - const str = table.getPiece(piece); - @memcpy(current_buffer[0..piece.length], str); - current_buffer = current_buffer[piece.length..]; - } - } - - pub fn writeAllAlloc(table: PieceTable) ![]u8 { - const size = table.getTotalSize(); - const buffer = try table.allocator.alloc(u8, size); - table.writeAll(buffer); - return buffer; - } -}; - -test "Init empty PieceTable" { - var table = try PieceTable.init(testing.allocator, ""); - defer table.deinit(); - - var out_buf: [0]u8 = undefined; - table.writeAll(&out_buf); - - try testing.expectEqualStrings("", &out_buf); -} - -test "Insert into empty PieceTable" { - var table = try PieceTable.init(testing.allocator, ""); - defer table.deinit(); - - try table.insert(0, "the quick brown fox\njumped over the lazy dog"); - - var out_buf: [44]u8 = undefined; - table.writeAll(&out_buf); - - try testing.expectEqualStrings( - \\the quick brown fox - \\jumped over the lazy dog - , &out_buf); -} - -test "Init Piecetable" { - const original = "the quick brown fox\njumped over the lazy dog"; - var table = try PieceTable.init(testing.allocator, original); - defer table.deinit(); - - var out_buf: [44]u8 = undefined; - table.writeAll(&out_buf); - - try testing.expectEqualStrings( - \\the quick brown fox - \\jumped over the lazy dog - , &out_buf); -} - -test "Insert into PieceTable" { - const original = "the quick brown fox\njumped over the lazy dog"; - var table = try PieceTable.init(testing.allocator, original); - defer table.deinit(); - - try table.insert(20, "went to the park and\n"); - - try testing.expectEqual(@as(usize, 3), table.pieces.items.len); - try testing.expectEqual(PieceTable.Piece.Tag.original, table.pieces.items[0].tag); - try testing.expectEqual(PieceTable.Piece.Tag.added, table.pieces.items[1].tag); - try testing.expectEqual(PieceTable.Piece.Tag.original, table.pieces.items[2].tag); - - try testing.expectEqualStrings("the quick brown fox\n", table.getPiece(table.pieces.items[0])); - try testing.expectEqualStrings("went to the park and\n", table.getPiece(table.pieces.items[1])); - try testing.expectEqualStrings("jumped over the lazy dog", table.getPiece(table.pieces.items[2])); - - try testing.expectEqual(@as(usize, 65), table.getTotalSize()); - - var out_buf: [65]u8 = undefined; - table.writeAll(&out_buf); - - try testing.expectEqualStrings( - \\the quick brown fox - \\went to the park and - \\jumped over the lazy dog - , &out_buf); -} - -test "Insert at end of Piece" { - const original = "the quick brown fox\njumped over the lazy dog"; - var table = try PieceTable.init(testing.allocator, original); - defer table.deinit(); - - try table.insert(20, "went to the park and\n"); - try table.insert(41, "ate a burger and\n"); - - try testing.expectEqual(@as(usize, 4), table.pieces.items.len); - try testing.expectEqual(PieceTable.Piece.Tag.original, table.pieces.items[0].tag); - try testing.expectEqual(PieceTable.Piece.Tag.added, table.pieces.items[1].tag); - try testing.expectEqual(PieceTable.Piece.Tag.added, table.pieces.items[2].tag); - try testing.expectEqual(PieceTable.Piece.Tag.original, table.pieces.items[3].tag); - - // try testing.expectEqualStrings("the quick brown fox\n", table.pieces.items[0].slice); - // try testing.expectEqualStrings("went to the park and\n", table.pieces.items[1].slice); - // try testing.expectEqualStrings("ate a burger and\n", table.pieces.items[2].slice); - // try testing.expectEqualStrings("jumped over the lazy dog", table.pieces.items[3].slice); - - try testing.expectEqual(@as(usize, 82), table.getTotalSize()); - - var out_buf: [82]u8 = undefined; - table.writeAll(&out_buf); - - try testing.expectEqualStrings( - \\the quick brown fox - \\went to the park and - \\ate a burger and - \\jumped over the lazy dog - , &out_buf); -} - -test "Insert at end of file" { - const original = "the quick brown fox"; - var table = try PieceTable.init(testing.allocator, original); - defer table.deinit(); - - try table.insert(19, "\njumped over the lazy dog"); - - try testing.expectEqual(@as(usize, 2), table.pieces.items.len); - try testing.expectEqual(PieceTable.Piece.Tag.original, table.pieces.items[0].tag); - try testing.expectEqual(PieceTable.Piece.Tag.added, table.pieces.items[1].tag); - - // try testing.expectEqualStrings("the quick brown fox", table.pieces.items[0].slice); - // try testing.expectEqualStrings("\njumped over the lazy dog", table.pieces.items[1].slice); - - try testing.expectEqual(@as(usize, 44), table.getTotalSize()); - - var out_buf: [44]u8 = undefined; - table.writeAll(&out_buf); - - try testing.expectEqualStrings( - \\the quick brown fox - \\jumped over the lazy dog - , &out_buf); -} - -test "Delete one entire Piece" { - const original = "the quick brown fox"; - var table = try PieceTable.init(testing.allocator, original); - defer table.deinit(); - - try table.delete(0, 19); - try testing.expectEqual(@as(usize, 0), table.pieces.items.len); -} - -test "Delete multiple entire Pieces" { - const original = "the quick brown fox\njumped over the lazy dog"; - var table = try PieceTable.init(testing.allocator, original); - defer table.deinit(); - - try table.insert(20, "went to the park and\n"); - try table.insert(41, "ate a burger and\n"); - try table.delete(20, 38); - - try testing.expectEqual(@as(usize, 2), table.pieces.items.len); -} - -test "Delete inside a Piece" { - const original = "the quick brown fox"; - var table = try PieceTable.init(testing.allocator, original); - defer table.deinit(); - - // delete "brown " - try table.delete(10, 6); - - try testing.expectEqual(@as(usize, 2), table.pieces.items.len); - // try testing.expectEqualStrings("the quick ", table.pieces.items[0].slice); - // try testing.expectEqualStrings("fox", table.pieces.items[1].slice); - - try testing.expectEqual(@as(usize, 13), table.getTotalSize()); - - var out_buf: [13]u8 = undefined; - table.writeAll(&out_buf); - - try testing.expectEqualStrings( - \\the quick fox - , &out_buf); -} - -test "Delete from within one piece to within another piece" { - const original = "the quick brown fox\njumped over the lazy dog"; - var table = try PieceTable.init(testing.allocator, original); - defer table.deinit(); - - try table.insert(20, "went to the park and\n"); - try table.insert(41, "ate a burger and\n"); - try table.delete(45, 13 + 12); - - try testing.expectEqual(@as(usize, 4), table.pieces.items.len); - - try testing.expectEqual(@as(usize, 57), table.getTotalSize()); - - var out_buf: [57]u8 = undefined; - table.writeAll(&out_buf); - - try testing.expectEqualStrings( - \\the quick brown fox - \\went to the park and - \\ate the lazy dog - , &out_buf); -} - -test "Delete from start of piece to within piece" { - const original = "the quick brown fox\njumped over the lazy dog"; - var table = try PieceTable.init(testing.allocator, original); - defer table.deinit(); - - try table.insert(20, "went to the park and\n"); - try table.insert(41, "ate a burger and\n"); - try table.delete(41, 13); - - try testing.expectEqual(@as(usize, 4), table.pieces.items.len); - - try testing.expectEqual(@as(usize, 69), table.getTotalSize()); - - var out_buf: [69]u8 = undefined; - table.writeAll(&out_buf); - - try testing.expectEqualStrings( - \\the quick brown fox - \\went to the park and - \\and - \\jumped over the lazy dog - , &out_buf); -} - -test "Delete from within piece to end of piece" { - const original = "the quick brown fox\njumped over the lazy dog"; - var table = try PieceTable.init(testing.allocator, original); - defer table.deinit(); - - try table.insert(20, "went to the park and\n"); - try table.insert(41, "ate a burger and\n"); - try table.delete(45, 13); - - try testing.expectEqual(@as(usize, 4), table.pieces.items.len); - - try testing.expectEqual(@as(usize, 69), table.getTotalSize()); - - var out_buf: [69]u8 = undefined; - table.writeAll(&out_buf); - - try testing.expectEqualStrings( - \\the quick brown fox - \\went to the park and - \\ate jumped over the lazy dog - , &out_buf); -} diff --git a/src/main.zig b/src/main.zig index 90126bc..9ef8760 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,482 +1,631 @@ const std = @import("std"); -const testing = std.testing; -pub const core = @import("./core.zig"); -pub const xdg = @import("./xdg.zig"); -pub const zxdg = @import("./zxdg.zig"); -pub const zwp = @import("./zwp.zig"); -pub const types = @import("./types.zig"); +const wayland = @import("root.zig"); +const font8x8 = @cImport({ + @cInclude("font8x8.h"); +}); -pub fn getDisplayPath(gpa: std.mem.Allocator) ![]u8 { - const xdg_runtime_dir_path = try std.process.getEnvVarOwned(gpa, "XDG_RUNTIME_DIR"); - defer gpa.free(xdg_runtime_dir_path); - const display_name = std.process.getEnvVarOwned(gpa, "WAYLAND_DISPLAY") catch |err| switch (err) { - error.EnvironmentVariableNotFound => return try std.fs.path.join(gpa, &.{ xdg_runtime_dir_path, "wayland-0" }), - else => return err, - }; - defer gpa.free(display_name); +const Pixel = [4]u8; +const Theme = struct { + const background = 0x282A36; + const current_line = 0x44475A; + const foreground = 0xF8F8F2; + const comment = 0x6272A4; - return try std.fs.path.join(gpa, &.{ xdg_runtime_dir_path, display_name }); -} - -pub const Header = extern struct { - object_id: u32 align(1), - size_and_opcode: SizeAndOpcode align(1), - - pub const SizeAndOpcode = packed struct(u32) { - opcode: u16, - size: u16, - }; + const cyan = 0x8BE9FD; + const green = 0x50FA7B; + const orange = 0xFFB86C; + const pink = 0xFF79C6; + const purple = 0xBD93F9; + const red = 0xFF5555; + const yellow = 0xF1FA8C; }; -test "[]u32 from header" { - try std.testing.expectEqualSlices( - u32, - &[_]u32{ - 1, - (@as(u32, 12) << 16) | (4), - }, - &@as([2]u32, @bitCast(Header{ - .object_id = 1, - .size_and_opcode = .{ - .size = 12, - .opcode = 4, - }, - })), - ); -} - -test "header from []u32" { - try std.testing.expectEqualDeep( - Header{ - .object_id = 1, - .size_and_opcode = .{ - .size = 12, - .opcode = 4, - }, - }, - @as(Header, @bitCast([2]u32{ - 1, - (@as(u32, 12) << 16) | (4), - })), - ); -} - -pub fn readUInt(buffer: []const u32, parent_pos: *usize) !u32 { - var pos = parent_pos.*; - if (pos >= buffer.len) return error.EndOfStream; - - const uint: u32 = @bitCast(buffer[pos]); - pos += 1; - - parent_pos.* = pos; - return uint; -} - -pub fn readInt(buffer: []const u32, parent_pos: *usize) !i32 { - var pos = parent_pos.*; - if (pos >= buffer.len) return error.EndOfStream; - - const int: i32 = @bitCast(buffer[pos]); - pos += 1; - - parent_pos.* = pos; - return int; -} - -pub fn readString(buffer: []const u32, parent_pos: *usize) !?[:0]const u8 { - var pos = parent_pos.*; - - const len = try readUInt(buffer, &pos); - if (len == 0) return null; - const wordlen = std.mem.alignForward(usize, len, @sizeOf(u32)) / @sizeOf(u32); - - if (pos + wordlen > buffer.len) return error.EndOfStream; - const string = std.mem.sliceAsBytes(buffer[pos..])[0 .. len - 1 :0]; - pos += std.mem.alignForward(usize, len, @sizeOf(u32)) / @sizeOf(u32); - - parent_pos.* = pos; - return string; -} - -pub fn readArray(comptime T: type, buffer: []const u32, parent_pos: *usize) ![]const T { - var pos = parent_pos.*; - - const byte_size = try readUInt(buffer, &pos); - - const array = @as([*]const T, @ptrCast(buffer[pos..].ptr))[0 .. byte_size / @sizeOf(T)]; - pos += byte_size / @sizeOf(u32); - - parent_pos.* = pos; - return array; -} - -pub fn deserializeArguments(comptime Signature: type, buffer: []const u32) !Signature { - if (Signature == void) return {}; - var result: Signature = undefined; - var pos: usize = 0; - inline for (std.meta.fields(Signature)) |field| { - if (field.type == types.Fd) continue; - switch (@typeInfo(field.type)) { - .Int => |int_info| switch (int_info.signedness) { - .signed => @field(result, field.name) = try readInt(buffer, &pos), - .unsigned => @field(result, field.name) = try readUInt(buffer, &pos), - }, - .Enum => |enum_info| if (@sizeOf(enum_info.tag_type) == @sizeOf(u32)) { - @field(result, field.name) = @enumFromInt(try readInt(buffer, &pos)); - } else { - @compileError("Unsupported type " ++ @typeName(field.type)); - }, - .Pointer => |ptr| switch (ptr.size) { - .Slice => if (ptr.child == u8) { - @field(result, field.name) = try readString(buffer, &pos) orelse return error.UnexpectedNullString; - } else { - @field(result, field.name) = try readArray(ptr.child, buffer, &pos); - }, - else => @compileError("Unsupported type " ++ @typeName(field.type)), - }, - .Optional => |opt| switch (@typeInfo(opt.child)) { - .Pointer => |ptr| switch (ptr.size) { - .Slice => if (ptr.child == u8) { - @field(result, field.name) = try readString(buffer, &pos); - } else @compileError("Unsupported type " ++ @typeName(field.type)), - else => @compileError("Unsupported type " ++ @typeName(field.type)), - }, - else => @compileError("Unsupported type " ++ @typeName(field.type)), - }, - else => @compileError("Unsupported type " ++ @typeName(field.type)), - } - } - return result; -} - -pub fn deserialize(comptime Union: type, header: Header, buffer: []const u32) !Union { - const op = try std.meta.intToEnum(std.meta.Tag(Union), header.size_and_opcode.opcode); - switch (op) { - inline else => |f| { - const Payload = std.meta.TagPayload(Union, f); - const payload = try deserializeArguments(Payload, buffer); - return @unionInit(Union, @tagName(f), payload); - }, - } -} - -/// Returns the length of the serialized message in `u32` words. -pub fn calculateSerializedWordLen(comptime Signature: type, message: Signature) usize { - var pos: usize = 0; - inline for (std.meta.fields(Signature)) |field| { - switch (@typeInfo(field.type)) { - .Int => pos += 1, - .Pointer => |ptr| switch (ptr.size) { - .Slice => { - // for size of string in bytes - pos += 1; - - const str = @field(message, field.name); - pos += std.mem.alignForward(usize, str.len + 1, @sizeOf(u32)) / @sizeOf(u32); - }, - else => @compileError("Unsupported type " ++ @typeName(field.type)), - }, - else => @compileError("Unsupported type " ++ @typeName(field.type)), - } - } - return pos; -} - -pub fn countFds(comptime Signature: type) usize { - if (Signature == void) return 0; - var count: usize = 0; - inline for (std.meta.fields(Signature)) |field| { - if (field.type == types.Fd) { - count += 1; - } - } - return count; -} - -pub fn extractFds(comptime Signature: type, message: *const Signature) [countFds(Signature)]*const types.Fd { - if (Signature == void) return [_]*const types.Fd{}; - var fds: [countFds(Signature)]*const types.Fd = undefined; - var i: usize = 0; - inline for (std.meta.fields(Signature)) |field| { - if (field.type == types.Fd) { - fds[i] = &@field(message, field.name); - i += 1; - } - } - return fds; -} - -/// Message must live until the iovec array is written. -pub fn serializeArguments(comptime Signature: type, buffer: []u32, message: Signature) ![]u32 { - if (Signature == void) return buffer[0..0]; - var pos: usize = 0; - inline for (std.meta.fields(Signature)) |field| { - if (field.type == types.Fd) continue; - switch (@typeInfo(field.type)) { - .Int => { - if (pos >= buffer.len) return error.OutOfMemory; - buffer[pos] = @bitCast(@field(message, field.name)); - pos += 1; - }, - .Enum => |enum_info| if (enum_info.tag_type == u32) { - if (pos >= buffer.len) return error.OutOfMemory; - buffer[pos] = @intFromEnum(@field(message, field.name)); - pos += 1; - } else { - @compileError("Unsupported type " ++ @typeName(field.type)); - }, - .Pointer => |ptr| switch (ptr.size) { - .Slice => { - const str = @field(message, field.name); - if (str.len >= std.math.maxInt(u32)) return error.StringTooLong; - - buffer[pos] = @intCast(str.len + 1); - pos += 1; - - const str_len_aligned = std.mem.alignForward(usize, str.len + 1, @sizeOf(u32)); - const padding_len = str_len_aligned - str.len; - if (str_len_aligned / @sizeOf(u32) >= buffer[pos..].len) return error.OutOfMemory; - const buffer_bytes = std.mem.sliceAsBytes(buffer[pos..]); - @memcpy(buffer_bytes[0..str.len], str); - @memset(buffer_bytes[str.len..][0..padding_len], 0); - pos += str_len_aligned / @sizeOf(u32); - }, - else => @compileError("Unsupported type " ++ @typeName(field.type)), - }, - .Optional => |opt| switch (@typeInfo(opt.child)) { - .Pointer => |ptr| switch (ptr.size) { - .Slice => if (ptr.child == u8) { - const str = @field(message, field.name); - if (str.len >= std.math.maxInt(u32)) return error.StringTooLong; - - buffer[pos] = @intCast(str.len + 1); - pos += 1; - - const str_len_aligned = std.mem.alignForward(usize, str.len + 1, @sizeOf(u32)); - const padding_len = str_len_aligned - str.len; - if (str_len_aligned / @sizeOf(u32) >= buffer[pos..].len) return error.OutOfMemory; - const buffer_bytes = std.mem.sliceAsBytes(buffer[pos..]); - @memcpy(buffer_bytes[0..str.len], str); - @memset(buffer_bytes[str.len..][0..padding_len], 0); - pos += str_len_aligned / @sizeOf(u32); - } else @compileError("Unsupported type " ++ @typeName(field.type)), - else => @compileError("Unsupported type " ++ @typeName(field.type)), - }, - else => @compileError("Unsupported type " ++ @typeName(field.type)), - }, - else => @compileError("Unsupported type " ++ @typeName(field.type)), - } - } - return buffer[0..pos]; -} - -pub fn serialize(comptime Union: type, buffer: []u32, object_id: u32, message: Union) ![]u32 { - const header_wordlen = @sizeOf(Header) / @sizeOf(u32); - const header: *Header = @ptrCast(buffer[0..header_wordlen]); - header.object_id = object_id; - - const tag = std.meta.activeTag(message); - header.size_and_opcode.opcode = @intFromEnum(tag); - - const arguments = switch (message) { - inline else => |payload| try serializeArguments(@TypeOf(payload), buffer[header_wordlen..], payload), +fn toPixel(color: u24) Pixel { + return .{ + @intCast(color & 0xFF), + @intCast(color >> 8 & 0xFF), + @intCast(color >> 16 & 0xFF), + 0xFF, }; - - header.size_and_opcode.size = @intCast(@sizeOf(Header) + arguments.len * @sizeOf(u32)); - return buffer[0 .. header.size_and_opcode.size / @sizeOf(u32)]; } -test "deserialize Registry.Event.Global" { - const words = [_]u32{ - 1, - 7, - @bitCast(@as([4]u8, "wl_s".*)), - @bitCast(@as([4]u8, "hm\x00\x00".*)), - 3, - }; - const parsed = try deserializeArguments(core.Registry.Event.Global, &words); - try std.testing.expectEqualDeep(core.Registry.Event.Global{ - .name = 1, - .interface = "wl_shm", - .version = 3, - }, parsed); -} +pub fn main() !void { + var general_allocator = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = general_allocator.deinit(); + const gpa = general_allocator.allocator(); -test "deserialize Registry.Event" { - const header = Header{ - .object_id = 123, - .size_and_opcode = .{ - .size = 28, - .opcode = @intFromEnum(core.Registry.Event.Tag.global), - }, - }; - const words = [_]u32{ - 1, - 7, - @bitCast(@as([4]u8, "wl_s".*)), - @bitCast(@as([4]u8, "hm\x00\x00".*)), - 3, - }; - const parsed = try deserialize(core.Registry.Event, header, &words); - try std.testing.expectEqualDeep( - core.Registry.Event{ - .global = .{ - .name = 1, - .interface = "wl_shm", - .version = 3, - }, - }, - parsed, + const display_path = try wayland.getDisplayPath(gpa); + defer gpa.free(display_path); + + var conn = try wayland.Conn.init(gpa, display_path); + defer conn.deinit(); + + // Create an id pool to allocate ids for us + var id_pool = wayland.IdPool{}; + + const ids = try wayland.registerGlobals(gpa, &id_pool, conn.socket, &.{ + wayland.core.Shm, + wayland.core.Compositor, + wayland.xdg.WmBase, + wayland.core.Seat, + wayland.zxdg.DecorationManagerV1, + wayland.zwp.TextInputManagerV3, + }); + + const DISPLAY_ID = 1; + const shm_id = ids[0] orelse return error.NeccessaryWaylandExtensionMissing; + const compositor_id = ids[1] orelse return error.NeccessaryWaylandExtensionMissing; + const xdg_wm_base_id = ids[2] orelse return error.NeccessaryWaylandExtensionMissing; + const wl_seat_id = ids[3] orelse return error.NeccessaryWaylandExtensionMissing; + const zwp_text_input_manager_v3 = ids[5] orelse return error.NeccessaryWaylandExtensionMissing; + + const surface_id = id_pool.create(); + try conn.send( + wayland.core.Compositor.Request, + compositor_id, + .{ .create_surface = .{ + .new_id = surface_id, + } }, ); - const header2 = Header{ - .object_id = 1, - .size_and_opcode = .{ - .size = 14 * @sizeOf(u32), - .opcode = @intFromEnum(core.Display.Event.Tag.@"error"), - }, - }; - const words2 = [_]u32{ - 1, - 15, - 40, - @bitCast(@as([4]u8, "inva".*)), - @bitCast(@as([4]u8, "lid ".*)), - @bitCast(@as([4]u8, "argu".*)), - @bitCast(@as([4]u8, "ment".*)), - @bitCast(@as([4]u8, "s to".*)), - @bitCast(@as([4]u8, " wl_".*)), - @bitCast(@as([4]u8, "regi".*)), - @bitCast(@as([4]u8, "stry".*)), - @bitCast(@as([4]u8, "@2.b".*)), - @bitCast(@as([4]u8, "ind\x00".*)), - }; - const parsed2 = try deserialize(core.Display.Event, header2, &words2); - try std.testing.expectEqualDeep( - core.Display.Event{ - .@"error" = .{ - .object_id = 1, - .code = 15, - .message = "invalid arguments to wl_registry@2.bind", - }, - }, - parsed2, + const xdg_surface_id = id_pool.create(); + try conn.send( + wayland.xdg.WmBase.Request, + xdg_wm_base_id, + .{ .get_xdg_surface = .{ + .id = xdg_surface_id, + .surface = surface_id, + } }, ); -} -test "serialize Registry.Event.Global" { - const message = core.Registry.Event.Global{ - .name = 1, - .interface = "wl_shm", - .version = 3, - }; - var buffer: [5]u32 = undefined; - const serialized = try serializeArguments(core.Registry.Event.Global, &buffer, message); - - try std.testing.expectEqualSlices( - u32, - &[_]u32{ - 1, - 7, - @bitCast(@as([4]u8, "wl_s".*)), - @bitCast(@as([4]u8, "hm\x00\x00".*)), - 3, - }, - serialized, + const xdg_toplevel_id = id_pool.create(); + try conn.send( + wayland.xdg.Surface.Request, + xdg_surface_id, + .{ .get_toplevel = .{ + .id = xdg_toplevel_id, + } }, ); -} -pub const IdPool = struct { - next_id: u32 = 2, - free_ids: std.BoundedArray(u32, 1024) = .{}, + const zwp_text_input_v3_id = id_pool.create(); + try conn.send( + wayland.zwp.TextInputManagerV3.Request, + zwp_text_input_manager_v3, + .{ .get_text_input = .{ + .id = zwp_text_input_v3_id, + .seat = wl_seat_id, + } }, + ); - pub fn create(this: *@This()) u32 { - if (this.free_ids.popOrNull()) |id| { - return id; - } - - defer this.next_id += 1; - return this.next_id; + var zxdg_toplevel_decoration_id_opt: ?u32 = null; + if (ids[4]) |zxdg_decoration_manager_id| { + zxdg_toplevel_decoration_id_opt = id_pool.create(); + try conn.send( + wayland.zxdg.DecorationManagerV1.Request, + zxdg_decoration_manager_id, + .{ .get_toplevel_decoration = .{ + .new_id = zxdg_toplevel_decoration_id_opt.?, + .toplevel = xdg_toplevel_id, + } }, + ); } - pub fn destroy(this: *@This(), id: u32) void { - for (this.free_ids.slice()) |existing_id| { - if (existing_id == id) return; - } - this.free_ids.append(id) catch {}; - } -}; - -pub fn registerGlobals(alloc: std.mem.Allocator, id_pool: *IdPool, socket: std.net.Stream, comptime T: []const type) ![T.len]?u32 { - const Item = struct { version: u32, index: u32 }; - const Pair = struct { []const u8, Item }; - comptime var kvs_list: []const Pair = &[_]Pair{}; - inline for (T, 0..) |t, i| { - kvs_list = kvs_list ++ &[_]Pair{.{ t.INTERFACE, .{ .version = t.VERSION, .index = i } }}; - } - const map = std.ComptimeStringMap(Item, kvs_list); - - const registry_id = id_pool.create(); - { - var buffer: [5]u32 = undefined; - const message = try serialize(core.Display.Request, &buffer, 1, .{ .get_registry = .{ .registry = registry_id } }); - try socket.writeAll(std.mem.sliceAsBytes(message)); - } + try conn.send( + wayland.core.Surface.Request, + surface_id, + wayland.core.Surface.Request.commit, + ); const registry_done_id = id_pool.create(); - { - var buffer: [5]u32 = undefined; - const message = try serialize(core.Display.Request, &buffer, 1, .{ .sync = .{ .callback = registry_done_id } }); - try socket.writeAll(std.mem.sliceAsBytes(message)); - } + try conn.send( + wayland.core.Display.Request, + DISPLAY_ID, + .{ .sync = .{ .callback = registry_done_id } }, + ); - var ids: [T.len]?u32 = [_]?u32{null} ** T.len; - var message_buffer = std.ArrayList(u32).init(alloc); - defer message_buffer.deinit(); - while (true) { - var header: Header = undefined; - const header_bytes_read = try socket.readAll(std.mem.asBytes(&header)); - if (header_bytes_read < @sizeOf(Header)) break; + var done = false; + var surface_configured = false; + var seat_capabilties: ?wayland.core.Seat.Capability = null; + while (!done or !surface_configured) { + const header, const body = try conn.recv(); - try message_buffer.resize((header.size_and_opcode.size - @sizeOf(Header)) / @sizeOf(u32)); - const bytes_read = try socket.readAll(std.mem.sliceAsBytes(message_buffer.items)); - message_buffer.shrinkRetainingCapacity(bytes_read / @sizeOf(u32)); - - if (header.object_id == registry_id) { - const event = try deserialize(core.Registry.Event, header, message_buffer.items); + if (header.object_id == xdg_surface_id) { + const event = try wayland.deserialize(wayland.xdg.Surface.Event, header, body); switch (event) { - .global => |global| { - var buffer: [20]u32 = undefined; - if (map.get(global.interface)) |item| { - if (global.version < item.version) { - // TODO: Add diagnostics API - return error.OutdatedCompositorProtocol; - } - const new_id = id_pool.create(); - ids[item.index] = new_id; - const message = try serialize(core.Registry.Request, &buffer, registry_id, .{ .bind = .{ - .name = global.name, - .interface = global.interface, - .version = item.version, - .new_id = new_id, - } }); - try socket.writeAll(std.mem.sliceAsBytes(message)); - } + .configure => |conf| { + try conn.send( + wayland.xdg.Surface.Request, + xdg_surface_id, + .{ .ack_configure = .{ + .serial = conf.serial, + } }, + ); + surface_configured = true; }, - .global_remove => {}, } + } else if (zxdg_toplevel_decoration_id_opt != null and header.object_id == zxdg_toplevel_decoration_id_opt.?) { + const event = try wayland.deserialize(wayland.zxdg.ToplevelDecorationV1.Event, header, body); + std.debug.print("<- zxdg_toplevel_decoration@{}\n", .{event}); + } else if (header.object_id == xdg_toplevel_id) { + const event = try wayland.deserialize(wayland.xdg.Toplevel.Event, header, body); + std.debug.print("<- {}\n", .{event}); } else if (header.object_id == registry_done_id) { - break; + done = true; + } else if (header.object_id == shm_id) { + const event = try wayland.deserialize(wayland.core.Shm.Event, header, body); + switch (event) { + .format => |format| std.debug.print("<- format {} {}\n", .{ format.format, std.zig.fmtEscapes(std.mem.asBytes(&format.format)) }), + } + } else if (header.object_id == wl_seat_id) { + const event = try wayland.deserialize(wayland.core.Seat.Event, header, body); + switch (event) { + .capabilities => |capabilities| { + const cap: wayland.core.Seat.Capability = @bitCast(capabilities.capability); + std.debug.print("<- wl_seat.capabilties = {}\n", .{cap}); + seat_capabilties = cap; + }, + .name => |name| { + std.debug.print("<- wl_seat.name = {s}\n", .{name.name}); + }, + } + } else if (header.object_id == DISPLAY_ID) { + const event = try wayland.deserialize(wayland.core.Display.Event, header, body); + switch (event) { + .@"error" => |err| std.debug.print("<- error({}): {} {s}\n", .{ err.object_id, err.code, err.message }), + .delete_id => |id| { + std.debug.print("id {} deleted\n", .{id}); + id_pool.destroy(id.id); + }, + } } else { - std.log.info("{} {x} \"{}\"", .{ - header.object_id, - header.size_and_opcode.opcode, - std.zig.fmtEscapes(std.mem.sliceAsBytes(message_buffer.items)), - }); + std.debug.print("{} {x} \"{}\"\n", .{ header.object_id, header.size_and_opcode.opcode, std.zig.fmtEscapes(std.mem.sliceAsBytes(body)) }); } } - return ids; + var wl_pointer_id_opt: ?u32 = null; + var wl_keyboard_id_opt: ?u32 = null; + if (seat_capabilties) |caps| { + if (caps.pointer) { + wl_pointer_id_opt = id_pool.create(); + std.debug.print("wl pointer id: {}\n", .{wl_pointer_id_opt.?}); + try conn.send( + wayland.core.Seat.Request, + wl_seat_id, + .{ .get_pointer = .{ + .new_id = wl_pointer_id_opt.?, + } }, + ); + } + if (caps.keyboard) { + wl_keyboard_id_opt = id_pool.create(); + std.debug.print("wl keyboard id: {}\n", .{wl_keyboard_id_opt.?}); + try conn.send( + wayland.core.Seat.Request, + wl_seat_id, + .{ .get_keyboard = .{ + .new_id = wl_keyboard_id_opt.?, + } }, + ); + } + } + const wl_pointer_id = wl_pointer_id_opt orelse return error.MissingPointer; + const wl_keyboard_id = wl_keyboard_id_opt orelse return error.MissingKeyboard; + + // allocate a shared memory file for display purposes + const framebuffer_size = [2]u32{ 128, 128 }; + const pool_file_len = 1024 * framebuffer_size[0] * framebuffer_size[1] * @sizeOf(Pixel); + + const pool_fd = try std.os.memfd_create("my-wayland-framebuffer", 0); + try std.os.ftruncate(pool_fd, pool_file_len); + const pool_bytes = try std.os.mmap(null, pool_file_len, std.os.PROT.READ | std.os.PROT.WRITE, std.os.MAP.SHARED, pool_fd, 0); + var pool_fixed_buffer_allocator = std.heap.FixedBufferAllocator.init(pool_bytes); + var pool_general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){ .backing_allocator = pool_fixed_buffer_allocator.allocator() }; + const pool_alloc = pool_general_purpose_allocator.allocator(); + + const framebuffer = try pool_alloc.alloc(Pixel, framebuffer_size[0] * framebuffer_size[1]); + + // put some interesting colors into the framebuffer + renderGradient(framebuffer, framebuffer_size); + + const wl_shm_pool_id = id_pool.create(); + { + std.debug.print("framebuffer_fd: {}\n", .{pool_fd}); + try conn.send( + wayland.core.Shm.Request, + shm_id, + .{ .create_pool = .{ + .new_id = wl_shm_pool_id, + .fd = @enumFromInt(pool_fd), + .size = pool_file_len, + } }, + ); + } + + var framebuffers = std.AutoHashMap(u32, []Pixel).init(gpa); + defer framebuffers.deinit(); + try framebuffers.put(wl_shm_pool_id, framebuffer); + + const wl_buffer_id = id_pool.create(); + try conn.send( + wayland.core.ShmPool.Request, + wl_shm_pool_id, + .{ .create_buffer = .{ + .new_id = wl_buffer_id, + .offset = 0, + .width = framebuffer_size[0], + .height = framebuffer_size[1], + .stride = framebuffer_size[0] * @sizeOf([4]u8), + .format = .argb8888, + } }, + ); + + try conn.send( + wayland.core.Surface.Request, + surface_id, + .{ .attach = .{ + .buffer = wl_buffer_id, + .x = 0, + .y = 0, + } }, + ); + + try conn.send( + wayland.core.Surface.Request, + surface_id, + .{ .damage = .{ + .x = 0, + .y = 0, + .width = std.math.maxInt(i32), + .height = std.math.maxInt(i32), + } }, + ); + + try conn.send( + wayland.core.Surface.Request, + surface_id, + wayland.core.Surface.Request.commit, + ); + + var window_size: [2]u32 = [2]u32{ @intCast(framebuffer_size[0]), @intCast(framebuffer_size[1]) }; + const xkb_ctx = xkbcommon.Context.new(.no_flags) orelse return error.XKBInit; + defer xkb_ctx.unref(); + + var xkb_keymap_opt: ?*xkbcommon.Keymap = null; + defer if (xkb_keymap_opt) |xkb_keymap| { + xkb_keymap.unref(); + }; + var xkb_state_opt: ?*xkbcommon.State = null; + defer if (xkb_state_opt) |xkb_state| { + xkb_state.unref(); + }; + + var piece_table = try PieceTable.init(gpa, "Hello, World!"); + defer piece_table.deinit(); + + var edit_buffer: [1024]u8 = [1]u8{0} ** 1024; + var edit_slice: ?[]u8 = null; + + var delete_before: usize = 0; + var delete_after: usize = 0; + + // var preedit_buffer: [1024]u8 = [1]u8{0} ** 1024; + // var preedit_slice: ?[]u8 = null; + + var cursor_pos: usize = piece_table.getTotalSize(); + + var running = true; + while (running) { + const header, const body = try conn.recv(); + + if (header.object_id == xdg_surface_id) { + const event = try wayland.deserialize(wayland.xdg.Surface.Event, header, body); + switch (event) { + .configure => |conf| { + try conn.send( + wayland.xdg.Surface.Request, + xdg_surface_id, + .{ .ack_configure = .{ + .serial = conf.serial, + } }, + ); + + const new_buffer_id = id_pool.create(); + const new_framebuffer = try pool_alloc.alloc(Pixel, window_size[0] * window_size[1]); + try framebuffers.put(new_buffer_id, new_framebuffer); + + // put some interesting colors into the new_framebuffer + renderGradient(new_framebuffer, window_size); + + const text = try piece_table.writeAllAlloc(); + defer gpa.free(text); + // blit some characters + renderText(new_framebuffer, window_size, .{ 10, 10 }, text); + + try conn.send( + wayland.core.ShmPool.Request, + wl_shm_pool_id, + .{ .create_buffer = .{ + .new_id = new_buffer_id, + .offset = @intCast(@intFromPtr(new_framebuffer.ptr) - @intFromPtr(pool_bytes.ptr)), + .width = @intCast(window_size[0]), + .height = @intCast(window_size[1]), + .stride = @as(i32, @intCast(window_size[0])) * @sizeOf([4]u8), + .format = .argb8888, + } }, + ); + + try conn.send( + wayland.core.Surface.Request, + surface_id, + .{ .attach = .{ + .buffer = new_buffer_id, + .x = 0, + .y = 0, + } }, + ); + + try conn.send( + wayland.core.Surface.Request, + surface_id, + .{ .damage = .{ + .x = 0, + .y = 0, + .width = std.math.maxInt(i32), + .height = std.math.maxInt(i32), + } }, + ); + + // commit the configuration + try conn.send( + wayland.core.Surface.Request, + surface_id, + wayland.core.Surface.Request.commit, + ); + }, + } + } else if (header.object_id == xdg_toplevel_id) { + const event = try wayland.deserialize(wayland.xdg.Toplevel.Event, header, body); + switch (event) { + .configure => |conf| { + std.debug.print("<- xdg_toplevel@{} configure <{}, {}> {any}\n", .{ header.object_id, conf.width, conf.height, conf.states }); + window_size = .{ + @intCast(conf.width), + @intCast(conf.height), + }; + }, + .close => running = false, + else => |tag| std.debug.print("<- xdg_toplevel@{} {s} {}\n", .{ header.object_id, @tagName(tag), event }), + } + } else if (header.object_id == xdg_wm_base_id) { + const event = try wayland.deserialize(wayland.xdg.WmBase.Event, header, body); + switch (event) { + .ping => |ping| { + try conn.send( + wayland.xdg.WmBase.Request, + xdg_wm_base_id, + .{ .pong = .{ + .serial = ping.serial, + } }, + ); + }, + } + } else if (header.object_id == wl_pointer_id) { + const event = try wayland.deserialize(wayland.core.Pointer.Event, header, body); + std.debug.print("<- wl_pointer@{}\n", .{event}); + } else if (header.object_id == wl_keyboard_id) { + const event = try wayland.deserialize(wayland.core.Keyboard.Event, header, body); + switch (event) { + .keymap => |keymap| { + const fd = conn.fd_queue.orderedRemove(0); + std.debug.print("keymap format={}, size={}, fd={}\n", .{ + keymap.format, + keymap.size, + fd, + }); + const mem = try std.os.mmap( + null, + keymap.size, + std.os.PROT.READ, + std.os.MAP.PRIVATE, + fd, + 0, + ); + std.debug.print("---START xkb file---\n{s}\n---END xkb file---\n", .{mem}); + xkb_keymap_opt = xkbcommon.Keymap.newFromString(xkb_ctx, @ptrCast(mem), .text_v1, .no_flags) orelse return error.XKBKeymap; + xkb_state_opt = xkbcommon.State.new(xkb_keymap_opt.?) orelse return error.XKBStateInit; + }, + .modifiers => |mods| { + if (xkb_state_opt) |xkb_state| { + _ = xkb_state.updateMask( + mods.mods_depressed, + mods.mods_latched, + mods.mods_locked, + 0, + 0, + 0, + ); + } + }, + .key => |key| { + if (xkb_state_opt) |xkb_state| { + const keycode: xkbcommon.Keycode = key.key + 8; + const keysym: xkbcommon.Keysym = xkb_state.keyGetOneSym(keycode); + var buf: [64]u8 = undefined; + // const name_len = keysym.getName(&buf, buf.len); + // std.debug.print("{s}\n", .{buf[0..@intCast(name_len)]}); + + if (key.state == .pressed) { + const sym = xkbcommon.Keysym; + switch (@as(u32, @intFromEnum(keysym))) { + sym.BackSpace => { + try piece_table.delete(cursor_pos - 1, 1); + cursor_pos -= 1; + }, + sym.Delete => { + piece_table.delete(cursor_pos, 1) catch |e| switch (e) { + error.OutOfBounds => {}, + else => return e, + }; + }, + sym.Left => { + cursor_pos -|= 1; + }, + sym.Right => { + cursor_pos += 1; + cursor_pos = @min(cursor_pos, piece_table.getTotalSize()); + }, + else => if (key.state == .pressed) { + const size = xkb_state.keyGetUtf8(keycode, &buf); + try piece_table.insert(cursor_pos, buf[0..size]); + cursor_pos += size; + }, + } + + const new_buffer_id, const new_framebuffer = try getFramebuffer(&framebuffers, &id_pool, pool_alloc, window_size); + + // put some interesting colors into the new_framebuffer + renderGradient(new_framebuffer, window_size); + + const text = try piece_table.writeAllAlloc(); + defer gpa.free(text); + // blit some characters + renderText(new_framebuffer, window_size, .{ 10, 10 }, text); + + try conn.send( + wayland.core.ShmPool.Request, + wl_shm_pool_id, + .{ .create_buffer = .{ + .new_id = new_buffer_id, + .offset = @intCast(@intFromPtr(new_framebuffer.ptr) - @intFromPtr(pool_bytes.ptr)), + .width = @intCast(window_size[0]), + .height = @intCast(window_size[1]), + .stride = @as(i32, @intCast(window_size[0])) * @sizeOf([4]u8), + .format = .argb8888, + } }, + ); + + try conn.send( + wayland.core.Surface.Request, + surface_id, + .{ .attach = .{ + .buffer = new_buffer_id, + .x = 0, + .y = 0, + } }, + ); + + try conn.send( + wayland.core.Surface.Request, + surface_id, + .{ .damage = .{ + .x = 0, + .y = 0, + .width = std.math.maxInt(i32), + .height = std.math.maxInt(i32), + } }, + ); + + // commit the configuration + try conn.send( + wayland.core.Surface.Request, + surface_id, + wayland.core.Surface.Request.commit, + ); + } + } + }, + else => { + std.debug.print("<- wl_keyboard@{}\n", .{event}); + }, + } + } else if (header.object_id == zwp_text_input_v3_id) { + const event = try wayland.deserialize(wayland.zwp.TextInputV3.Event, header, body); + std.debug.print("<- zwp_text_input_v3@{} event {}\n", .{ zwp_text_input_v3_id, event }); + switch (event) { + .enter => |e| { + _ = e; + + // if (e.surface == surface_id) { + try conn.send( + wayland.zwp.TextInputV3.Request, + zwp_text_input_v3_id, + .enable, + ); + + try conn.send( + wayland.zwp.TextInputV3.Request, + zwp_text_input_v3_id, + .{ .set_content_type = .{ + .hint = .multiline, + .purpose = .normal, + } }, + ); + + try conn.send( + wayland.zwp.TextInputV3.Request, + zwp_text_input_v3_id, + .commit, + ); + // } + }, + .leave => |e| { + _ = e; + + // if (e.surface == surface_id) { + try conn.send( + wayland.zwp.TextInputV3.Request, + zwp_text_input_v3_id, + .disable, + ); + // } + }, + .preedit_string => {}, + .commit_string => |commit| { + edit_slice = edit_buffer[0..commit.text.len]; + @memcpy(edit_slice.?, commit.text); + }, + .delete_surrounding_text => |offset| { + delete_before = offset.before_length; + delete_after = offset.after_length; + }, + .done => |_| { + // 1 replace existing pre-edit string with cursor + // 2 delete requested surrounding text + const start = cursor_pos - delete_before; + const end = cursor_pos + delete_after; + const length = end - start; + if (length != 0) { + try piece_table.delete(start, length); + } + // 3 insert commit string with cursor at its end + if (edit_slice) |slice| { + try piece_table.insert(cursor_pos, slice); + cursor_pos += slice.len; + edit_slice = null; + } + // 4 calculate surrounding text to send + // 5 insert new preedit text in cursor position + // 6 place cursor inside predit text + }, + } + } else if (framebuffers.get(header.object_id)) |framebuffer_slice| { + const event = try wayland.deserialize(wayland.core.Buffer.Event, header, body); + switch (event) { + .release => { + _ = framebuffers.remove(header.object_id); + pool_alloc.free(framebuffer_slice); + }, + } + } else if (header.object_id == DISPLAY_ID) { + const event = try wayland.deserialize(wayland.core.Display.Event, header, body); + switch (event) { + .@"error" => |err| std.debug.print("<- error({}): {} {s}\n", .{ err.object_id, err.code, err.message }), + .delete_id => |id| id_pool.destroy(id.id), + } + } else { + std.debug.print("{} {x} \"{}\"\n", .{ header.object_id, header.size_and_opcode.opcode, std.zig.fmtEscapes(std.mem.sliceAsBytes(body)) }); + } + } } fn cmsg(comptime T: type) type { @@ -490,157 +639,49 @@ fn cmsg(comptime T: type) type { }; } -pub const Conn = struct { - allocator: std.mem.Allocator, - send_buffer: []u32, - recv_buffer: []u32, - fd_queue: std.ArrayListUnmanaged(std.os.fd_t), - socket: std.net.Stream, +fn getFramebuffer(framebuffers: *std.AutoHashMap(u32, []Pixel), id_pool: *wayland.IdPool, pool_alloc: std.mem.Allocator, fb_size: [2]u32) !struct { u32, []Pixel } { + const new_buffer_id = id_pool.create(); + const new_framebuffer = try pool_alloc.alloc(Pixel, fb_size[0] * fb_size[1]); + try framebuffers.put(new_buffer_id, new_framebuffer); + return .{ new_buffer_id, new_framebuffer }; +} - pub fn init(alloc: std.mem.Allocator, display_path: []const u8) !Conn { - const send_buffer = try alloc.alloc(u32, 16); - const recv_buffer = try alloc.alloc(u32, 16); - return .{ - .allocator = alloc, - .send_buffer = send_buffer, - .recv_buffer = recv_buffer, - .fd_queue = .{}, - .socket = try std.net.connectUnixSocket(display_path), - }; - } - - pub fn deinit(conn: *Conn) void { - conn.allocator.free(conn.send_buffer); - conn.allocator.free(conn.recv_buffer); - conn.fd_queue.deinit(conn.allocator); - conn.socket.close(); - } - - pub fn send(conn: *Conn, comptime Signature: type, id: u32, message: Signature) !void { - const msg = while (true) { - const msg = serialize( - Signature, - conn.send_buffer, - id, - message, - ) catch |e| switch (e) { - error.OutOfMemory => { - conn.send_buffer = try conn.allocator.realloc(conn.send_buffer, conn.send_buffer.len * 2); - continue; - }, - else => return e, - }; - - break msg; - }; - const msg_bytes = std.mem.sliceAsBytes(msg); - const msg_iov = [_]std.os.iovec_const{ - .{ - .iov_base = msg_bytes.ptr, - .iov_len = msg_bytes.len, - }, - }; - const fds = switch (message) { - inline else => |*payload| extractFds(@TypeOf(payload.*), payload), - }; - var ctrl_msgs: [fds.len]cmsg(std.os.fd_t) = undefined; - for (fds, 0..) |fdp, i| { - std.debug.print("fd {}: {}\n", .{ i, fdp.* }); - ctrl_msgs[i] = .{ - .level = std.os.SOL.SOCKET, - .type = 0x01, - .data = @intFromEnum(fdp.*), +fn renderGradient(framebuffer: []Pixel, fb_size: [2]u32) void { + for (0..fb_size[1]) |y| { + const row = framebuffer[y * fb_size[0] .. (y + 1) * fb_size[0]]; + for (row, 0..fb_size[0]) |*pixel, x| { + pixel.* = .{ + @truncate(x), + @truncate(y), + 0x00, + 0xFF, }; } - const socket_msg = std.os.msghdr_const{ - .name = null, - .namelen = 0, - .iov = &msg_iov, - .iovlen = msg_iov.len, - .control = &ctrl_msgs, - .controllen = @intCast(@sizeOf(cmsg(std.os.fd_t)) * ctrl_msgs.len), - .flags = 0, - }; - _ = try std.os.sendmsg(conn.socket.handle, &socket_msg, 0); } +} - pub const Message = struct { Header, []const u32 }; - pub fn recv(conn: *Conn) !Message { - // TODO: make this less messy - // Read header - @memset(conn.recv_buffer, 0); - var iov: [1]std.os.iovec = .{.{ - .iov_base = std.mem.sliceAsBytes(conn.recv_buffer).ptr, - .iov_len = @sizeOf(Header), - }}; - var control_msg: cmsg(std.os.fd_t) = undefined; - const control_bytes = std.mem.asBytes(&control_msg); - var socket_msg = std.os.msghdr{ - .name = null, - .namelen = 0, - .iov = &iov, - .iovlen = iov.len, - .control = control_bytes.ptr, - .controllen = @intCast(control_bytes.len), - .flags = 0, - }; +fn textWidth(str: []const u8) usize { + return std.unicode.utf8CountCodepoints(str) catch 0; // incorrect, but I'm going with it +} - const size = std.os.linux.recvmsg(conn.socket.handle, &socket_msg, 0); +fn renderText(framebuffer: []Pixel, fb_size: [2]u32, pos: [2]usize, str: []const u8) void { + const top, const left = pos; + const bot = @min(top + 8, fb_size[1]); + const right = @min(left + textWidth(str) * 8, fb_size[0]); - if (size < @sizeOf(Header)) return error.SocketClosed; - - var header: Header = undefined; - @memcpy(std.mem.asBytes(&header), iov[0].iov_base[0..@sizeOf(Header)]); - - if (socket_msg.controllen != 0) { - try conn.fd_queue.append(conn.allocator, control_msg.data); + for (top..bot) |y| { + const row = framebuffer[y * fb_size[0] .. (y + 1) * fb_size[0]]; + for (row[left..right], left..right) |*pixel, x| { + const col = ((x - left) / 8); + const which_char = str[col]; + if (!std.ascii.isPrint(which_char)) continue; + const char = font8x8.font8x8_basic[which_char]; + const line = char[(y - top) % 8]; + if ((line >> @intCast((x - left) % 8)) & 0x1 != 0) { + pixel.* = toPixel(Theme.foreground); + } else { + pixel.* = toPixel(Theme.background); + } } - - // Read body - const body_size = (header.size_and_opcode.size - @sizeOf(Header)) / @sizeOf(u32); - - iov[0] = .{ - .iov_base = std.mem.sliceAsBytes(conn.recv_buffer).ptr, - .iov_len = body_size * @sizeOf(u32), - }; - socket_msg = std.os.msghdr{ - .name = null, - .namelen = 0, - .iov = &iov, - .iovlen = iov.len, - .control = control_bytes.ptr, - .controllen = @intCast(control_bytes.len), - .flags = 0, - }; - const size2 = std.os.linux.recvmsg(conn.socket.handle, &socket_msg, 0); - const message = conn.recv_buffer[0 .. size2 / @sizeOf(u32)]; - - if (socket_msg.controllen != 0) { - try conn.fd_queue.append(conn.allocator, control_msg.data); - } - - return .{ header, message }; } -}; - -// pub const XKBKeymap = struct { -// keycodes: Keycodes, -// types: Types, -// compatability: Compatability, -// symbols: Symbols, -// -// const Keycodes = struct { -// min: usize, -// max: usize, -// map: std.AutoHashMap(usize, usize), -// indicators: std.StringHashMap(usize), -// }; -// -// const ISOKEY = [4]u8; -// -// const Types = struct {}; -// const Compatability = struct {}; -// const Symbols = struct {}; -// -// pub fn parse() {} -// }; +} diff --git a/src/root.zig b/src/root.zig new file mode 100644 index 0000000..90126bc --- /dev/null +++ b/src/root.zig @@ -0,0 +1,646 @@ +const std = @import("std"); +const testing = std.testing; +pub const core = @import("./core.zig"); +pub const xdg = @import("./xdg.zig"); +pub const zxdg = @import("./zxdg.zig"); +pub const zwp = @import("./zwp.zig"); +pub const types = @import("./types.zig"); + +pub fn getDisplayPath(gpa: std.mem.Allocator) ![]u8 { + const xdg_runtime_dir_path = try std.process.getEnvVarOwned(gpa, "XDG_RUNTIME_DIR"); + defer gpa.free(xdg_runtime_dir_path); + const display_name = std.process.getEnvVarOwned(gpa, "WAYLAND_DISPLAY") catch |err| switch (err) { + error.EnvironmentVariableNotFound => return try std.fs.path.join(gpa, &.{ xdg_runtime_dir_path, "wayland-0" }), + else => return err, + }; + defer gpa.free(display_name); + + return try std.fs.path.join(gpa, &.{ xdg_runtime_dir_path, display_name }); +} + +pub const Header = extern struct { + object_id: u32 align(1), + size_and_opcode: SizeAndOpcode align(1), + + pub const SizeAndOpcode = packed struct(u32) { + opcode: u16, + size: u16, + }; +}; + +test "[]u32 from header" { + try std.testing.expectEqualSlices( + u32, + &[_]u32{ + 1, + (@as(u32, 12) << 16) | (4), + }, + &@as([2]u32, @bitCast(Header{ + .object_id = 1, + .size_and_opcode = .{ + .size = 12, + .opcode = 4, + }, + })), + ); +} + +test "header from []u32" { + try std.testing.expectEqualDeep( + Header{ + .object_id = 1, + .size_and_opcode = .{ + .size = 12, + .opcode = 4, + }, + }, + @as(Header, @bitCast([2]u32{ + 1, + (@as(u32, 12) << 16) | (4), + })), + ); +} + +pub fn readUInt(buffer: []const u32, parent_pos: *usize) !u32 { + var pos = parent_pos.*; + if (pos >= buffer.len) return error.EndOfStream; + + const uint: u32 = @bitCast(buffer[pos]); + pos += 1; + + parent_pos.* = pos; + return uint; +} + +pub fn readInt(buffer: []const u32, parent_pos: *usize) !i32 { + var pos = parent_pos.*; + if (pos >= buffer.len) return error.EndOfStream; + + const int: i32 = @bitCast(buffer[pos]); + pos += 1; + + parent_pos.* = pos; + return int; +} + +pub fn readString(buffer: []const u32, parent_pos: *usize) !?[:0]const u8 { + var pos = parent_pos.*; + + const len = try readUInt(buffer, &pos); + if (len == 0) return null; + const wordlen = std.mem.alignForward(usize, len, @sizeOf(u32)) / @sizeOf(u32); + + if (pos + wordlen > buffer.len) return error.EndOfStream; + const string = std.mem.sliceAsBytes(buffer[pos..])[0 .. len - 1 :0]; + pos += std.mem.alignForward(usize, len, @sizeOf(u32)) / @sizeOf(u32); + + parent_pos.* = pos; + return string; +} + +pub fn readArray(comptime T: type, buffer: []const u32, parent_pos: *usize) ![]const T { + var pos = parent_pos.*; + + const byte_size = try readUInt(buffer, &pos); + + const array = @as([*]const T, @ptrCast(buffer[pos..].ptr))[0 .. byte_size / @sizeOf(T)]; + pos += byte_size / @sizeOf(u32); + + parent_pos.* = pos; + return array; +} + +pub fn deserializeArguments(comptime Signature: type, buffer: []const u32) !Signature { + if (Signature == void) return {}; + var result: Signature = undefined; + var pos: usize = 0; + inline for (std.meta.fields(Signature)) |field| { + if (field.type == types.Fd) continue; + switch (@typeInfo(field.type)) { + .Int => |int_info| switch (int_info.signedness) { + .signed => @field(result, field.name) = try readInt(buffer, &pos), + .unsigned => @field(result, field.name) = try readUInt(buffer, &pos), + }, + .Enum => |enum_info| if (@sizeOf(enum_info.tag_type) == @sizeOf(u32)) { + @field(result, field.name) = @enumFromInt(try readInt(buffer, &pos)); + } else { + @compileError("Unsupported type " ++ @typeName(field.type)); + }, + .Pointer => |ptr| switch (ptr.size) { + .Slice => if (ptr.child == u8) { + @field(result, field.name) = try readString(buffer, &pos) orelse return error.UnexpectedNullString; + } else { + @field(result, field.name) = try readArray(ptr.child, buffer, &pos); + }, + else => @compileError("Unsupported type " ++ @typeName(field.type)), + }, + .Optional => |opt| switch (@typeInfo(opt.child)) { + .Pointer => |ptr| switch (ptr.size) { + .Slice => if (ptr.child == u8) { + @field(result, field.name) = try readString(buffer, &pos); + } else @compileError("Unsupported type " ++ @typeName(field.type)), + else => @compileError("Unsupported type " ++ @typeName(field.type)), + }, + else => @compileError("Unsupported type " ++ @typeName(field.type)), + }, + else => @compileError("Unsupported type " ++ @typeName(field.type)), + } + } + return result; +} + +pub fn deserialize(comptime Union: type, header: Header, buffer: []const u32) !Union { + const op = try std.meta.intToEnum(std.meta.Tag(Union), header.size_and_opcode.opcode); + switch (op) { + inline else => |f| { + const Payload = std.meta.TagPayload(Union, f); + const payload = try deserializeArguments(Payload, buffer); + return @unionInit(Union, @tagName(f), payload); + }, + } +} + +/// Returns the length of the serialized message in `u32` words. +pub fn calculateSerializedWordLen(comptime Signature: type, message: Signature) usize { + var pos: usize = 0; + inline for (std.meta.fields(Signature)) |field| { + switch (@typeInfo(field.type)) { + .Int => pos += 1, + .Pointer => |ptr| switch (ptr.size) { + .Slice => { + // for size of string in bytes + pos += 1; + + const str = @field(message, field.name); + pos += std.mem.alignForward(usize, str.len + 1, @sizeOf(u32)) / @sizeOf(u32); + }, + else => @compileError("Unsupported type " ++ @typeName(field.type)), + }, + else => @compileError("Unsupported type " ++ @typeName(field.type)), + } + } + return pos; +} + +pub fn countFds(comptime Signature: type) usize { + if (Signature == void) return 0; + var count: usize = 0; + inline for (std.meta.fields(Signature)) |field| { + if (field.type == types.Fd) { + count += 1; + } + } + return count; +} + +pub fn extractFds(comptime Signature: type, message: *const Signature) [countFds(Signature)]*const types.Fd { + if (Signature == void) return [_]*const types.Fd{}; + var fds: [countFds(Signature)]*const types.Fd = undefined; + var i: usize = 0; + inline for (std.meta.fields(Signature)) |field| { + if (field.type == types.Fd) { + fds[i] = &@field(message, field.name); + i += 1; + } + } + return fds; +} + +/// Message must live until the iovec array is written. +pub fn serializeArguments(comptime Signature: type, buffer: []u32, message: Signature) ![]u32 { + if (Signature == void) return buffer[0..0]; + var pos: usize = 0; + inline for (std.meta.fields(Signature)) |field| { + if (field.type == types.Fd) continue; + switch (@typeInfo(field.type)) { + .Int => { + if (pos >= buffer.len) return error.OutOfMemory; + buffer[pos] = @bitCast(@field(message, field.name)); + pos += 1; + }, + .Enum => |enum_info| if (enum_info.tag_type == u32) { + if (pos >= buffer.len) return error.OutOfMemory; + buffer[pos] = @intFromEnum(@field(message, field.name)); + pos += 1; + } else { + @compileError("Unsupported type " ++ @typeName(field.type)); + }, + .Pointer => |ptr| switch (ptr.size) { + .Slice => { + const str = @field(message, field.name); + if (str.len >= std.math.maxInt(u32)) return error.StringTooLong; + + buffer[pos] = @intCast(str.len + 1); + pos += 1; + + const str_len_aligned = std.mem.alignForward(usize, str.len + 1, @sizeOf(u32)); + const padding_len = str_len_aligned - str.len; + if (str_len_aligned / @sizeOf(u32) >= buffer[pos..].len) return error.OutOfMemory; + const buffer_bytes = std.mem.sliceAsBytes(buffer[pos..]); + @memcpy(buffer_bytes[0..str.len], str); + @memset(buffer_bytes[str.len..][0..padding_len], 0); + pos += str_len_aligned / @sizeOf(u32); + }, + else => @compileError("Unsupported type " ++ @typeName(field.type)), + }, + .Optional => |opt| switch (@typeInfo(opt.child)) { + .Pointer => |ptr| switch (ptr.size) { + .Slice => if (ptr.child == u8) { + const str = @field(message, field.name); + if (str.len >= std.math.maxInt(u32)) return error.StringTooLong; + + buffer[pos] = @intCast(str.len + 1); + pos += 1; + + const str_len_aligned = std.mem.alignForward(usize, str.len + 1, @sizeOf(u32)); + const padding_len = str_len_aligned - str.len; + if (str_len_aligned / @sizeOf(u32) >= buffer[pos..].len) return error.OutOfMemory; + const buffer_bytes = std.mem.sliceAsBytes(buffer[pos..]); + @memcpy(buffer_bytes[0..str.len], str); + @memset(buffer_bytes[str.len..][0..padding_len], 0); + pos += str_len_aligned / @sizeOf(u32); + } else @compileError("Unsupported type " ++ @typeName(field.type)), + else => @compileError("Unsupported type " ++ @typeName(field.type)), + }, + else => @compileError("Unsupported type " ++ @typeName(field.type)), + }, + else => @compileError("Unsupported type " ++ @typeName(field.type)), + } + } + return buffer[0..pos]; +} + +pub fn serialize(comptime Union: type, buffer: []u32, object_id: u32, message: Union) ![]u32 { + const header_wordlen = @sizeOf(Header) / @sizeOf(u32); + const header: *Header = @ptrCast(buffer[0..header_wordlen]); + header.object_id = object_id; + + const tag = std.meta.activeTag(message); + header.size_and_opcode.opcode = @intFromEnum(tag); + + const arguments = switch (message) { + inline else => |payload| try serializeArguments(@TypeOf(payload), buffer[header_wordlen..], payload), + }; + + header.size_and_opcode.size = @intCast(@sizeOf(Header) + arguments.len * @sizeOf(u32)); + return buffer[0 .. header.size_and_opcode.size / @sizeOf(u32)]; +} + +test "deserialize Registry.Event.Global" { + const words = [_]u32{ + 1, + 7, + @bitCast(@as([4]u8, "wl_s".*)), + @bitCast(@as([4]u8, "hm\x00\x00".*)), + 3, + }; + const parsed = try deserializeArguments(core.Registry.Event.Global, &words); + try std.testing.expectEqualDeep(core.Registry.Event.Global{ + .name = 1, + .interface = "wl_shm", + .version = 3, + }, parsed); +} + +test "deserialize Registry.Event" { + const header = Header{ + .object_id = 123, + .size_and_opcode = .{ + .size = 28, + .opcode = @intFromEnum(core.Registry.Event.Tag.global), + }, + }; + const words = [_]u32{ + 1, + 7, + @bitCast(@as([4]u8, "wl_s".*)), + @bitCast(@as([4]u8, "hm\x00\x00".*)), + 3, + }; + const parsed = try deserialize(core.Registry.Event, header, &words); + try std.testing.expectEqualDeep( + core.Registry.Event{ + .global = .{ + .name = 1, + .interface = "wl_shm", + .version = 3, + }, + }, + parsed, + ); + + const header2 = Header{ + .object_id = 1, + .size_and_opcode = .{ + .size = 14 * @sizeOf(u32), + .opcode = @intFromEnum(core.Display.Event.Tag.@"error"), + }, + }; + const words2 = [_]u32{ + 1, + 15, + 40, + @bitCast(@as([4]u8, "inva".*)), + @bitCast(@as([4]u8, "lid ".*)), + @bitCast(@as([4]u8, "argu".*)), + @bitCast(@as([4]u8, "ment".*)), + @bitCast(@as([4]u8, "s to".*)), + @bitCast(@as([4]u8, " wl_".*)), + @bitCast(@as([4]u8, "regi".*)), + @bitCast(@as([4]u8, "stry".*)), + @bitCast(@as([4]u8, "@2.b".*)), + @bitCast(@as([4]u8, "ind\x00".*)), + }; + const parsed2 = try deserialize(core.Display.Event, header2, &words2); + try std.testing.expectEqualDeep( + core.Display.Event{ + .@"error" = .{ + .object_id = 1, + .code = 15, + .message = "invalid arguments to wl_registry@2.bind", + }, + }, + parsed2, + ); +} + +test "serialize Registry.Event.Global" { + const message = core.Registry.Event.Global{ + .name = 1, + .interface = "wl_shm", + .version = 3, + }; + var buffer: [5]u32 = undefined; + const serialized = try serializeArguments(core.Registry.Event.Global, &buffer, message); + + try std.testing.expectEqualSlices( + u32, + &[_]u32{ + 1, + 7, + @bitCast(@as([4]u8, "wl_s".*)), + @bitCast(@as([4]u8, "hm\x00\x00".*)), + 3, + }, + serialized, + ); +} + +pub const IdPool = struct { + next_id: u32 = 2, + free_ids: std.BoundedArray(u32, 1024) = .{}, + + pub fn create(this: *@This()) u32 { + if (this.free_ids.popOrNull()) |id| { + return id; + } + + defer this.next_id += 1; + return this.next_id; + } + + pub fn destroy(this: *@This(), id: u32) void { + for (this.free_ids.slice()) |existing_id| { + if (existing_id == id) return; + } + this.free_ids.append(id) catch {}; + } +}; + +pub fn registerGlobals(alloc: std.mem.Allocator, id_pool: *IdPool, socket: std.net.Stream, comptime T: []const type) ![T.len]?u32 { + const Item = struct { version: u32, index: u32 }; + const Pair = struct { []const u8, Item }; + comptime var kvs_list: []const Pair = &[_]Pair{}; + inline for (T, 0..) |t, i| { + kvs_list = kvs_list ++ &[_]Pair{.{ t.INTERFACE, .{ .version = t.VERSION, .index = i } }}; + } + const map = std.ComptimeStringMap(Item, kvs_list); + + const registry_id = id_pool.create(); + { + var buffer: [5]u32 = undefined; + const message = try serialize(core.Display.Request, &buffer, 1, .{ .get_registry = .{ .registry = registry_id } }); + try socket.writeAll(std.mem.sliceAsBytes(message)); + } + + const registry_done_id = id_pool.create(); + { + var buffer: [5]u32 = undefined; + const message = try serialize(core.Display.Request, &buffer, 1, .{ .sync = .{ .callback = registry_done_id } }); + try socket.writeAll(std.mem.sliceAsBytes(message)); + } + + var ids: [T.len]?u32 = [_]?u32{null} ** T.len; + var message_buffer = std.ArrayList(u32).init(alloc); + defer message_buffer.deinit(); + while (true) { + var header: Header = undefined; + const header_bytes_read = try socket.readAll(std.mem.asBytes(&header)); + if (header_bytes_read < @sizeOf(Header)) break; + + try message_buffer.resize((header.size_and_opcode.size - @sizeOf(Header)) / @sizeOf(u32)); + const bytes_read = try socket.readAll(std.mem.sliceAsBytes(message_buffer.items)); + message_buffer.shrinkRetainingCapacity(bytes_read / @sizeOf(u32)); + + if (header.object_id == registry_id) { + const event = try deserialize(core.Registry.Event, header, message_buffer.items); + switch (event) { + .global => |global| { + var buffer: [20]u32 = undefined; + if (map.get(global.interface)) |item| { + if (global.version < item.version) { + // TODO: Add diagnostics API + return error.OutdatedCompositorProtocol; + } + const new_id = id_pool.create(); + ids[item.index] = new_id; + const message = try serialize(core.Registry.Request, &buffer, registry_id, .{ .bind = .{ + .name = global.name, + .interface = global.interface, + .version = item.version, + .new_id = new_id, + } }); + try socket.writeAll(std.mem.sliceAsBytes(message)); + } + }, + .global_remove => {}, + } + } else if (header.object_id == registry_done_id) { + break; + } else { + std.log.info("{} {x} \"{}\"", .{ + header.object_id, + header.size_and_opcode.opcode, + std.zig.fmtEscapes(std.mem.sliceAsBytes(message_buffer.items)), + }); + } + } + + return ids; +} + +fn cmsg(comptime T: type) type { + const padding_size = (@sizeOf(T) + @sizeOf(c_long) - 1) & ~(@as(usize, @sizeOf(c_long)) - 1); + return extern struct { + len: c_ulong = @sizeOf(@This()) - padding_size, + level: c_int, + type: c_int, + data: T, + _padding: [padding_size]u8 align(1) = [_]u8{0} ** padding_size, + }; +} + +pub const Conn = struct { + allocator: std.mem.Allocator, + send_buffer: []u32, + recv_buffer: []u32, + fd_queue: std.ArrayListUnmanaged(std.os.fd_t), + socket: std.net.Stream, + + pub fn init(alloc: std.mem.Allocator, display_path: []const u8) !Conn { + const send_buffer = try alloc.alloc(u32, 16); + const recv_buffer = try alloc.alloc(u32, 16); + return .{ + .allocator = alloc, + .send_buffer = send_buffer, + .recv_buffer = recv_buffer, + .fd_queue = .{}, + .socket = try std.net.connectUnixSocket(display_path), + }; + } + + pub fn deinit(conn: *Conn) void { + conn.allocator.free(conn.send_buffer); + conn.allocator.free(conn.recv_buffer); + conn.fd_queue.deinit(conn.allocator); + conn.socket.close(); + } + + pub fn send(conn: *Conn, comptime Signature: type, id: u32, message: Signature) !void { + const msg = while (true) { + const msg = serialize( + Signature, + conn.send_buffer, + id, + message, + ) catch |e| switch (e) { + error.OutOfMemory => { + conn.send_buffer = try conn.allocator.realloc(conn.send_buffer, conn.send_buffer.len * 2); + continue; + }, + else => return e, + }; + + break msg; + }; + const msg_bytes = std.mem.sliceAsBytes(msg); + const msg_iov = [_]std.os.iovec_const{ + .{ + .iov_base = msg_bytes.ptr, + .iov_len = msg_bytes.len, + }, + }; + const fds = switch (message) { + inline else => |*payload| extractFds(@TypeOf(payload.*), payload), + }; + var ctrl_msgs: [fds.len]cmsg(std.os.fd_t) = undefined; + for (fds, 0..) |fdp, i| { + std.debug.print("fd {}: {}\n", .{ i, fdp.* }); + ctrl_msgs[i] = .{ + .level = std.os.SOL.SOCKET, + .type = 0x01, + .data = @intFromEnum(fdp.*), + }; + } + const socket_msg = std.os.msghdr_const{ + .name = null, + .namelen = 0, + .iov = &msg_iov, + .iovlen = msg_iov.len, + .control = &ctrl_msgs, + .controllen = @intCast(@sizeOf(cmsg(std.os.fd_t)) * ctrl_msgs.len), + .flags = 0, + }; + _ = try std.os.sendmsg(conn.socket.handle, &socket_msg, 0); + } + + pub const Message = struct { Header, []const u32 }; + pub fn recv(conn: *Conn) !Message { + // TODO: make this less messy + // Read header + @memset(conn.recv_buffer, 0); + var iov: [1]std.os.iovec = .{.{ + .iov_base = std.mem.sliceAsBytes(conn.recv_buffer).ptr, + .iov_len = @sizeOf(Header), + }}; + var control_msg: cmsg(std.os.fd_t) = undefined; + const control_bytes = std.mem.asBytes(&control_msg); + var socket_msg = std.os.msghdr{ + .name = null, + .namelen = 0, + .iov = &iov, + .iovlen = iov.len, + .control = control_bytes.ptr, + .controllen = @intCast(control_bytes.len), + .flags = 0, + }; + + const size = std.os.linux.recvmsg(conn.socket.handle, &socket_msg, 0); + + if (size < @sizeOf(Header)) return error.SocketClosed; + + var header: Header = undefined; + @memcpy(std.mem.asBytes(&header), iov[0].iov_base[0..@sizeOf(Header)]); + + if (socket_msg.controllen != 0) { + try conn.fd_queue.append(conn.allocator, control_msg.data); + } + + // Read body + const body_size = (header.size_and_opcode.size - @sizeOf(Header)) / @sizeOf(u32); + + iov[0] = .{ + .iov_base = std.mem.sliceAsBytes(conn.recv_buffer).ptr, + .iov_len = body_size * @sizeOf(u32), + }; + socket_msg = std.os.msghdr{ + .name = null, + .namelen = 0, + .iov = &iov, + .iovlen = iov.len, + .control = control_bytes.ptr, + .controllen = @intCast(control_bytes.len), + .flags = 0, + }; + const size2 = std.os.linux.recvmsg(conn.socket.handle, &socket_msg, 0); + const message = conn.recv_buffer[0 .. size2 / @sizeOf(u32)]; + + if (socket_msg.controllen != 0) { + try conn.fd_queue.append(conn.allocator, control_msg.data); + } + + return .{ header, message }; + } +}; + +// pub const XKBKeymap = struct { +// keycodes: Keycodes, +// types: Types, +// compatability: Compatability, +// symbols: Symbols, +// +// const Keycodes = struct { +// min: usize, +// max: usize, +// map: std.AutoHashMap(usize, usize), +// indicators: std.StringHashMap(usize), +// }; +// +// const ISOKEY = [4]u8; +// +// const Types = struct {}; +// const Compatability = struct {}; +// const Symbols = struct {}; +// +// pub fn parse() {} +// };