Up to now, a drawable always figured out the screen that it is on by
looking at its position. This causes memleak-like problems with wibars:
A wibar has a screen assigned, but its underlying drawable will end up
referring to another screen. Via this, we were managing to build a long
reference chain of screens and drawable that meant that none of the fake
screens that our test suite added could be garbage collected.
To fix this, add wibox.drawable._force_screen(s). After this function is
called, the normal screen detection based on the position is skipped and
instead the given screen is always used. This breaks the above reference
chain and things become garbage-collectable.
Also, this chains the drawable to the life time of the screen: When the
screen becomes invalid (.valid == false), the drawable will stop
redrawing.
Fixes: https://github.com/awesomeWM/awesome/issues/1237
Signed-off-by: Uli Schlachter <psychon@znc.in>
Previously, the API to set the data that should be displayed was
:set_data(t) where t is a table. This table has the labels to use as its
keys and the numbers as its values. With this API, it was not possible
to influence the order in which the "pie pieces" were drawn.
This commit adds and uses a new API called :set_data_list(t). Here, t is
a table with integer keys and tables as values, thus one can iterate
over this with ipairs() and the order is well-defined. The tables used
as values contain the label as their first entry and the number as their
second entry.
Fixes: https://github.com/awesomeWM/awesome/issues/1249
Signed-off-by: Uli Schlachter <psychon@znc.in>
It does not provide much value. The version number is already known to
ldoc globally in the "description" variable.
Signed-off-by: Uli Schlachter <psychon@znc.in>
No idea what self referencing loops this refers to. Lua 5.1's and
LuaJIT's garbage collector both should handle cycles just fine. Things
only start getting complicated when you start using weak tables.
Unless someone comes up with an example where this patch causes a leak,
let's remove the weak table magic.
Signed-off-by: Uli Schlachter <psychon@znc.in>
Matrix operations are hard. Apparently I always keep confusing the order
that transformations are applied in the matrix resulting from a matrix
multiplication.
This commit fixes things in wibox.hierarchy that were wrong due to the
wrong order and changes a unit test so that it would now catch the
breakage (and makes sure that it does not happen again).
Signed-off-by: Uli Schlachter <psychon@znc.in>
Instead of matrix_to_device and matrix_to_parent, this now provides the
full hierarchy instance managing the current widget.
In addition to x, y, width and height (which are an over-approximation
of the widget's extents on the drawable), this now also provides
widget_width and widget_height in the widget's local coordinate system.
These last two values are exact.
For example, the tooltip needs x/y/width/height while a widget that
wants to figure out which point on it was hit with a mouse press will
need widget_width and widget_height (together with the position argument
that is passed in with mouse::press).
I don't know how to document the return type of this function properly.
Hopefully just describing the structure of the resulting table is good
enough.
Signed-off-by: Uli Schlachter <psychon@znc.in>
Similar to the previous commit, this makes the drawable not apply a
pending relayout while it is not visible. When it becomes visible again,
the relayout is done.
The hope here is that less work is done while a drawable is not visible,
saving CPU time.
Signed-off-by: Uli Schlachter <psychon@znc.in>
LGI does not protect against use-after-free issues that can occur due to
using an object after finalisation. This manifests itself as occasional
crashes on Travis in cairo_region_union_rectangle() (AFAIK no one ran
into this issue in real-world usage).
Since visible drawables are always strongly reachable, the issue can
only occur with invisible drawables. The previous commit made sure that
those are fully repainted when they become visible, so we can just
ignore redraws for those and fix the crash issue.
Signed-off-by: Uli Schlachter <psychon@znc.in>
Instead of tracking all drawables that are alive, the code now only
tracks visible drawables. When a drawable is made visible it is
completely repainted. This should not cause a difference when a wibox is
initially made visible, because it has to be redrawn anyway. However,
this introduces a full repaint when a wibox is hidden and then made
visible again.
Thanks to this change, we can stop using weak tables. Visible drawables
cannot be collected and so we can keep a strong reference to them. This
allows us to get rid of the weak tables which solves various problems
involving finalizers and using objects after finalisation.
Signed-off-by: Uli Schlachter <psychon@znc.in>
This new function is called whenever the visibility of the drawable
changes. Later commits can use this for explicitly tracking the lifetime
of drawables instead of using magic weak tables.
Signed-off-by: Uli Schlachter <psychon@znc.in>
This restore a feature that was available in Awesome 2.1-3.2.
The reason margin is implemented rather than use a container is to
be able to make the background smaller than the bar.
The current progressbar code dates from a time when Awesome had
a very limited drawing API. This commit first re-write the
algorithm to remove the workaround used to draw the border using
full rectangles only. It then add support for outer and inner
shapes with their respective border settings.
This commit also add clip support. This is enabled by default, but
could be disabled to have the bar taller than the background.
Twice now we had problems with the garbage collector which caused signals
established via weak_connect_signal() not to be disconnected when we wanted them
to be disconnected. The effect was that we tried to redraw a drawable after it
was garbage collected which caused errors.
Instead of playing whack-a-mole with all the various ways that might make us
redraw a drawable after GC, let's just fix all of these issues by explicitly
checking for this case and turning it into a no-op.
Signed-off-by: Uli Schlachter <psychon@znc.in>
The previous commit made wibox.drawable turn a "normal redraw" into a complete
repaint when it was moved to another screen. However, nothing happened until
that normal redraw.
This commit triggers a normal redraw when we are (possibly) moved to another
screen. More precise, this means that whenever a screen appears, disappears or
changes its geometry and when the drawable is moved, we trigger a normal redraw.
This redraw will likely do nothing, because no relayout is pending and no part
of the surface needs a redraw, so it is cheap.
However, if the drawable really ends up on another screen, then the code from
the previous commits makes us do a full relayout and redraw.
This commit likely fixes the current instability of test-screen-changes.lua. See
https://github.com/awesomeWM/awesome/issues/982#issuecomment-231712056.
As explained there, the test fails because the fake screen that it created is
still referenced, so cannot be garbage collected, but the test doesn't succeed
unless the screen is garbage collected. So something is still referencing the
screen that was removed. This something can be a client's titlebar, because the
underlying drawable still has a context member referring to the old screen.
This commit should fix that problem, because we now trigger a redraw which will
compute a new context and thus the reference to the old screen is released.
Signed-off-by: Uli Schlachter <psychon@znc.in>
The previous commit made the hierarchy do a re-layout when the context changes.
However, widgets could change their appearance depending on the context without
changing their layout. Thus, the previous commit is not enough.
This commit also makes the drawable redraw everything when the context changes.
Signed-off-by: Uli Schlachter <psychon@znc.in>
When the context for widget changes (e.g. we are on a new different screen or
have a different DPI value), widgets might change their appearance even though
they didn't emit widget::layout_changed. Thus, update the hierarchy in these
cases.
Signed-off-by: Uli Schlachter <psychon@znc.in>
widget_at() no longer exists since 0aa4304bda (and the surrounding commits
stopped us using this function).
Signed-off-by: Uli Schlachter <psychon@znc.in>
The actual bg is drawn either with fake transparency over the wallpaper (this
uses operator OVER) or for true transparency with operator SOURCE. The bgimage
should be drawn ontop of this without erasing the background and thus needs
operator OVER.
However, before this commit the bgimage was drawn in the same way as the bg and
thus inherited its SOURCE operator if a compositor is running. Fix this by
restoring the default operator (OVER) and also e.g. the default source before
drawing the bgimage.
Fixes: https://github.com/awesomeWM/awesome/issues/954
Signed-off-by: Uli Schlachter <psychon@znc.in>
When called with the file name of an image, this function failed to turn that
file name into a cairo surface.
Fixes: https://github.com/awesomeWM/awesome/issues/954
Signed-off-by: Uli Schlachter <psychon@znc.in>
The requirement to call add_signal() was added to catch typos. However, this
requirement became increasingly annoying with property::<name> signals and e.g.
gears.object allowing arbitrary properties to be changed.
All of this ended up in a single commit because tests/examples fails if I first
let add_signal() emit a deprecation warning.
Signed-off-by: Uli Schlachter <psychon@znc.in>
It was set as `module` instead of `class` because ldoc was confused
set shown the methods as functions and functions as methods.
This commit set the explicit section so ldoc don't gress (wrongly)
local functions and metatable based constructors are not
documented unless an explicit @function is added.
Also add missing return values and fix formatting.
Before this commit, it was necessary to call 'rawset' to be
able to add new fields to the wibox. This is no longer required.
This solution was choosen because wibox is itself a base class of
menus and wibars. Those classes can now add new properties without
hacks.
As wibox contain a drawin, but isn't one, it is necessary to map
drawin to wibox.
This could eventually be fixed by turning wibox into drawin just
like the client, tag and screen do.
When there are no screens, screen[1] causes an error. Thus, this isn't a safe
fallback for these functions. Instead, this commit makes the code prefer the
primary screen, if possible. If no screen exists, then screen.primary will be
nil, but at least it won't throw an error like screen[1] does.
(This also changes the outdated copy of getbycoord that exists in
wibox.drawable)
Signed-off-by: Uli Schlachter <psychon@znc.in>
This makes it possible to have the systray only visible on the primary screen,
which is the new default value. This also makes it possible to configure
directly on which screen the systray should be visible.
This breaks the API in the sense that people who use "the old method" to
configure the systray's screen possibly don't have a systray.
Fixes: https://github.com/awesomeWM/awesome/issues/724
Signed-off-by: Uli Schlachter <psychon@znc.in>
There's no point in having multiple instances of this, because there are no
per-instance settings and the systray can only be visible in a single place at a
time anyway.
Signed-off-by: Uli Schlachter <psychon@znc.in>
* Better widget names when using the declarative syntax
* Add ratio.get_ratio to avoid using the private API
* Also support `set_widget` when swapping widgets
Issues involve:
- :layout() had the wrong signature and expected a cr argument that was left
from when this was still the :draw() function.
- horizontal and vertical reflection were mixed up (I guess it has always been
this way?)
- The return value should be a table of widget placements. Instead it was just a
single widget placement.
This is broken since commit 85ab3f045b.
Fixes: https://github.com/awesomeWM/awesome/issues/718
Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit makes these methods invoke the method on a widget in a protected
context. Thanks to this, e.g. the wibox and other widgets are protected from
errors in a child widget.
Additionally, fit_widget() now assumes 0 if a widget's :fit() method didn't
provide a number.
Signed-off-by: Uli Schlachter <psychon@znc.in>
I just spent too much time tracking down a bug that happened while drawing a
widget. This is the reason why we should apply sanity checks while widgets are
constructed, so that we get a useful backtrace.
Signed-off-by: Uli Schlachter <psychon@znc.in>
This makes the code use the existing functions for setting widgets. That way,
all the sanity checks that the existing functions have are applied for this code
as well.
I just spent half an hour tracking down a bug where a boolean ended up as a
"widget" in a fixed layout. The symptom was that while drawing the widget, an
error happened. Via this change, the error would instead be flagged while
constructing the widget.
Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit documents that a textbox already accepts a screen object where a
screen index is expected. Also, this changes the widget API in that a widget's
context.screen is now a screen object instead of a screen index.
Signed-off-by: Uli Schlachter <psychon@znc.in>
This layout allow each widgets to take 'r' percent of the total
space, where 'r' is configurable.
It re-implement the 'wfact' system used by `awful.layout.suit.tile`
This layout display the widgets on top of each other. It can also optionally
display only the first one.
The most common use case is to create a composited widget. Other use case
include the creation of a "paged" stack to only display the most
relevant widget without adding extra complexity to the parent layout.
This new syntax is inspired by the Awesome widget 3.2-3.4 API. It
allow cleaner widgets declaration. The produced code is usually much
shorted and easier to read than wibox.widget imperative syntax.
There is already a hack into `awful.widget.common`. This system aim
to make the hack obselete while preserving the useful part.
I think this is also necessary to properly support SVG (with DPI
and resize).
Finally, Qt handle this using the QBrush concept, where you can have
programmatic patterns. Cairo doesn't have this concept, so there is no
"clean" way to have programmatic brushes.
It's unused since commit 0aa4304bda. Before this was a stable sorting
algorithm since table.sort is allowed to be unstable. Apparently we don't need a
stable sorting algorithm anymore.
Signed-off-by: Uli Schlachter <psychon@znc.in>
Until now, this layout was "append only". There was no official
APIs to remove, replace, insert and swap widgets. This is fine
for the usual wibox + sensors widget used by the majority of
users, but lack flexibility necessary to use the layout system
to place dynamic elements such as clients.
The methods introduced by this commit are also recursive. This
allow widgets to be decorated, wrapped and splitted without
having to add boilerplate code everywhere.
This remove duplicated code and will allow more "collection"
style layouts to be implemented without logic duplication.
This commit also do some small cleanup to remove duplicated
code now present in `awful.util`.
Fixes https://github.com/awesomeWM/awesome/issues/617
Instead of throwing a Lua error, the code now just prints an error message to
stderr on invalid markup. For callers which want to handle this case specially,
we add :set_markup_silently() which returns error messages.
Fixes: https://github.com/awesomeWM/awesome/issues/546
Signed-off-by: Uli Schlachter <psychon@znc.in>
Without this fix `wibox.widget.textbox` ignores current theme font
setting and resets it to the initial one.
It becomes handy when the initial theme is tweaked during runtime, ie.
in `rc.lua`. Other AwesomeWM components like `awful` (taglist,
tasklist, menu) are aware and do respect the actual theme settings.
Closes https://github.com/awesomeWM/awesome/pull/89.
This adds new functions to all widgets that allow to force a specific
width/height. These values override the result from :fit().
Signed-off-by: Uli Schlachter <psychon@znc.in>
When emitting layout_changed, the widget is relayouted. If this doesn't actually
change anything, nothing will be redrawn. Thus, this also emits redraw_needed to
force redraws.
This fixes a race condition with some weird tray icons. A new tray icon is
created and the systray is updated. Then this new icon is destroyed immediately
again and at the same time another icon is created. Then, the systray isn't
updated since the number of icons (=the layout) did not actually change.
However, it needs to be updated and so we ended up with broken/missing icons.
Fixes: https://github.com/awesomeWM/awesome/issues/487
Signed-off-by: Uli Schlachter <psychon@znc.in>
This allows scrolling a widget if there is too few space available. There are
several different modes available for how the scrolling "looks like".
Signed-off-by: Uli Schlachter <psychon@znc.in>
This adds :get_preferred_size() and :get_preferred_size_at_dpi() which return
the size (=width, height) that the textbox would need if unlimited space is
available.
This also adds :get_height_for_width() and :get_height_for_width_at_dpi() which
return the height that the textbox would need if the given width is available.
Signed-off-by: Uli Schlachter <psychon@znc.in>
If someone modifies a cairo surface and then sets the resulting object as the
image of an imagebox, the imagebox needs to redraw. Thus, since surfaces are
modifiable, we cannot assume that nothing changed when the same image is set
multiple times on an imagebox.
However, the dimensions of a surface cannot be changed and thus this does not
need to emit widget::layout_changed.
Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit does two things: It gets rid of the reference to the layoutbox that
the default config created and it changes the widget dependency cache to not
keep widgets alive unnecessarily.
Signed-off-by: Uli Schlachter <psychon@znc.in>
This function updates a hierarchy if the layout of some widgets changed. It does
nothing on the parts that did not change. This should be more efficient than
recomputing the whole hierarchy whenever something changes.
Once again, this has some positive results on the "benchmark test":
Before:
create wibox: 0.083016 sec/iter ( 13 iters, 1.161 sec for benchmark)
update textclock: 0.00391091 sec/iter (271 iters, 3.219 sec for benchmark)
relayout textclock: 0.00273234 sec/iter (397 iters, 1.087 sec for benchmark)
redraw textclock: 0.0010191 sec/iter (989 iters, 1.745 sec for benchmark)
After:
create wibox: 0.083146 sec/iter ( 13 iters, 1.163 sec for benchmark)
update textclock: 0.00170519 sec/iter (647 iters, 2.201 sec for benchmark)
relayout textclock: 0.000581637 sec/iter (1880 iters, 1.094 sec for benchmark)
redraw textclock: 0.0010167 sec/iter (997 iters, 1.773 sec for benchmark)
So again no difference for creating wiboxes (100.16% compared to before). This
time we also have no real difference for creating wiboxes (99.76%). Update (44%)
and relayout (21%) are improved a lot.
Closes https://github.com/awesomeWM/awesome/pull/463.
Signed-off-by: Uli Schlachter <psychon@znc.in>
This makes the textbox' :draw() and :fit() callbacks use the DPI that is
specified in the given drawing context. With this, the textbox now scales
correctly if different screens have different DPI values.
Idea originally from Daniel.
Closes https://github.com/awesomeWM/awesome/pull/457.
Signed-off-by: Uli Schlachter <psychon@znc.in>
This has some positive results on the "benchmark test". Each single number is
the best one out of three runs.
Before:
create wibox: 0.0826502 sec/iter ( 13 iters, 1.157 sec for benchmark)
update textclock: 0.0186952 sec/iter ( 57 iters, 2.473 sec for benchmark)
relayout textclock: 0.0158112 sec/iter ( 64 iters, 1.028 sec for benchmark)
redraw textclock: 0.0015197 sec/iter (662 iters, 1.861 sec for benchmark)
After:
create wibox: 0.0825672 sec/iter ( 13 iters, 1.154 sec for benchmark)
update textclock: 0.00378412 sec/iter (277 iters, 4.216 sec for benchmark)
relayout textclock: 0.00259056 sec/iter (420 iters, 1.09 sec for benchmark)
redraw textclock: 0.00105128 sec/iter (958 iters, 1.79 sec for benchmark)
We see no significant change in the creation of wiboxes (99.9% compared to
before). Update (20% of the previous run time), relayout (16%) and redraw (69%)
are all sped up by this change.
Signed-off-by: Uli Schlachter <psychon@znc.in>
Before this, dependencies between widgets where implicitly discovered by
recursive calls to base.fit_widget() and base.layout_widget(). However, it is
too easy to get this wrong (just call one of these functions from outside of a
widget's :fit() / :layout() function) and the resulting mess would be hard to
debug.
Thus, this commit changes the API so that callers have to identify themselves
and we can explicitly record the dependency between the widgets involved.
This also fixes a bug where no dependencies were tracked for widgets after
:set_visible(false). Whoops...
Sorry for breaking the API for adding this.
Signed-off-by: Uli Schlachter <psychon@znc.in>
When a complete repaint is scheduled, also do a relayout, because this is also
the case that we go through when the underlying cairo surface is resized. For
example, resizing a client with a titlebar would trigger this.
Also, going through this code path is necessary since this is the only place
where the dirty area is updated so that it includes "everything". Before this
change, nothing was actually redrawn, because the dirty area was empty.
Fixes: https://github.com/awesomeWM/awesome/issues/449
Signed-off-by: Uli Schlachter <psychon@znc.in>
This accidentally called the draw callbacks with a nil argument instead of the
context. This was introduced in some badly done rebase, sorry! :-(
Signed-off-by: Uli Schlachter <psychon@znc.in>
The parent was needed for :get_matrix_to_device() which recursively walked
parents and multiplied together their transformation matrices. This is now
replaced by calculating all these matrices while constructing the hierarchy.
Signed-off-by: Uli Schlachter <psychon@znc.in>
There once was a function :get_root() on hierarchies, but that wasn't needed any
more and thus was removed. This commit also removes the internal code that was
used to record the root element of the hierarchy.
Signed-off-by: Uli Schlachter <psychon@znc.in>
These caches, well, cache the result of the :layout and :fit callbacks on
widgets.
Clearing caches is done by recording dependencies between a widget. When a call
to base.fit_widget() or base.layout_widget() recursively causes another call to
such a function, this means that the earlier widget depends on the later widget.
This dependency is recorded and when the later widget emits
widget::layout_changed, the caches of all the widgets involved are cleared.
Signed-off-by: Uli Schlachter <psychon@znc.in>
A widget hierarchy describes the position of widgets. The hierarchy is a
recursive tree of widget hierarchy instances. This functionality depends on a
:layout function that is not yet implemented on widgets, but will be added
later.
Signed-off-by: Uli Schlachter <psychon@znc.in>
After this change, fit_widget() enforces that a widget cannot ask for more space
than was offered to it. This also fixes a rounding issue in the flex layout
where its fit function would return too small numbers.
Thanks to this, lots of "XXX" comments in spec/ disappear.
Signed-off-by: Uli Schlachter <psychon@znc.in>
In expand nodes "none" and "outside", the variable size_remains describes how
much space is available for the first/third widget. Everything else is used by
the second widget. Thus, fitting the second widget to anything involving
size_remains is wrong. Instead, this commit uses the correct value.
This also fixes a messed up argument order for horizontal align layouts.
Signed-off-by: Uli Schlachter <psychon@znc.in>