Skip to content
This repository was archived by the owner on Jan 11, 2020. It is now read-only.

Awesome wm/awesome and class fixups drawin impl#456

Merged
Timidger merged 42 commits into
masterfrom
awesomeWM/awesome_and_class_fixups_drawin_impl
Jan 4, 2018
Merged

Awesome wm/awesome and class fixups drawin impl#456
Timidger merged 42 commits into
masterfrom
awesomeWM/awesome_and_class_fixups_drawin_impl

Conversation

@Timidger
Copy link
Copy Markdown
Member

@Timidger Timidger commented Dec 10, 2017

This has some crucial changes needed for AwesomeWM compatibility. There are also some additions for drawin, drawable, and others etc. but they are incomplete. I'm merging them anyways so I don't have to duplicate the effort later but those APIs should still be considered incomplete.

With these changes the rc.lua no longer properly runs (it fails trying to access a layoutbox property). I will attempt to fix that however because I want the master rc.lua always to be usable for testing purposes.

Comment thread config/rc.lua Outdated
title = "Oops, there were errors during startup!",
text = awesome.startup_errors })
end
naughty.notify({ preset = naughty.config.presets.critical,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you just duplicate this by accident??

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I put this in here to test notifications. I was hoping to get them working when I first started on this PR (notice a lot of the changes relate to adding cairo and xcb stuff to awesome bindings). Alas, no such luck. I'll remove this as this is a debug thing I forgot to remove.

I'm going to review this again properly and merge it in soon (tm). There's some changes here that are fairly critical (fix a lot of issues with Awesome classes that will be needed down the line. Plus it shows how to connect and use xcb)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be great! I was going to base the wallpaper work off of this branch anyway!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll work on cleaning this up and merging it in today.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok "today" was a bit optimistic. Going to try to finish this up ASAP, but you should still base your work off this branch.

We weren't wrapping it in a table, like is expected of in Lua because
Awesome does it.

HOWEVER, they use lua_setuservalue. We don't have access to that, so we
just put it in a table. Need to double check this does the right
thing...because this doesn't seem right :(
I really need to implement these properly
By movinging it before hand, xcb can talk to xwayland and get e.g xkb
information.
Also adds more safety checks for unsafely getting the group names
Even in the error case we ensure that the connection isn't closed.
Because lua doesn't have the screen, which it gets from the client or
from the mouse. So I need to implement it for mouse because that's the
easiest way. yay.
The way it's done is crazy, but basically mouse has a reference to the
screen table and then if screen global gets a screen instance we just
return it. Again, it's really crazy
I was saving it on the instance of the class instead of the class
itself, which makes sense in retrospect
You should set it on the class instead
Took way too long because the C code is inscrutable
@Timidger Timidger force-pushed the awesomeWM/awesome_and_class_fixups_drawin_impl branch from 0eaafcb to bdffbbd Compare December 27, 2017 18:45
@Timidger Timidger force-pushed the awesomeWM/awesome_and_class_fixups_drawin_impl branch from 67659b2 to dc5a560 Compare December 28, 2017 01:11
This is to get around issues with testing...also it's technically
correct, as we don't have hard dependency on xwayland _quite_ yet
@Timidger
Copy link
Copy Markdown
Member Author

Currently we are doing the objects allocation wrong here. We are allocating the tables weirdly, and we need to be 1-1 on what Awesome does. Once that is setup properly, writing the APIs will be easy enough that it can be done in parallel.

cc @psychon We talked a bit about this on the gitter channel, but I know it's hard to read this Rust when you're not familiar with it. Any quick run-down on how the objects (e.g like a client) should look on the Lua side? Right now this current PR seems to allocate them fine since we are running it against the default rc.lua and it's accessing the objects fine but it's still almost certainly not correct.

@psychon
Copy link
Copy Markdown
Contributor

psychon commented Dec 29, 2017

Any quick run-down on how the objects (e.g like a client) should look on the Lua side?

Well... it's a userdata with some object-specific fields, some of them read-only. The general "stuff" is:

  • the signal API (add_signal, connect_signal, disconnect_signal, emit_signal),
  • a valid field that is always true and becomes false after the object's __gc metamethod runs (implemented by setting a different metatable, all other indices cause an error to be thrown),
  • a data table that the C code saves but does not otherwise care about; this is used to e.g. save the floating state of a client and was needed so that Lua's garbage collector knows that this table is only kept alive by the client and can be garbage collected together with it (previously some magic with weak tables were used and if you did awful.client.property.set(c, "foo", c) this magic would break down and the client object would be un-garbage-collectable).

Each object has a class, e.g. a client belongs to the client global exposed by awesome. This has some fields, too:

  • the signal API again; one thing that is easy to miss is that all signals on objects are also emitted on its class, e.g. doing c:emit_signal("foo", true) calls all callbacks for "foo" on this client with argument true and also all callbacks on the client global with arguments c, true,
  • a counter of "how many instances of this class do currently exist?" as .instances (this is a function returning the number, I think); this is not used anywhere, so can be left out, but it still exists and is sometimes useful in debugging leaks ("oh, the number of live client objects is way too high"),
  • A special "callback registering" API set_index_miss_handler and set_newindex_miss_handler; I think this gets the same arguments as the corresponding metafunctions and is used in Lua to implement some additional magic on individual objects, not the class itself (e.g. makes c.floating return c.data.floating, but is also used to implement read-only properties etc; internally this calls getter and setter functions) (implemented e.g. in lib/awful/client.lua by calling gears.object.properties(client, { getter_class = awful.client.object, setter_class = awful.client.object, getter_fallback = client.property.get, setter_fallback = client.property.set }).

I'll try to give your rust code a close look later.

Comment thread src/awesome/drawable.rs Outdated
pub surface: Option<ImageSurface>,
geo: Geometry,
refreshed: bool,
// TODO Refresh callback
Copy link
Copy Markdown
Contributor

@psychon psychon Dec 29, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are using an ImageSurface which allocates its own memory to draw to; awesome uses a XcbSurface drawing to the pixmap. Thus, you don't need a pixmap member here, it's just the "target" for drawing in awesome.

The refresh callback is just an internal implementation detail. For drawins it copies from the drawable's pixmap to the screen and for titlebars it does basically the same. However, for your case it should be enough to just always copy the contents of the surface to the screen on each frame and basically ignore the refresh function that Lua calls (it is always valid to use the contents of the surface, the refresh callback from Lua is just a "I changed something"-signal to force a repaint; this can of course be optimized later).

Edit: Oh, okay, I forgot about the refreshed member. Okay, refresh can just set that boolean and you only draw if it is true...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I had a feeling I didn't need a pixmap but I hadn't looked into whether or not I needed it.

Ok so I don't even really need to add it as a field, I can just have a refresh function that checks the bool and only draws if it's true then. That will simplify this.

Comment thread src/awesome/drawin.rs
use super::dummy;
builder.method("connect_signal".into(), lua.create_function(dummy))?
.method("__call".into(), lua.create_function(dummy_create))
.method("__call".into(), lua.create_function(|lua, _: Value| Drawin::new(lua)))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh and the global (e.g. drawin) when called get a table of properties to be applied, for example visible = true (but the table can also contains keys that the C code does not understand and thus ignores). This code looks like you explicitly ignore these extra arguments.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch, I'll fix that when I fix the object creation (so I can throw those unknown keys into data)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think awesome stores unknown keys into data, it just really completely ignores them.
This seems to be done in luaA_class_new in common/luaclass.c: All strings for which it finds a lua_class_property_t are handled, all others are just silently ignored.
(This is like this mostly for "historic reasons", I guess; I don't know if it makes sense or not)

Comment thread src/awesome/awesome.rs Outdated
}).unwrap_or_else(|err| {
warn!("err: {:#?}", err);
Some("pc+us+inet(evdev)".into())
}).unwrap())
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I liked your previous "just return static fake data" version of this more. :-)
On a more serious note, I would expect a wayland compositor to already have the required data here somewhere. From a quick look at wlroots, this data seems to be in struct roots_keyboard_config (which is part of the example compositor, so perhaps wlroots requires the compositor to handle this itself?).

