Skip to content

Conversation

Caellian
Copy link
Collaborator

@Caellian Caellian commented Apr 1, 2020

General description

This PR adds a lua_mouse_hook to Lua config script as suggested in issue #938. I remembered wanting click events in conky before, and I wanted them again, this time I understood C & C++ a bit more so I decided to implement it.

Instead of defining 6 different hooks, I opted for creating just one and passing the relevant data in a table as an argument. Hopefully, this table stuff doesn't break any guidelines. This also means that lua_mouse_hook is not adjustable by context (can't pass custom arguments), but mouse action handling is generally very case-specific so that shouldn't be a problem.

I added a custom build flag which means this can be turned off completely if not wanted. There is some code outside of #ifdef, but it will be optimized away by most compilers as it's very trivial (declaring a variable that never changes). I can wrap it if needed.

List of events handled by the lua_mouse_hook

  • button_down - called when a mouse button is clicked
  • button_up - called when a mouse button is released
  • button_scroll - called on scroll action (X handles it the same way as button clicks)
  • mouse_move - called when the pointer is being dragged across conky window
  • mouse_enter - called when the pointer enters conky window
  • mouse_leave - called when the pointer leaves conky window

Users are supposed to handle the events by reading event.type string and putting logic into appropriate if-clauses - where event is the name of the first (and only) function argument and value is one of the event names from the above list. If there is an error with code, event.type == "err".

Users can return true to signal conky that the event has been "consumed" and shouldn't be passed to the root window. If nothing is returned, false is assumed which pushes the event through.

Depending on event type, different data is appended to the event table:

Move event

event table has following keys:

  • x - window-relative cursor x position (int)
  • y - window-relative cursor y position (int)
  • x_abs - display-relative cursor x position (int)
  • y_abs - display-relative cursor y position (int)
  • time - time in ms provided by Xlib (ulong)

Button press and release event

event table has all move event entries and additionally:

  • mods - table of buttons and modifier keys being held (name to bool map)
    • shift
    • lock
    • control
    • mod1
    • num_lock
    • mod3
    • mod4
    • mod5
    • mouse_left
    • mouse_right
    • mouse_middle
    • scroll_up
    • scroll_down
  • button - number of the button being pressed/released (int)
    • Left button: 1
    • Right button: 2
    • Middle button: 3

Scroll event

Same as button press and release event but instead of the button field, a direction field is provided, holding either up or down string value - depending on scroll direction.

Mouse enter/leave event

Called when the mouse enters or leaves conky window area. This might be useful for "turning off" "buttons" when the user drags their mouse outside the window while holding the mouse button pressed. event fields are the same as in the movement event.

Problems

  • When own_window_type property is set to desktop or override, no mouse_events are being handled as making any changes to events root window listens to caused a crash while I was initially trying to get the code to work. This sadly means that users with some WMs/DEs won't be able to use mouse events at all (for instance me, bspwm). I also tested this on XFCE where all other mounting options worked fine (again, didn't modify the root window). On bspwm anything other than desktop and override make conky render as a window. Sudo didn't prevent crashing.
  • I wasn't able to test mods scroll_up and scroll_down, they might represent 2 extra buttons on some mice but I believe scrolling is more likely as they're named the same as scrolling actions in Xlib docs. I don't have a mouse with 5 buttons, so I can't test it as scrolling is really hard to capture from my experience.

Screenshots

Sadly I haven't gotten into Cairo yet, so all of these are pretty technical.

Imgur post containing images below.

Image 1
Image 2
Image 3

Errors you see in VSCode navigation are because my environment isn't configured, wouldn't be able to compile and run it if they were actual errors.

Lua script using all provided options

I used this script for the above images. I fixed it a bit here because the 'mods' section had the wrong indentation for first item (extra '\t').

function echo (what)
    os.execute("echo -n '" .. what .. "'")
end

local function print_mods (mods)
    echo("mods:\n")
    for k,v in pairs(mods) do
        if (v) then
            echo("\t- " .. k .. "\n")
        end
    end
end

