From 2fbe02f7cbb620194669b2eebc1c77a7100195af Mon Sep 17 00:00:00 2001 From: Jiri Kalvoda <jirikalvoda@kam.mff.cuni.cz> Date: Fri, 12 Aug 2022 15:28:13 +0200 Subject: [PATCH] Add OnClick --- Program.cs | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 120 insertions(+), 6 deletions(-) diff --git a/Program.cs b/Program.cs index 807628a..457b63d 100644 --- a/Program.cs +++ b/Program.cs @@ -47,6 +47,17 @@ static class POSIX public static int SIGUSR1 = 10; public static int EEXIST = 17; public static int ERRNO { get => Marshal.GetLastPInvokeError();} + public static void Bash(string cmd) + { + var process = new Process(); + process.StartInfo.FileName = "bash"; + process.StartInfo.Arguments = ""; + process.StartInfo.RedirectStandardInput = true; + process.Start(); + TextWriter stdin = process.StandardInput; + stdin.Write(cmd); + stdin.Close(); + } } static class ProcesExtended @@ -97,6 +108,33 @@ enum Markup Pango } +record Coordinates( + int X, + int Y + ); + +enum MouseButton +{ + Left, + Right, + Middle +} + +[Flags] +enum Modifiers +{ + Shift=1, + Ctrl=2 +} + +record ClickEvent( + Coordinates Relative, // relative_x, relative_y + Coordinates Size, // width, height + MouseButton Button, + Coordinates? Absolute = null, // x, y + Coordinates? Output = null, // output_x, output_y + Modifiers Modifiers = 0 + ); record Block( string Text, @@ -114,7 +152,8 @@ record Block( bool Urgent = false, bool Separator = true, int? SeparatorBlockWidth=null, - Markup Markup = Markup.None + Markup Markup = Markup.None, + Action<ClickEvent>? OnClick=null ); @@ -417,14 +456,82 @@ class StatusBarTerminal: StatusBarPlainText } class StatusBarI3: RootStatusBar { - public StatusBarI3(FileInfo configFile):base(configFile){} + Thread? inputThread; + record HistoryElement( + long time_ms, + long id, + IEnumerable<Block> data + ); + Queue<HistoryElement> history = new(); // for finding correct lambda in inputThread + int outputCounter = 0; + public StatusBarI3(FileInfo configFile, bool doInput):base(configFile) + { + Console.Error.Flush(); + if(doInput) + { + inputThread = new Thread(this.inputThreadFunc); + inputThread.IsBackground = true; + inputThread.Start(); + } + } + void inputThreadFunc() + { + Console.ReadLine(); // read "[" + while(true) + { + #pragma warning disable 8602 + string? line = Console.ReadLine(); + if(line == null) throw new Exception("I3bar close input"); + if(line[0] == ',') line = line[1..]; + + JsonObject json = JsonObject.Parse(line).AsObject(); + MouseButton button; + int jsonButton = json["button"].AsValue().GetValue<int>(); + if(jsonButton == 1) button = MouseButton.Left; else + if(jsonButton == 2) button = MouseButton.Middle; else + if(jsonButton == 3) button = MouseButton.Left; else + break; + var ev = new ClickEvent( + Relative: new Coordinates(json["relative_x"].AsValue().GetValue<int>(), json["relative_y"].AsValue().GetValue<int>()), + Size: new Coordinates(json["height"].AsValue().GetValue<int>(), json["width"].AsValue().GetValue<int>()), + Button: button + ); + string name = json["name"].AsValue().GetValue<string>(); + int outputId = int.Parse(name.Split(".")[0]); + int blockId = int.Parse(name.Split(".")[1]); + HistoryElement currentBar; + lock(history) + { + while(history.Count > 0 && history.Peek().id < outputId) + history.Dequeue(); + if(history.Count <= 0) break; + currentBar = history.Peek(); + } + var block = currentBar.data.ElementAt(blockId); + if(block.OnClick != null) + block.OnClick(ev); + #pragma warning restore 8602 + } + } override protected void initOutput(TextWriter w) { - w.WriteLine("{\"version\":1}"); + if(inputThread == null) + w.WriteLine("{\"version\":1}"); + else + w.WriteLine("{\"version\":1, \"click_events\": true }"); w.WriteLine("[{}"); } override protected void format(TextWriter w, List<Block> elements) { + if(inputThread != null) + { + lock(history) + { + while(history.Count > 0 && history.Peek().time_ms < Environment.TickCount64 - 1000) + history.Dequeue(); + history.Enqueue(new HistoryElement(Environment.TickCount64, outputCounter, elements)); + } + } JsonNode? intStringUnion(int? _int, string? _string) { JsonNode? n = null; @@ -432,7 +539,9 @@ class StatusBarI3: RootStatusBar if(_string != null) n = _string; return n; } + int i = 0; var json = new JsonArray((from e in elements select new JsonObject(){ + ["name"] = $"{outputCounter}.{i++}", ["full_text"] = e.Text, ["short_text"] = e.ShortText, ["color"] = e.Color?.ToHex(), @@ -453,6 +562,7 @@ class StatusBarI3: RootStatusBar opt.DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull; w.Write(","); w.WriteLine(json.ToJsonString(opt)); + outputCounter++; } } @@ -504,10 +614,14 @@ along with this program. If not, see <https://www.gnu.org/licenses/>."); var c_i3 = new Command("i3", "Comunicate with i3bar."); rootCommand.Add(c_i3); - c_i3.SetHandler(async (config) => + var c_i3_input = new Option<bool> + ("--input", "Read mouse clicks."); + c_i3_input.AddAlias("-i"); + c_i3.Add(c_i3_input); + c_i3.SetHandler(async (config, input) => { - (new StatusBarI3(config)).Run(Console.Out); - }, configOption); + (new StatusBarI3(config, input)).Run(Console.Out); + }, configOption, c_i3_input); rootCommand.Invoke(args); return 0; -- GitLab