Copy link
Copy Markdown
Member Author

@Timidger Timidger Dec 29, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In wlc (the current compositor framework Way Cooler uses) that information is not exposed (or at least, not anywhere I can see). It, along with xwayland stuff, is all handled internally.

When we switch to wlroots though that will definitely be what we do. Also yes you're correct we have to handle it ourselves--that's the main benefit of wlroots actually is that we have to manage more stuff (compared to wlc). This increases the complexity of the compositor but also gives enough control that we can do stuff like this.

I'm going to keep this really bad version, since it actually gets the required info necessary for the user. When we switch wlroots though it will definitely change :)

Comment thread src/awesome/awesome.rs Outdated
/// This actually does nothing, since this is Wayland.
fn register_xproperty<'lua>(_: &'lua Lua, _: Value<'lua>) -> rlua::Result<()> {
warn!("register_xproperty not supported");
fn register_xproperty<'lua>(lua: &'lua Lua, (name, v_type): (String, String)) -> rlua::Result<()> {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I would implement this purely in Lua (somehow). In awesome, awesome can be restarted while the X11 server continues running, so there it makes sense to save things in the X11 server. For way-cooler, a restart surely loses all the state (right?), so emulating xproperties in Lua is okay.
What do you think?
(No, I don't know how to actually do this; it's just a thought.)

Copy link
Copy Markdown
Member Author

@Timidger Timidger Dec 29, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may still need to implement this actually, because we will be relying on xwayland a lot and, AFAIK, the xwayland server lets you register xproperties to the clients still.

If the main use case is to store state in case of a restart though, that means we may need to do some hoops to achieve this...

You're right in that if way-cooler was to restart (e.g the process died) then we would lose all state because Way Cooler is not only the window manager but also the display server. If the use case is primarily recovery from the process dying (e.g from an error) then we would need to achieve this via some other way.

One thing we could do is run Lua in a totally separate process and communicate between Way Cooler and Lua via IPC. Though that would obviously be:

  1. Slower
  2. Way more complicated

That would achieve the same thing Awesome currently does with X11 (since they are separate processes there) but it would mean more work.

Depending on the use case, this could drastically affect the design. But it shouldn't affect implementing the interface, as I'll be moving things around when we move to wlroots anyways. I'll be thinking about this though, thank you.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, the "global state" (xproperties on root) is not all that interesting, I think. And xproperties on individual client objects will still be lost since when the display server dies, all clients die with it.

Yes, this xproperty API is from a time when awesome was still restarting whenever the screen configuration changed. Ever since awesome stopped doing that, I haven't seen much use of this API.

Comment thread src/awesome/screen.rs Outdated
// TODO
Some(lua.create_function(screen_new)),
Some(lua.create_function(get_visible)),
Some(lua.create_function(set_visible))))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh? Screens don't have a visible property and Lua cannot (that easily) create screens.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, looks like an oversight. I'll remove those.

@Timidger
Copy link
Copy Markdown
Member Author

Thanks for the detailed writeup! I'm going to work on this PR more and get it to be compliant ASAP. I'm mostly trying to focus on wlroots, since that's going to necessitate mostly starting from scratch on the compositor, but this is really important to enable both me and others to work on whatever part of the Awesome API that seems easiest / most interesting to work on.

a data table that the C code saves but does not otherwise care about; this is used to e.g. save the floating state of a client and was needed so that Lua's garbage collector knows that this table is only kept alive by the client and can be garbage collected together...

Ahhh, ok that was the missing piece in my information. Previously I tried to store these things in the object itself but ran into a lot of issues which prompted the discussion in this rlua issue thread. Here's the relevant takeaway from the thread:

Just so you know though, this is almost NEVER a good idea. This bindings system is not designed to have Lua handles inside UserData, because Lua itself cannot garbage collect through a rust UserData, so you can very easily end up with unbreakable cycles.

It's not 1-1 with Awesome, but from a user's perspective as long as they
don't do weird raw setting/getting on the data I give them it should be
all good.
Doing this so it can still work on master. If it's uncommented, then you
need to fix layoutboxes since it's used in the default rc.lua
@Timidger
Copy link
Copy Markdown
Member Author

Timidger commented Jan 3, 2018

Ok I think I fixed all the issues I had with this PR. Still some rough edges around the core object stuff, but nothing blocking working on the other issues. Gonna give this one more look through and then merge it later today.

@Timidger Timidger merged commit c263393 into master Jan 4, 2018
@Timidger Timidger deleted the awesomeWM/awesome_and_class_fixups_drawin_impl branch January 4, 2018 17:32
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants