diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c2658d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/resources/palettes_gen.sh b/resources/palettes_gen.sh new file mode 100755 index 0000000..0b0f6cb --- /dev/null +++ b/resources/palettes_gen.sh @@ -0,0 +1,263 @@ +#!/bin/bash + +# ---- sys +NC=" \033[0m" +coerce=false +lowercase=false +file="" +prefix="" +original_palette="storm" +verbosity=0 + +script_help=$( + cat < [arg] + +Flags: + -f, --file specify file (mandatory) + -v, --verbose increase verbosity by 1 + -o, --original-palette the palette used in the based file (given by --file) + -l, --lowercase replaces with lowercased hex codes + -c, --coerce force the creation of new palette files (useful when those files already exist) + -p, --prefix specify which prefix to use for the hex codes. Surround it with double quotes if needed. + -h, --help see this message +EOF +) + +palette_names=( + storm + dusk + dawn +) + +declare -A dusk=( + [white]='C6D0F5' + [peach]='FAB387' + [gray2]='ADB5D8' + [black0]='101019' + [black1]='181825' + [gray1]='959BBA' + [blue]='90C1FB' + [green]='A6E3A1' + [sapphire]='74C7EC' + [black3]='323044' + [black4]='4B4B62' + [black5]='63657F' + [teal]='94E2D5' + [gray0]='7C809D' + [rosewater]='F5E0DC' + [maroon]='EBA0AC' + [lavender]='C9CBFF' + [yellow]='F9E2AF' + [flamingo]='F2CDCD' + [sky]='89DCEB' + [mauve]='CBA6F7' + [black2]='1E1E2E' + [pink]='F5C2E7' + [red]='F38BA8' +) + +declare -A storm=( + [white]='C5CFF5' + [sapphire]='34C3DC' + [pink]='F5BFE7' + [rosewater]='F5DFDA' + [black2]='24273A' + [flamingo]='F2CBCB' + [red]='F67E98' + [maroon]='F1949B' + [peach]='FEA571' + [black1]='1F2233' + [sky]='89DCFD' + [gray1]='8289AA' + [lavender]='C2CBFE' + [black3]='2B3045' + [green]='A1DF8E' + [black4]='3E435E' + [yellow]='F1D8A4' + [gray2]='A6AFD2' + [blue]='83ABF9' + [black0]='1A1B26' + [gray0]='5F6587' + [teal]='85E0D1' + [black5]='4F5473' + [mauve]='C59FF6' +) + +declare -A dawn=( + [black4]='CCC9D1' + [peach]='FE6811' + [black3]='E6E3E5' + [pink]='EC83D0' + [black0]='D3D0D2' + [black1]='EDEDED' + [blue]='1D65F5' + [lavender]='7287FD' + [mauve]='8F46EF' + [black5]='B5B1BF' + [maroon]='E63B4A' + [rosewater]='E5AC9F' + [green]='509E31' + [gray1]='86819C' + [black2]='FBF8F4' + [white]='575279' + [gray2]='6E6A8B' + [sky]='04A5E5' + [sapphire]='209FB5' + [red]='D20F39' + [teal]='289886' + [gray0]='9D99AE' + [flamingo]='DF7F7F' + [yellow]='E49320' +) + +function prompt() { + local type=${1} # error, success, warning, info + local message=${2} + local modifiers=${3} + + if [[ $1 == "-i" || $1 == "--info" ]]; then + type="" + fi + + case ${type} in + "-e" | "--error") + printf "\033[0;31m${modifiers}ERROR: %s${NC}\n" "${message}" + ;; + "-s" | "--success") + printf "\033[0;32m${modifiers}SUCCESS: %s${NC}\n" "${message}" + ;; + "-w" | "--warning") + printf "\033[0;33m${modifiers}WARNING: %s${NC}\n" "${message}" + ;; + *) + printf "\033[0;34m${modifiers}INFO: %s${NC}\n" "${message}" + ;; + esac +} + +function verbose_print() { + # $1 = message + # $2 = modifiers + if [[ $verbosity -gt 0 ]]; then + printf "\033[3;29m${2}%s${NC}\n" "${1}" + fi +} + +function generate_palettes() { + capitalization_char='\U' # uppercase + [[ $lowercase == true ]] && { + capitalization_char='\L' # lowercase + } + + new_array=() + for val in "${palette_names[@]}"; do + [[ "$val" != "$original_palette" ]] && new_array+=("$val") + done + palette_names=("${new_array[@]}") + unset new_array + + for palette in "${palette_names[@]}"; do + printf " GENERATING: \033[3;32m%s${NC}\n" "$palette" + + local dest_file="${palette}.${file##*.}" + prompt -w "creating $dest_file..." "\t• " + + if [[ -f $dest_file ]]; then + if [[ ! $coerce == true ]]; then + prompt -e "file '$dest_file' already exists. Use --coerce to force it's replacement" "\t• " + exit 1 + fi + fi + + cp "$file" "$dest_file" + prompt -i "replacing colors..." "\t• " + + for clr in "${!storm[@]}"; do + local curr_color=$(eval "echo \${${original_palette}[$clr]}") + local dest_color=$(eval "echo \${${palette}[${clr}]}") + verbose_print "modifying ${clr}" "\t + " + sed -i "s/${curr_color}/${prefix}${capitalization_char}${dest_color}/gI" "$dest_file" + done + done +} + +function detect_original_palette() { + prompt -w "detecting palette..." + original_palette="" + for palette in "${palette_names[@]}"; do + for clr in "${!storm[@]}"; do + if grep -q $(eval "echo \${${palette}[${clr}]}") "$file"; then + original_palette=$palette + break 2 + fi + done + done + + if [[ $original_palette == "" ]]; then + prompt -e "couldn't detect the original palette" + exit 1 + else + prompt -s "detected '$original_palette'" + fi +} + +main() { + if [[ ! "$#" -gt 0 ]]; then + prompt -e "you must provide at least the file you want to generate the missing palettes from" + else + local help_used=false + while [ "$1" != "" ]; do + case $1 in + -v | --verbose) + verbosity=$((verbosity + 1)) + ;; + -f | --file) + file=$2 + shift + ;; + -o | --original-palette) + origianl_palette=$2 + shift + ;; + -l | --lowercase) + lowercase=true + ;; + -c | --coerce) + coerce=true + ;; + -p | --prefix) + prefix=$2 + shift + ;; + -h | --help) + help_used=true + echo "$script_help" + ;; + *) + echo "ERROR: command ($1) not recognized" + ;; + esac + shift + done + + if [[ $help_used != "true" ]]; then + if [[ $file != "" ]]; then + [[ -f $file ]] && { + prompt "updating colors..." + if [[ original_palette != "storm" || original_palette != "dusk" || original_palette != "dawn" ]]; then + detect_original_palette + fi + generate_palettes + } || prompt -e "file ${1} does not exist" + else + prompt -e "please profive a file to use a base using the --file flag" + fi + fi + fi +} + +main "$@" diff --git a/samples/header.h b/samples/header.h new file mode 100644 index 0000000..43777dd --- /dev/null +++ b/samples/header.h @@ -0,0 +1,131 @@ +/* See LICENSE file for copyright and license details. */ + +/* appearance */ +static const unsigned int borderpx = 1; /* border pixel of windows */ +static const unsigned int snap = 32; /* snap pixel */ +static const int showbar = 1; /* 0 means no bar */ +static const int topbar = 1; /* 0 means bottom bar */ +static const char *fonts[] = { "monospace:size=10" }; +static const char dmenufont[] = "monospace:size=10"; +static const char col_gray1[] = "#5F6587"; +static const char col_gray2[] = "#8289AA"; +static const char col_gray3[] = "#A6AFD2"; +static const char col_gray4[] = "#C5CFF5"; +static const char col_teal[] = "#78DCCC"; +static const char *colors[][3] = { + /* fg bg border */ + [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, + [SchemeSel] = { col_gray4, col_teal, col_teal }, +}; + +/* tagging */ +static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; + +static const Rule rules[] = { + /* xprop(1): + * WM_CLASS(STRING) = instance, class + * WM_NAME(STRING) = title + */ + /* class instance title tags mask isfloating monitor */ + { "Gimp", NULL, NULL, 0, 1, -1 }, + { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, +}; +static const int ruleperiod = 5; /* number of seconds before rules are ignored */ + +/* layout(s) */ +static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ +static const int nmaster = 1; /* number of clients in master area */ +static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */ +static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ + +static const LayoutMonitorRule lm_rules[] = { + /* >=w, >=h, req'd layout, new nmaster, new mfact */ + { 3000, 0, 0, 2, 0.66 }, +}; + +static const Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, + { "TTT", bstack }, + { "===", bstackhoriz }, +}; + +/* key definitions */ +#define MODKEY Mod1Mask +#define TAGKEYS(KEY,TAG) \ + { KeyPress, MODKEY, KEY, view, {.ui = 1 << TAG} }, \ + { KeyPress, MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \ + { KeyPress, MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \ + { KeyPress, MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} }, + +/* helper for spawning shell commands in the pre dwm-5.0 fashion */ +#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } + +/* commands */ +static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ +static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_teal, "-sf", col_gray4, NULL }; +static const char *termcmd[] = { "st", NULL }; + +#include "movestack.c" +static Key keys[] = { + /* modifier key function argument */ + { MODKEY, XK_p, spawn, {.v = dmenucmd } }, + { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_b, togglebar, {0} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, + { MODKEY, XK_d, incnmaster, {.i = -1 } }, + { MODKEY, XK_h, setmfact, {.f = -0.05} }, + { MODKEY, XK_l, setmfact, {.f = +0.05} }, + { MODKEY|ShiftMask, XK_j, movestack, {.i = +1 } }, + { MODKEY|ShiftMask, XK_k, movestack, {.i = -1 } }, + { MODKEY, XK_Return, zoom, {0} }, + { MODKEY, XK_Tab, view, {0} }, + { MODKEY|ShiftMask, XK_c, killclient, {0} }, + { MODKEY|ShiftMask, XK_x, killunsel, {0} }, + { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, + { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, + { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, + { MODKEY, XK_u, setlayout, {.v = &layouts[3]} }, + { MODKEY, XK_o, setlayout, {.v = &layouts[4]} }, + { MODKEY, XK_space, setlayout, {0} }, + { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, + { MODKEY, XK_0, view, {.ui = ~0 } }, + { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, + { MODKEY, XK_comma, focusmon, {.i = -1 } }, + { MODKEY, XK_period, focusmon, {.i = +1 } }, + { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, + { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, + { MODKEY|ControlMask, XK_comma, tagallmon, {.i = -1 } }, + { MODKEY|ControlMask, XK_period, tagallmon, {.i = +1 } }, + TAGKEYS( XK_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) + TAGKEYS( XK_4, 3) + TAGKEYS( XK_5, 4) + TAGKEYS( XK_6, 5) + TAGKEYS( XK_7, 6) + TAGKEYS( XK_8, 7) + TAGKEYS( XK_9, 8) + { KeyPress, MODKEY|ShiftMask, XK_q, quit, {0} }, +}; + +/* button definitions */ +/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ +static Button buttons[] = { + /* click event mask button function argument */ + { ClkLtSymbol, 0, Button1, setlayout, {0} }, + { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, + { ClkWinTitle, 0, Button2, zoom, {0} }, + { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, + { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, + { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, + { ClkTagBar, 0, Button1, view, {0} }, + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, +}; diff --git a/samples/rust.rs b/samples/rust/0.rs similarity index 95% rename from samples/rust.rs rename to samples/rust/0.rs index 531316e..1bd9226 100644 --- a/samples/rust.rs +++ b/samples/rust/0.rs @@ -1,5 +1,3 @@ -// Simple program made by a simple programmer - #![warn(rust_2018_idioms)] #![allow(elided_lifetimes_in_paths)] diff --git a/samples/rust/1.rs b/samples/rust/1.rs new file mode 100644 index 0000000..ff4fa8c --- /dev/null +++ b/samples/rust/1.rs @@ -0,0 +1,961 @@ +use crate::context::DrawContext; +use crate::controller::Controller; +use crate::font::FontCache; +use crate::scene::*; +use crate::wayland::*; +use crate::*; +use smithay_client_toolkit::reexports::calloop::{EventLoop, LoopHandle, RegistrationToken}; +use smithay_client_toolkit::seat::keyboard::ModifiersState; +use smithay_client_toolkit::shm::AutoMemPool; +use smithay_client_toolkit::WaylandSource; + +use std::cell::RefCell; +use std::ops::{Deref, DerefMut}; +use std::rc::Rc; + +use smithay_client_toolkit::reexports::client::{ + global_filter, + protocol::wl_buffer::WlBuffer, + protocol::wl_callback, + protocol::wl_compositor::WlCompositor, + protocol::wl_output::{self, WlOutput}, + protocol::wl_pointer::{self, WlPointer}, + protocol::wl_region::WlRegion, + protocol::wl_seat::{self, Capability, WlSeat}, + protocol::wl_shm::WlShm, + protocol::wl_surface::WlSurface, + Attached, Display, GlobalError, GlobalManager, Interface, Main, Proxy, +}; +use smithay_client_toolkit::reexports::protocols::wlr::unstable::layer_shell::v1::client::{ + zwlr_layer_shell_v1::ZwlrLayerShellV1, zwlr_layer_surface_v1, + zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, +}; + +pub struct Application +where + C: Controller + Clone + 'static, +{ + display: Display, + globals: Rc>, + global_manager: GlobalManager, + pub inner: Vec>, + token: RegistrationToken, +} + +struct Context { + pending_cb: bool, + time: Option, + render_node: Option, + font_cache: FontCache, +} + +pub struct CoreApplication +where + C: Controller + Clone, +{ + pub controller: C, + ctx: Context, + globals: Rc>, + mempool: AutoMemPool, + widget: Box>, + surface: Option, +} + +pub struct InnerApplication +where + C: Controller + Clone, +{ + core: CoreApplication, + cb: Box, Event)>, +} + +impl Surface { + fn new( + surface: Main, + shell: Shell, + region: Main, + previous: Option, + ) -> Self { + Surface { + alive: true, + surface, + shell, + region, + previous: if let Some(surface) = previous { + Some(Box::new(surface)) + } else { + None + }, + buffer: None, + } + } + fn commit(&mut self) { + self.surface.commit(); + std::mem::drop(&mut self.previous); + self.previous = None; + } + fn destroy(&mut self) { + self.alive = false; + self.surface.destroy(); + self.region.destroy(); + self.shell.destroy(); + if let Some(buffer) = self.buffer.as_ref() { + buffer.destroy(); + } + self.buffer = None; + } + fn destroy_previous(&mut self) { + if let Some(surface) = self.previous.as_mut() { + surface.destroy(); + } + self.previous = None; + } + fn set_size(&self, width: u32, height: u32) { + self.shell.set_size(width, height); + } + fn damage(&self, report: &[Region]) { + self.surface.attach(self.buffer.as_ref(), 0, 0); + for d in report { + self.surface + .damage(d.x as i32, d.y as i32, d.width as i32, d.height as i32); + } + } + fn attach_buffer(&mut self, buffer: WlBuffer) { + self.buffer = Some(buffer); + } +} + +impl Globals { + fn new() -> Self { + Self { + outputs: Vec::new(), + seats: Vec::new(), + shm: None, + compositor: None, + shell: None, + } + } + pub fn create_shell_surface_from( + &self, + geometry: &dyn Widget, + config: ShellConfig, + previous: Option, + ) -> Option + where + M: 'static, + C: Controller + Clone + 'static, + { + if self.compositor.is_some() { + match config { + ShellConfig::LayerShell(config) => { + if let Some(layer_shell) = self.shell.as_ref() { + let region = self.compositor.as_ref().unwrap().create_region(); + let wl_surface = self.compositor.as_ref().unwrap().create_surface(); + let layer_surface = layer_shell.get_layer_surface( + &wl_surface, + config.output.as_ref(), + config.layer, + config.namespace.clone(), + ); + if let Some(anchor) = &config.anchor { + layer_surface.set_anchor(*anchor); + } + wl_surface.quick_assign(|_, _, _| {}); + layer_surface.set_exclusive_zone(config.exclusive); + layer_surface.set_keyboard_interactivity(config.interactivity); + layer_surface.set_size(geometry.width() as u32, geometry.height() as u32); + layer_surface.set_margin( + config.margin[0], + config.margin[1], + config.margin[2], + config.margin[3], + ); + wl_surface.commit(); + assign_surface::(&layer_surface); + return Some(Surface::new( + wl_surface, + Shell::LayerShell { + surface: layer_surface, + config, + }, + region, + previous, + )); + } + } + } + } + None + } + pub fn create_mempool(&self) -> AutoMemPool { + let attached = Attached::from(self.shm.clone().unwrap()); + AutoMemPool::new(attached).unwrap() + } + pub fn get_outputs(&self) -> Vec { + self.outputs.clone() + } + pub fn get_seats(&self) -> &[Seat] { + &self.seats + } +} + +impl Output { + fn new(output: Main) -> Self { + Output { + width: 0, + height: 0, + scale: 1, + name: String::new(), + output, + } + } +} + +impl Application +where + M: 'static, + C: Controller + Clone + 'static, +{ + pub fn new(pointer: bool) -> (Self, EventLoop<'static, Self>) { + let display = Display::connect_to_env().unwrap(); + let event_queue = display.create_event_queue(); + let attached_display = (*display).clone().attach(event_queue.token()); + + let display_handle = display.clone(); + + let globals = Globals::new(); + + let global_manager = GlobalManager::new_with_cb( + &attached_display, + global_filter!( + [ + ZwlrLayerShellV1, + 1, + |layer_shell: Main, mut application: DispatchData| { + if let Some(application) = application.get::>() { + if let Ok(mut globals) = application.globals.try_borrow_mut() { + globals.shell = Some(layer_shell); + } + } + } + ], + [ + WlShm, + 1, + |shm: Main, mut application: DispatchData| { + shm.quick_assign(|_, _, _| {}); + if let Some(application) = application.get::>() { + if let Ok(mut globals) = application.globals.try_borrow_mut() { + globals.shm = Some(shm); + } + } + } + ], + [ + WlCompositor, + 4, + |compositor: Main, mut application: DispatchData| { + if let Some(application) = application.get::>() { + if let Ok(mut globals) = application.globals.try_borrow_mut() { + globals.compositor = Some(compositor); + } + } + } + ], + [WlSeat, 7, move |seat: Main, _: DispatchData| { + seat.quick_assign(move |wl_seat, event, mut application| match event { + wl_seat::Event::Capabilities { capabilities } => { + if let Some(application) = application.get::>() { + if pointer + && capabilities & Capability::Pointer == Capability::Pointer + { + let pointer = wl_seat.get_pointer(); + assign_pointer::(&pointer); + } + if let Ok(mut globals) = application.globals.try_borrow_mut() { + let mut found = None; + for seat in &mut globals.seats { + if wl_seat.eq(&seat.seat) { + found = Some(()); + seat.capabilities = capabilities; + } + } + if found.is_none() { + globals.seats.push(Seat { + capabilities, + seat: wl_seat, + }); + } + } + } + } + _ => {} + }); + }], + [ + WlOutput, + 3, + |output: Main, _application: DispatchData| { + output.quick_assign(move |wl_output, event, mut application| match event { + wl_output::Event::Geometry { + x: _, + y: _, + physical_width: _, + physical_height: _, + subpixel: _, + make, + model: _, + transform: _, + } => { + if let Some(application) = application.get::>() { + if let Ok(mut globals) = application.globals.try_borrow_mut() { + let mut found = None; + for output in &mut globals.outputs { + if wl_output.eq(&output.output) { + found = Some(()); + output.name = make.clone(); + } + } + if found.is_none() { + let mut output = Output::new(wl_output); + output.name = make; + globals.outputs.push(output); + } + } + } + } + wl_output::Event::Mode { + flags: _, + width, + height, + refresh: _, + } => { + if let Some(application) = application.get::>() { + if let Ok(mut globals) = application.globals.try_borrow_mut() { + let mut found = None; + for output in &mut globals.outputs { + if wl_output.eq(&output.output) { + found = Some(()); + output.width = width; + output.height = height; + } + } + if found.is_none() { + let mut output = Output::new(wl_output); + output.width = width; + output.height = height; + globals.outputs.push(output); + } + } + } + } + wl_output::Event::Scale { factor } => { + if let Some(application) = application.get::>() { + if let Ok(mut globals) = application.globals.try_borrow_mut() { + let mut found = None; + for output in &mut globals.outputs { + if wl_output.eq(&output.output) { + found = Some(()); + output.scale = factor; + } + } + if found.is_none() { + let mut output = Output::new(wl_output); + output.scale = factor; + globals.outputs.push(output); + } + } + } + } + wl_output::Event::Done => {} + _ => {} + }); + } + ] + ), + ); + + let event_loop = EventLoop::try_new().expect("Failed to initialize the event loop!"); + let token = WaylandSource::new(event_queue) + .quick_insert(event_loop.handle()) + .unwrap(); + + let (mut application, mut event_loop) = ( + Application { + display, + globals: Rc::new(RefCell::new(globals)), + global_manager, + inner: Vec::new(), + token, + }, + event_loop, + ); + + for _ in 0..2 { + display_handle.flush().unwrap(); + event_loop.dispatch(None, &mut application).unwrap(); + } + + (application, event_loop) + } + fn get_index(&self, surface: &WlSurface) -> usize { + for i in 0..self.inner.len() { + if self.inner[i].eq(surface) { + return i; + } + } + 0 + } + fn get_application(&mut self, surface: &WlSurface) -> Option<&mut InnerApplication> { + for inner in &mut self.inner { + if inner.eq(surface) { + return Some(inner); + } + } + None + } + pub fn get_global(&self) -> Result, GlobalError> + where + I: Interface + AsRef> + From>, + { + self.global_manager.instantiate_range::(0, 1 << 8) + } + pub fn create_empty_inner_application( + &mut self, + controller: C, + widget: impl Widget + 'static, + handle: LoopHandle<'_, Data>, + cb: impl FnMut(&mut CoreApplication, Event) + 'static, + ) { + let inner_application = + InnerApplication::empty(controller, widget, self.globals.clone(), cb); + self.inner.push(inner_application); + handle.update(&self.token).unwrap(); + } + pub fn create_inner_application_from( + &mut self, + controller: C, + config: ShellConfig, + widget: impl Widget + 'static, + handle: LoopHandle<'_, Data>, + cb: impl FnMut(&mut CoreApplication, Event) + 'static, + ) { + let inner_application = + InnerApplication::new(controller, widget, config, self.globals.clone(), cb); + self.inner.push(inner_application); + handle.update(&self.token).unwrap(); + } + pub fn create_inner_application( + &mut self, + controller: C, + widget: impl Widget + 'static, + handle: LoopHandle<'_, Data>, + cb: impl FnMut(&mut CoreApplication, Event) + 'static, + ) { + let inner_application = + InnerApplication::normal(controller, widget, self.globals.clone(), cb); + self.inner.push(inner_application); + handle.update(&self.token).unwrap(); + } + pub fn run(mut self, event_loop: &mut EventLoop<'static, Self>) { + loop { + self.display.flush().unwrap(); + event_loop.dispatch(None, &mut self).unwrap(); + } + } +} + +impl Deref for InnerApplication +where + C: Controller + Clone + 'static, +{ + type Target = CoreApplication; + fn deref(&self) -> &Self::Target { + &self.core + } +} + +impl DerefMut for InnerApplication +where + C: Controller + Clone + 'static, +{ + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.core + } +} + +impl CoreApplication +where + M: 'static, + C: Controller + Clone + 'static, +{ + pub fn poll(&mut self, ev: Event) -> C { + let mut ctl = self.controller.clone(); + let mut sync_ctx = SyncContext::new(&mut ctl, &mut self.ctx.font_cache); + self.widget.sync(&mut sync_ctx, ev); + ctl + } + pub fn sync(&mut self, ev: Event) -> bool { + let mut sync_ctx = SyncContext::new(&mut self.controller, &mut self.ctx.font_cache); + let mut damage = self.widget.sync(&mut sync_ctx, ev); + while let Ok(msg) = sync_ctx.sync() { + damage = damage.max(self.widget.sync(&mut sync_ctx, Event::Message(&msg))); + } + if damage == Damage::Frame { + if self.ctx.time.is_none() { + self.ctx.time = Some(0); + } + } + damage.is_some() && !self.ctx.pending_cb + } + pub fn destroy(&mut self) { + if let Some(surface) = self.surface.as_mut() { + surface.destroy(); + } + } + pub fn get_layer_surface(&self) -> ZwlrLayerSurfaceV1 { + match &self.surface.as_ref().unwrap().shell { + Shell::LayerShell { config: _, surface } => surface.detach(), + } + } + pub fn is_hidden(&self) -> bool { + if let Some(surface) = self.surface.as_ref() { + return !surface.alive; + } else { + true + } + } + pub fn replace_surface(&mut self) { + if let Some(surface) = self.surface.as_mut() { + surface.destroy(); + surface.alive = true; + match &surface.shell { + Shell::LayerShell { config, surface: _ } => { + self.surface = self.globals.borrow().create_shell_surface_from::( + self.widget.deref(), + ShellConfig::LayerShell(config.clone()), + Some(surface.clone()), + ); + } + } + } else { + self.surface = self.globals.borrow().create_shell_surface_from::( + self.widget.deref(), + ShellConfig::LayerShell(LayerShellConfig::default()), + None, + ); + } + } + pub fn replace_surface_by(&mut self, config: ShellConfig) { + if let Some(surface) = self.surface.as_mut() { + surface.destroy(); + surface.alive = true; + self.surface = self.globals.borrow().create_shell_surface_from::( + self.widget.deref(), + config, + Some(surface.clone()), + ); + } else { + self.surface = self.globals.borrow().create_shell_surface_from::( + self.widget.deref(), + config, + None, + ); + } + } +} + +impl Geometry for InnerApplication +where + C: Controller + Clone + 'static, +{ + fn width(&self) -> f32 { + self.widget.width() + } + fn height(&self) -> f32 { + self.widget.height() + } + fn set_size(&mut self, width: f32, height: f32) -> Result<(), (f32, f32)> { + if let Some(surface) = self.surface.as_ref() { + surface.set_size(width as u32, height as u32); + surface.surface.commit(); + } + Ok(()) + } +} + +impl InnerApplication +where + M: 'static, + C: Controller + Clone + 'static, +{ + pub fn empty( + controller: C, + widget: impl Widget + 'static, + globals: Rc>, + cb: impl FnMut(&mut CoreApplication, Event) + 'static, + ) -> Self { + let mempool = globals.borrow().create_mempool(); + let mut default = InnerApplication { + core: CoreApplication { + controller, + ctx: Context { + pending_cb: false, + time: None, + font_cache: FontCache::new(), + render_node: None, + }, + surface: None, + widget: Box::new(widget), + mempool, + globals, + }, + cb: Box::new(cb), + }; + default.sync(Event::Prepare); + default + } + pub fn normal( + controller: C, + widget: impl Widget + 'static, + globals: Rc>, + cb: impl FnMut(&mut CoreApplication, Event) + 'static, + ) -> Self { + let mempool = globals.borrow().create_mempool(); + let mut default = InnerApplication { + core: CoreApplication { + controller, + ctx: Context { + pending_cb: false, + time: None, + font_cache: FontCache::new(), + render_node: None, + }, + surface: None, + widget: Box::new(widget), + mempool, + globals, + }, + cb: Box::new(cb), + }; + default.sync(Event::Prepare); + default.replace_surface(); + default + } + pub fn new( + controller: C, + widget: impl Widget + 'static, + config: ShellConfig, + globals: Rc>, + cb: impl FnMut(&mut CoreApplication, Event) + 'static, + ) -> Self { + let mempool = globals.borrow().create_mempool(); + let mut new = InnerApplication { + core: CoreApplication { + controller, + ctx: Context { + pending_cb: false, + time: None, + font_cache: FontCache::new(), + render_node: None, + }, + surface: None, + widget: Box::new(widget), + mempool, + globals, + }, + cb: Box::new(cb), + }; + new.sync(Event::Prepare); + new.replace_surface_by(config); + new + } + fn eq(&self, wl_surface: &WlSurface) -> bool { + if let Some(surface) = &self.surface { + return surface.surface.detach().eq(wl_surface); + } + false + } + pub fn roundtrip(&mut self, ev: Event) -> Result { + let width = self.width(); + let height = self.height(); + + // Sending the event to the widget tree + if self.sync(ev) || ev.is_frame() { + // Calling the application´s closure + (self.cb)(&mut self.core, ev); + + if !self.is_hidden() { + let current_width = self.width(); + let current_height = self.height(); + + // Resizing the surface in case the widget changed size + if ev.is_frame() { + self.ctx.render_node = None; + } else if width != current_width || height != current_height { + let _ = self.set_size(current_width, current_height); + return Err(()); + } + + // Creating the render node + let render_node = self.core.widget.create_node(0., 0.); + + self.ctx.pending_cb = true; + + return Ok(render_node); + } + } else { + // Calling the application´s closure + (self.cb)(&mut self.core, ev); + } + + Err(()) + } + fn render(&mut self, time: u32, recent_node: RenderNode) { + let width = recent_node.width(); + let height = recent_node.height(); + if Some(time).ne(&self.core.ctx.time) || time == 0 { + if let Ok((buffer, wl_buffer)) = + Buffer::new(&mut self.core.mempool, width as i32, height as i32) + { + let mut v = Vec::new(); + let mut ctx = + DrawContext::new(buffer.backend, &mut self.core.ctx.font_cache, &mut v); + if let Some(render_node) = self.core.ctx.render_node.as_mut() { + if let Err(region) = render_node.draw_merge( + recent_node, + &mut ctx, + &Instruction::empty(0., 0., width, height), + None, + ) { + ctx.damage_region(&Background::Transparent, region, false); + } + } else { + ctx.damage_region( + &Background::Transparent, + Region::new(0., 0., width, height), + false, + ); + recent_node.render(&mut ctx, None); + self.core.ctx.render_node = Some(recent_node); + } + self.core.ctx.pending_cb = false; + if let Some(surface) = self.core.surface.as_mut() { + surface.attach_buffer(wl_buffer); + surface.damage(&v); + surface.commit(); + if let Some(_) = self.core.ctx.time { + self.core.ctx.time = Some(time); + frame_callback::(time, surface.surface.clone()); + } + } + } + } + } + pub fn callback(&mut self, ev: Event) { + if self.ctx.time.is_none() || ev.is_cb() { + if let Ok(render_node) = self.roundtrip(ev) { + if let Some(surface) = self.surface.as_ref() { + draw_callback::(&surface.surface, render_node); + } + } + } else { + let width = self.width(); + let height = self.height(); + + self.sync(ev); + + let current_width = self.width(); + let current_height = self.height(); + + // Resizing the surface in case the widget changed size + if width != current_width || height != current_height { + let _ = self.set_size(current_width, current_height); + } + } + } +} + +fn frame_callback(time: u32, surface: Main) +where + M: 'static, + C: Controller + Clone + 'static, +{ + let h = surface.detach(); + surface + .frame() + .quick_assign(move |_, event, mut application| match event { + wl_callback::Event::Done { callback_data } => { + let timeout = (callback_data - time).min(50); + if let Some(application) = application.get::>() { + if let Some(inner_application) = application.get_application(&h) { + inner_application.ctx.time = None; + inner_application.callback(Event::Callback(timeout)); + } + } + } + _ => {} + }); + surface.commit(); +} + +fn draw_callback(surface: &Main, mut recent_node: RenderNode) +where + M: 'static, + C: Controller + Clone + 'static, +{ + let h = surface.detach(); + surface + .frame() + .quick_assign(move |_, event, mut application| match event { + wl_callback::Event::Done { callback_data } => { + if let Some(application) = application.get::>() { + let inner_application = application.get_application(&h).unwrap(); + inner_application.render(callback_data, std::mem::take(&mut recent_node)); + } + } + _ => {} + }); + surface.commit(); +} + +impl From for Modifiers { + fn from(modifer_state: ModifiersState) -> Modifiers { + Modifiers { + ctrl: modifer_state.ctrl, + alt: modifer_state.alt, + shift: modifer_state.shift, + caps_lock: modifer_state.caps_lock, + logo: modifer_state.logo, + num_lock: modifer_state.num_lock, + } + } +} + +fn assign_pointer(pointer: &Main) +where + M: 'static, + C: Controller + Clone + 'static, +{ + let mut index = 0; + let mut input = Pointer::Enter; + let (mut x, mut y) = (0., 0.); + pointer.quick_assign(move |_, event, mut inner| match event { + wl_pointer::Event::Leave { serial: _, surface } => { + input = Pointer::Leave; + if let Some(application) = inner.get::>() { + if let Some(inner_application) = application.get_application(&surface) { + inner_application.callback(Event::Pointer(x as f32, y as f32, input)); + } + } + } + wl_pointer::Event::Button { + serial: _, + time, + button, + state, + } => { + input = Pointer::MouseClick { + time, + button: MouseButton::new(button), + pressed: state == wl_pointer::ButtonState::Pressed, + }; + } + wl_pointer::Event::Frame => { + if let Some(application) = inner.get::>() { + let inner_application = application.inner.get_mut(index).unwrap(); + inner_application.callback(Event::Pointer(x as f32, y as f32, input)); + } + } + wl_pointer::Event::Axis { + time: _, + axis, + value, + } => { + input = Pointer::Scroll { + orientation: match axis { + wl_pointer::Axis::VerticalScroll => Orientation::Vertical, + wl_pointer::Axis::HorizontalScroll => Orientation::Horizontal, + _ => Orientation::Vertical, + }, + value: value as f32, + } + } + wl_pointer::Event::Enter { + serial: _, + surface, + surface_x, + surface_y, + } => { + if let Some(application) = inner.get::>() { + x = surface_x; + y = surface_y; + index = application.get_index(&surface); + } + } + wl_pointer::Event::Motion { + time: _, + surface_x, + surface_y, + } => { + x = surface_x; + y = surface_y; + input = Pointer::Hover; + } + _ => {} + }); +} + +fn assign_surface(shell: &Main) +where + M: 'static, + C: Controller + Clone + 'static, +{ + shell.quick_assign(move |shell, event, mut inner| match event { + zwlr_layer_surface_v1::Event::Configure { + serial, + width, + height, + } => { + shell.ack_configure(serial); + println!("\nCONFIGURE - {} : {} X {}\n", serial, width, height); + if let Some(application) = inner.get::>() { + for inner_application in &mut application.inner { + if let Some(app_surface) = inner_application.surface.as_mut() { + match &app_surface.shell { + Shell::LayerShell { config: _, surface } => { + if shell.eq(surface) { + app_surface.destroy_previous(); + let _ = inner_application + .widget + .set_size(width as f32, height as f32); + if inner_application.ctx.pending_cb { + if let Ok(render_node) = + inner_application.roundtrip(Event::Frame) + { + draw_callback::( + &inner_application + .surface + .as_ref() + .unwrap() + .surface, + render_node, + ); + } + } else { + if let Ok(render_node) = + inner_application.roundtrip(Event::Frame) + { + inner_application.render(0, render_node); + } + } + } + } + } + } + } + } + } + _ => unreachable!(), + }); +} diff --git a/tests/wcag-compliance/package-lock.json b/tests/wcag-compliance/package-lock.json new file mode 100644 index 0000000..e0fc0c6 --- /dev/null +++ b/tests/wcag-compliance/package-lock.json @@ -0,0 +1,326 @@ +{ + "name": "wcag-compliance", + "version": "0.1.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "wcag-compliance", + "version": "0.1.0", + "license": "MIT", + "dependencies": { + "color-contrast-checker": "^2.1.0", + "execa": "^6.1.0" + } + }, + "node_modules/color-contrast-checker": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/color-contrast-checker/-/color-contrast-checker-2.1.0.tgz", + "integrity": "sha512-6Y0aIEej3pwZTVlicIqVzhO6T4izDWouaIXnYoDdTuFFAMQ9nnN0dgHNP9J94jRnH6asjPq1/wzUKxwoNbWtRQ==" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/execa": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-6.1.0.tgz", + "integrity": "sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^3.0.1", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/human-signals": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-3.0.1.tgz", + "integrity": "sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==", + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + } + }, + "dependencies": { + "color-contrast-checker": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/color-contrast-checker/-/color-contrast-checker-2.1.0.tgz", + "integrity": "sha512-6Y0aIEej3pwZTVlicIqVzhO6T4izDWouaIXnYoDdTuFFAMQ9nnN0dgHNP9J94jRnH6asjPq1/wzUKxwoNbWtRQ==" + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "execa": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-6.1.0.tgz", + "integrity": "sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==", + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^3.0.1", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + } + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" + }, + "human-signals": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-3.0.1.tgz", + "integrity": "sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==" + }, + "is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==" + }, + "npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "requires": { + "path-key": "^4.0.0" + }, + "dependencies": { + "path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==" + } + } + }, + "onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "requires": { + "mimic-fn": "^4.0.0" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==" + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + } + } +} diff --git a/tests/wcag-compliance/package.json b/tests/wcag-compliance/package.json new file mode 100644 index 0000000..a77038f --- /dev/null +++ b/tests/wcag-compliance/package.json @@ -0,0 +1,32 @@ +{ + "name": "wcag-compliance", + "version": "0.1.0", + "description": "An accessibility checker tool for validating the color contrast of Catppuccin's palettes based on WCAG 2.0 and WCAG 2.1 standards", + "main": "./src/index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/catppuccin/catppuccin.git" + }, + "keywords": [ + "wcag", + "wcag-aa", + "color", + "contrast", + "verifier", + "accessibility", + "standard" + ], + "author": "Pocco81", + "license": "MIT", + "bugs": { + "url": "https://github.com/catppuccin/catppuccin/issues" + }, + "homepage": "https://github.com/catppuccin/catppuccin#readme", + "dependencies": { + "color-contrast-checker": "^2.1.0", + "execa": "^6.1.0" + } +} diff --git a/tests/wcag-compliance/src/index.js b/tests/wcag-compliance/src/index.js new file mode 100644 index 0000000..1d5ac3c --- /dev/null +++ b/tests/wcag-compliance/src/index.js @@ -0,0 +1,110 @@ +// import { platform } from 'os'; + +const os = require('os') +const execa = require("execa") +const ColorContrastChecker = require('color-contrast-checker') + +const {stdout} = execa('echo', ['unicorns']); +console.log(stdout); + + +function get_git_root() { + try { + let cmd = '' + + if (platform() === 'win32') { + cmd = `git rev-parse --show-toplevel ` + } else { + cmd = `(git rev-parse --show-toplevel )` + } + + const { stdout } = execa.shellSync(cmd) + + return stdout + } catch (e) { + return '' + } +} + +// console.log(execa.shellSync("echo 'hello'")) + +// /* File System Object */ +// var fs = require('fs'); +// +// pr + +/* Read File */ +// fs.readFile(get_git_root() + "palettes.json", bar) + +function bar (err, data) + { + /* If an error exists, show it, otherwise show the file */ + err ? Function("error","throw error")(err) : console.log(JSON.stringify(data) ); + }; + +// const fs = require("fs") +// + +// var ccc = new ColorContrastChecker(); +// var palettes = fs.readFileSync('../../palettes.json', 'utf8'); +// var palettes = fs.readFile('test.json', 'utf8'); + +// fs.readFile("../../../palettes.json", function(text){ +// palettes = text.split("\n") +// }); + +// for (var key in palettes) { +// console.log(key) +// if (ccc.isLevelAA(background, rainbow[key], 14)) { +// console.log(" •" + key + ": ✅"); +// } else { +// console.log(" •" + key + ": ❌"); +// } +// } + +// const background = "#1E1D2F" +// var rainbow = { +// rosewater: "#F5E0DC", +// flamingo: "#F2CDCD", +// mauve: "#DDB6F2", +// pink: "#F5C2E7", +// red: "#F28FAD", +// maroon: "#E8A2AF", +// peach: "#F8BD96", +// yellow: "#FAE3B0", +// green: "#ABE9B3", +// blue: "#96CDFB", +// sky: "#89DCEB", +// teal: "#B5E8E0", +// lavender: "#C9CBFF", +// white: "#D9E0EE", +// gray2: "#C3BAC6", +// gray1: "#988BA2", +// gray0: "#6E6C7E", +// black4: "#575268", +// black3: "#302D41", +// black2: "#1E1D2F", +// black1: "#1A1823", +// black0: "#131020", +// } +// +// console.log("\t---- WCAG conformance level AA on Catppuccin ----\n") +// +// for (var key in rainbow) { +// if (ccc.isLevelAA(background, rainbow[key], 14)) { +// console.log(" •" + key + ": ✅"); +// } else { +// console.log(" •" + key + ": ❌"); +// } +// } + +// var color1 = "#FFFFFF"; +// var color2 = "#000000"; +// +// if (ccc.isLevelAA(color1, color2, 14)) { +// console.log("Valid Level AA"); +// } else { +// console.log("Invalid Contrast"); +// } +// +// console.log("Hello world!") diff --git a/tests/wcag-compliance/test.json b/tests/wcag-compliance/test.json new file mode 100644 index 0000000..df68a9c --- /dev/null +++ b/tests/wcag-compliance/test.json @@ -0,0 +1,3 @@ +{ + "hello": "world" +}