function conky_mouse (event)
    if (event.type ~= "mouse_move") then
        echo("type: " .. event.type .. ",\n")
    end
    
    if (event.type == "button_down") then
        echo("x: " .. tostring(event.x) .. ", ")
        echo("y: " .. tostring(event.y) .. ", ")
        echo("x_abs: " .. tostring(event.x_abs) .. ", ")
        echo("y_abs: " .. tostring(event.y_abs) .. ",\n")
        echo("time: " .. tostring(event.time) .. ",\n")
        print_mods(event.mods)
        echo("button: " .. tostring(event.button) .. "\n")
    elseif (event.type == "button_up") then
        echo("x: " .. tostring(event.x) .. ", ")
        echo("y: " .. tostring(event.y) .. ", ")
        echo("x_abs: " .. tostring(event.x_abs) .. ", ")
        echo("y_abs: " .. tostring(event.y_abs) .. ",\n")
        echo("time: " .. tostring(event.time) .. "\n")
        print_mods(event.mods)
        echo("button: " .. tostring(event.button) .. "\n")
    elseif (event.type == "mouse_scroll") then
        echo("x: " .. tostring(event.x) .. ", ")
        echo("y: " .. tostring(event.y) .. ", ")
        echo("x_abs: " .. tostring(event.x_abs) .. ", ")
        echo("y_abs: " .. tostring(event.y_abs) .. ",\n")
        echo("time: " .. tostring(event.time) .. ",\n")
        print_mods(event.mods)
        echo("direction: " .. tostring(event.direction) .. "\n")
    elseif (event.type == "mouse_move") then
        -- This will spam out everything else
        echo("x: " .. tostring(event.x) .. ", ")
        echo("y: " .. tostring(event.y) .. ", ")
        echo("x_abs: " .. tostring(event.x_abs) .. ", ")
        echo("y_abs: " .. tostring(event.y_abs) .. ",\n")
        echo("time: " .. tostring(event.time) .. ",\n")
        print_mods(event.mods)
    elseif (event.type == "mouse_enter") then
        echo("x: " .. tostring(event.x) .. ", ")
        echo("y: " .. tostring(event.y) .. ", ")
        echo("x_abs: " .. tostring(event.x_abs) .. ", ")
        echo("y_abs: " .. tostring(event.y_abs) .. ",\n")
        echo("time: " .. tostring(event.time) .. "\n")
    elseif (event.type == "mouse_leave") then
        echo("x: " .. tostring(event.x) .. ", ")
        echo("y: " .. tostring(event.y) .. ", ")
        echo("x_abs: " .. tostring(event.x_abs) .. ", ")
        echo("y_abs: " .. tostring(event.y_abs) .. ",\n")
        echo("time: " .. tostring(event.time) .. "\n")
    elseif (event.type == "err") then
        echo("This currently can't happen.")
    end
    return false
end

Notes

I have a few additional thoughts and concerns:

  • Mouse movement event is being called very frequently, I'm not familiar with Lua enough to know for sure whether this would slow conky down or not. This event should maybe be separated into it's own hook just so that users have the option of ignoring only that event. Or maybe a mask option can be provided to select exactly the events they want to receive. Other events don't really need to be controlled from C++ code as they aren't being called that often (on average even less than some of the other hooks).
  • Keyboard events can easily be added in a similar fashion to these. Someone is likely to ask for those too. But they have the problem of requiring conky to capture ALL keyboard events, detect mouse position, query entire window tree form X, calculate where the mouse is and then finally handle them or pass them through to the appropriate window at which point conky becomes more like a WM than what it's supposed to be. I suggest they're not added.
  • In screenshots above conky is being displayed over VSCode because it doesn't work on bspwm unless it's drawn on root window (which disables mouse events). I noticed it captures all events as a normal window and doesn't pass them through. Also, upon grabbing the pointer it also seems to grab the keyboard or something because I had to switch to another desktop and go back to be able to type anything into VSCode. SIGTERM keybind seemed to send it to VSCode, so I know it was focused. This might be a bug. Also, it's worth considering the possibility of drawing conky over the windows instead of below.

@Caellian
Copy link
Collaborator Author

Caellian commented Apr 1, 2020

The last commit isn't verified because I did several amends. (Should I squash all of them?)

Regarding tests - I didn't see a point in writing them as CIs can't generate mouse events. I thoroughly tested added behaviour with Lua scripts so I know it works.

Also wanted to mention that I added a lot of code for Lua table construction, but kept it in mouse_events.cc as it's only being used there so that it's excluded from conky. I'd be happy to add it to the rest of the code in llua.cc if that's prefered, but in that case, I'd like to extend it a tiny bit to support more types and make the table into its own object.

I noticed Wayland support is being worked on. I'd be willing to implement the same functionality for Wayland too when it gets added. Holding off this PR until #664 is done might be a good idea.

@Slimaure
Copy link

I know this is not an answer but you can use this project that allows you to use conky clicks https://github.com/netikras/ConkyClicky

@Caellian
Copy link
Collaborator Author

I know this is not an answer but you can use this project that allows you to use conky clicks https://github.com/netikras/ConkyClicky

That makes it very hard to make "components" react to mouse clicks. I mean, you can store click info in a file and then read it form rendering calls, but that's complicating things a lot an slower due to file IO. Also, you'd have to manually map all components, this PR allows you to run a custom conky instance for buttons which makes click detection effortless in LUA. Mapping absolute mouse positions is a bad idea as you'll have to redo your job every time you change something in your layout.

Another thing worth mentioning is, down the line, if this gets merged and the concept of components get added to conky, it would allow adding buttons without manual mapping or running them in separate instances.

Base automatically changed from master to main January 24, 2021 14:18
@su8 su8 mentioned this pull request Feb 10, 2021
@su8 su8 added enhancement suggests alteration of existing functionality to better support different use cases good first issue straightforward enough for first-time contributors to be able to implement themselves question issue where reporter seeks information about conky or a problem they encounter while running it labels Feb 22, 2021
@mmuman mmuman mentioned this pull request Oct 25, 2021
ulukyn added a commit to ulukyn/conky that referenced this pull request Aug 8, 2022
Test of  Added mouse events to conky brndnmtthws#955
@mmuman
Copy link
Collaborator

mmuman commented Sep 12, 2022

Since #664 has been merged in, you'll want to rebase this work. I tried to minimize the differences when moving code around, so you should be able to find the X11 stuff that was in conky.cc in display-x11.cc. You may want to first rebase against the commit preceding the change, 714e3a5, to make sure you don't introduce any regression, then rebase over main.

Reading through your code I see some X structs passed around that shouldn't be, but we can clean that later with the rest anyway.

@Caellian
Copy link
Collaborator Author

I'll take a look at the diff to recall my changes. I think I'll start from scratch with prev code as reference. From what I remember, the only reason it took me as long as it did to implement was figuring out X11, lua bindings and conky code. I'll rebase sometime soon I hope. :)

@Caellian Caellian closed this Dec 13, 2022
@netlify
Copy link

netlify bot commented Dec 13, 2022

Deploy Preview for conkyweb canceled.

Name Link
🔨 Latest commit 7599a76
🔍 Latest deploy log https://app.netlify.com/sites/conkyweb/deploys/63b1b75e327cba0008d6621e

@Caellian
Copy link
Collaborator Author

Sorry, I separated changes onto another branch and fastforwarded master ytd so GitHub auto closed the PR. I'm almost done and will reopen this PR in a few days once I push to my fork.

It was pretty straightforward to update the code. I also noticed that I might've caused issues with mouse events for root by mishandling some X events so I'd like to debug that.

Thanks to mmuman's work I noticed ncurses and would like to check how conky interfaces with it to see whether adding mouse events to ncurses display would also make sense and be straightforward enough.

Signed-off-by: Tin Svagelj <tin.svagelj@live.com>
@Caellian
Copy link
Collaborator Author

Caellian commented Dec 30, 2022

Fixed a use after free error I previously introduced.

Cleaned up XSelectInput call in init_window so it's easier to modify, resulting binary should stay the same but it's more readable now.
Previous code was changing input event mask twice and on second change wasn't checking the window type.
I also removed the check for TYPE_OVERRIDE windows and allowed mouse events on those as override windows really shouldn't have issues with allowing mouse events so I suspect it was a WM specific crash.

Decided to forgo adding mouse events to ncurses for now.

@Caellian Caellian reopened this Dec 30, 2022
@github-actions github-actions bot added documentation suggests documentation changes or improvements sources PR modifies project sources labels Dec 30, 2022
@brndnmtthws brndnmtthws removed question issue where reporter seeks information about conky or a problem they encounter while running it good first issue straightforward enough for first-time contributors to be able to implement themselves labels Jan 1, 2023
Signed-off-by: Tin Svagelj <tin.svagelj@live.com>
Because func was previously char* I forgot to update NORM_ERR function
argument to `func.c_str()` not that it's std::string.

Previously func was pointing to std::string memory that was freed at
assignment.

Signed-off-by: Tin Svagelj <tin.svagelj@live.com>
@brndnmtthws brndnmtthws merged commit 7fbdfbd into brndnmtthws:main Jan 1, 2023
@Caellian Caellian changed the title Added mouse events to conky Add mouse events for X11 Jan 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation suggests documentation changes or improvements enhancement suggests alteration of existing functionality to better support different use cases sources PR modifies project sources
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants