For each widget, the layout function checks whether placing it would
make the function exceed the allowed geometry.
If not, the function places both the widget and a spacing widget.
This check ignores the size of the spacing widget itself, this can cause
overloading of widgets on top of each other.
For example, the following scenario with these widgets:
widgets: widget1 { width = 10, height = 10 }
widget2 { width = 10, height = 10 }
widget3 { width = 10, height = 10 }
and a call to horizontal layout with the
{ width = 10, height = 10, spacing = -5 } parameters.
The function would layout the widgets the following way:
{
widget1: { x = 0, y = 0, width = 10, height = 10 }
spacing: { x = 5, y = 0, width = 5, height = 10 }
widget2: { x = 5, y = 0, width = 5, height = 10 }
spacing: { x = 5, y = 0, width = 5, height = 10 }
widget3: { x = 5, y = 0, width = 5, height = 10 }
}
This behaviour would be the same for any number of widgets for negative
layout.
This patch changes the layout function to check whether the current
widget uses up the whole space.
It also removes 'pos' variable. Its purpose isn't intuitive in the
presence of x and y. This helps to understand where each widget is
placed now that x, y don't hold the end location of the widget in the
previous loop iteration.
The result of the previous example becomes:
{
widget1: { x = 0, y = 0, width = 10, height = 10 }
}
While this might not be the wanted behaviour exactly, distinguishing
between the scenario where 2 widgets are drawn and a scenario where 3
are drawn might complicate the layout function too much.
This patch also adds unit testing that catches the described behaviour.
Signed-off-by: Shay Agroskin <agrosshay@gmail.com>
The fit function is called twice in row.
- The first time it gets the maximum available width, and returns how
much of it it needs (with 0 spacing it would be 477)
- The second time the available width it gets is the same as it returned
last phase (and probably is expected to return the same result again)
The width fit requests is the total width of all widgets together + the
spacing (e.g. if each tag widget is 53 px and spacing is -10 then the
requested width 53 * 9 - 80).
The function tries to first fit all its widgets (the tag numbers) in the
amount of width it received, and only then adds the spacing to it. This
is problematic because in the second phase the widgets need to fit
themselves in the same width they requested earlier minus the spacing
(in case of negative spacing). This is of course impossible and so some
widgets are just not being drawn correctly.
This patch makes fit function take into account the spacing while
placing the widgets and not afterwards.
Also add unit-testing that test the bug described.
Signed-off-by: Shay Agroskin <agrosshay@gmail.com>
The function has several expressions of the form
if self._private.dir == "y" then
This patch stores the result of
self._private.dir == "y"
to avoid code duplication.
Also remove the 'used_in_dir' and 'in_dir' variables since their values
can be calculated using other variables in the function and updating
them individually is error prone.
This patch doesn't do any functional changes.
Signed-off-by: Shay Agroskin <agrosshay@gmail.com>
When wrapping container widgets to create reusable composite widgets,
`drill` will be called twice on the same widget definition. The first
call happens within the wrapping function and applies the children
widgets fine. The second call happens when the composite widget is used,
but since there are no children widgets defined, the call to
`set_children` sets the existing child to `nil` instead.
Fixes#3213.
Signed-off-by: Lucas Schwiderski <lucas@lschwiderski.de>
There seem to be two issues here. First, the if-statement at the
beginning of the function will return prematurely if
`self._private.widgets[index]` exists. There seems to be a
missing `not` there.
Second, index 1 is interpreted as the top of the stack (although the
documentation says otherwise), but the widget is inserted at the end of
`self._private.widgets`, so it gets pushed to the bottom
instead of the top.
When less space is available than was asked, systray:draw() has to
compute the right base size so that all the icons fit into the available
space. This computation so far ignored the icon spacing, resulting in a
too large base size.
Fixes: https://github.com/awesomeWM/awesome/issues/2981
Signed-off-by: Uli Schlachter <psychon@znc.in>
Just like clients and other CAPI classes, it is now possible to
connect to all instance signals. There was already a couple of
`request::geometry`, but no way to forward them, so it was
de-facto broken.
The next commit will all class level signals. The current design
is used in widgets, but is a bad fit for wiboxes. They should
behave more like client. In v5, setting methods on `wibox` directly
will be deprecated. `wibox.object` is already supported. I don't
think anyone really do that anyway and isn't documented.
The default `rc.lua` was using the focus/unfocus signals to set
the border color along with `awful.rules`. This logic block was
no longer aligned with the rest of `rc.lua` since it was
the only place where `beautiful` variables where only used by
`rc.lua`.
On top of this, the new request handler also has extra contexts
for the urgent and floating/maximixed use cases. So it can be used
by themes to implement much smarter borders than just focus based
ones. They were previously limited by the fact most of the
(un-monkey-patchable) logic was in `rc.lua`.
Note that this commit also shuffle the awful.rules order between
the titlebar and the border and changes the tests accordignly.
After some consideration, I came to the conclusion the previous
behavior was bogus and the fact that the placement tests required
to know about the titlebar height is simply a proof of that. The
change was required in this commit because since the border is no
longer in the default rules, a new buggy edge case surfaced.
Commit f025409 avoided negative dimensions but
also stopped allowing width and height to be zero.
For widgets like awful.widget.watch it is reasonable
to allow dimensions to be zero because in many cases when
the margin container is being calculated the watch widget is
still computing and therefore has width and height zero.
This hass the following tags:
* @interface
* @tparam
* @propbeautiful
* @propemits
* @renamedin
Beside tags, it adds some comments, fix formatting and add
new lines and dots where they belong.
Also add some signals to standardize everything.
This hass the following tags:
* @interface
* @tparam
* @propbeautiful
* @propemits
* @renamedin
Beside tags, it adds some comments, fix formatting and add
new lines and dots where they belong.
Also add some signals to standardize everything.
* Add the ldoc stop marker `.` to each functions, properties and methods definition ;
* Improve a little summaries ;
* Improve properties vs access methods documentation ;
* Change all documented parameters and return values to typed values.
* Add a better descrition for the `imagebox` role in the wiboxes system ;
* Improve image + code render and integration into the descrition ;
* Add a second code exemple to show both coding style (imperative and declarative).
I think the user can now have a better overview of what's a `wibox.widget.imagebox` and how to use it.
get_children's return value should not be called "The". That was a
mistake because ldoc requires a name for return values and parameters.
If a name isn't provided, it thinks the first word of the description
is the name.
* Add format docs to the constructor.
* Add timezone docs to the property.
* Give the argument to set_refresh a name other than "How".
* Fix bug in constructor argument "format" rendering.
Having the new object layout will be important soon when the
append/remove methods start to get added to the client and the
reborn `awful.keyboard` module.
This function is not documented to handle userdata, but historically it
would just pass all arguments to gears.surface.load(), which interpreted
userdata as cairo surfaces. After 3295e9f33d, userdata
objects are restricted.
Accept userdata objects again by explicitly passing them to
gears.surface.load().
Fixes: https://github.com/awesomeWM/awesome/issues/2903
Signed-off-by: Uli Schlachter <psychon@znc.in>
This is done now because a lot of code in `lib/` add buttons by manually
extracting buttons from awful.button. Instead of adding ugly code to
prevent using the legacy API, do this.
Now always call both check_widget and make_widget_from_value. This
should make it a lot less confusing when randomly trying to create
a widget as all ways to do it slowly converge toward an unified
one.
This doesn't mean removing all screens is supported. It isn't and never
will be. The only reason this commit exist is to allow some
initialization and error handling code to be tested.
The way background are rendered changed to accomodate issues regarding
cliping and border. However this broke the documentation examples.
This commit fixes this in the least hacky way I found.
Fixes#2727
Cairo's save/restore methods handle all properties except for the
current path. The path is just left as-is.
A widget's draw method could create some path without consuming it. This
path would then interfere with random things later which did not expect
a path to already exist.
This commits adds calls to cairo_new_path() in the relevant positions to
clean things up.
This not only applies to a widget's draw method, but also
{before,after}_draw_{child,children}. However, these methods could (for
whatever reason) create paths that are to be consumed in one of the
other methods. To keep this working, the path is only cleared after all
of these methods ran.
I do not expect this commit to break anything, because a widget cannot
really assume much about what widget is drawn after it. Especially so,
because partial redraws could mean that some later widget is skipped and
not redrawn.
This should fix the issue reported at
https://github.com/awesomeWM/awesome/pull/2804.
Signed-off-by: Uli Schlachter <psychon@znc.in>
This function checks if a given cairo context has an empty clip. It was
written with the assumption that cairo_clip_extents() produces the x, y,
width, height of the clip extents. However, that function actually
produces x1, y1, x2, y2, where (x1, y1) and (x2, y2) are the corners of
the rectangles.
Due to the way the function is written, it will return non-zero numbers
when there is a translation (cr:translate()). Thus, this function worked
basically never.
Fix this by checking if both points have the same X- or Y-coordinate.
Signed-off-by: Uli Schlachter <psychon@znc.in>
With draw_empty=false, :fit() can return 0,0. Then, when :layout() is
called, it will compute negative widths and heights. This can then cause
lots of problems later on.
Avoid this by having :layout() return nothing instead of producing
negative sizes.
Fixes: https://github.com/awesomeWM/awesome/issues/2799
Signed-off-by: Uli Schlachter <psychon@znc.in>
This way their name doesn't get mangle by the broken magic. It will also
eventually allow to `error()` in the template when the implicit
`@function` is used.
This commit also fixes a large number of issues found while
proof-reading everything.
ldoc has a magical `@classmod` module type which tries to detect
what is a method and what is a static function. It fails about as
often as it works. This commit makes everything explicit to remove
such issues.
Fixes#2640
Ref #1373
- Fill slider bar with a linear pattern based on current value (if `bar_active_color` and `bar_color` are correctly provided)
- Add examples for the apidoc
It makes some code easier to write. It is mostly useful when the margins
are exposed through another widget. In that case it avoids having to
proxy 5 different property or re-invent the wheel there.
Previously, the border "support" was limited to shapes and would not
move the content by the offset of the border. Borders are now better
supported and thus renamed from `shape_border_width` to `border_width.
In the end, shrinking the widget by the border size is too common to
ignore. It should have been the default all along, just like the clip.
* Fixed input_passthrough property not being set
In the table of properties supplied to the `wibox` function, you couldn't set the `input_passthrough` property. You could only set it after the wibox was created like this: `my_shlick_wibox.input_passthrough = true`. This commit fixes that and now you can set it in both ways.
Commit ba75da7976 worked around a bug in LGI. However, it did so by
just dropping the code that set the foreground color. Instead, it should
have changed the code so that cr:set_source() is only called if the
background container has a foreground color configured instead of "just
always".
Fixes: https://github.com/awesomeWM/awesome/pull/2609#issuecomment-459580395
Signed-off-by: Uli Schlachter <psychon@znc.in>
When $SOURCE_DIRECTORY is set, we are most likely currently running the
examples test, i.e. generating images. These images end up in the
documentation.
To make the images reproducable, i.e. independent from the current time,
this commit makes the textclock honor $SOURCE_DATE_EPOCH if
$SOURCE_DIRECTORY is set.
See commit 9d7eaf02 for some more details.
Signed-off-by: Uli Schlachter <psychon@znc.in>
cairo_get_source() is not bound correctly, leading to use-after-free
bugs. Cairo catches this and crashes.
Work around this by preserving the current source in a different way.
Instead of using cairo_get_source() and later cairo_set_source(), this
commit wraps everything that changes the current source between
cairo_save() and cairo_restore(). Thus, cairo saves the current source
for us without us having to grab an explicit reference.
Works-around: https://github.com/pavouk/lgi/issues/210
Signed-off-by: Uli Schlachter <psychon@znc.in>
Previously, the background container "just" used the shape and drew a
line around it. This means that half the line will be inside of the
shape and half of it will be outside. Thus, this hides the actual shape
that is used.
This commit changes that so that the line is added outside of the shape.
It does this via some tricks:
- In :before_draw_children(), :push_group() is used to redirect drawing
of the child widget to a temporary surface.
- In :after_draw_children(), the border is added to this group.
+ For this, another temporary surface is created. It will be used as a
mask.
+ The inside of the shape on this mask is cleared, everything else is
filled. Thus, the mask now contains everything "not content".
+ Everything inside the mask is filled with the background color.
- Also in :after_draw_children(), the group is drawn to the actual
target surface.
+ Again, this needs a mask.
+ This time, we draw the shape to the mask with twice the border width.
Thus, half of this line will be outside of the shape.
+ Then, the shape itself is also filled so that the mask contains the
shape and the border.
+ This mask is then used to copy the right parts of the temporary
surface were the child widget and border was drawn to the actual
target surface that will be visible on screen.
This approach has some upsides. Because we no longer have "half the
border" above content, colors with some transparency work fine for the
border. Also, this should avoid issues with anti-aliasing, because e.g.
the border is not just drawn with the border width, but also further out
to everything else so that the background cannot "bleed through".
Fixes: https://github.com/awesomeWM/awesome/issues/2516
Signed-off-by: Uli Schlachter <psychon@znc.in>
Before this commit, it was added by `wibox.widget.base` if
`:setup()` is used. However it doesn't work for the `awful.popup`
because of the extra indirection.
This commit stops the monkey-patching and make sure the function
always exists. This doesn't prevent it from not working and in
the long run this should still be moved into the hierarchy.
However for now it makes the situation a lot more consistent and is a
quick band-aid without too much controversy.
Mitigate #2181
It is not possible to distribute 100px to three widgets equally. The
current version of wibox.layout.flex tries to do that anyway, by giving
each widget 33px and leaving one pixel outside of any widget. Thus, if
the widgets e.g. have a common background, this leads to a one pixel gap
in the background.
This patch changes the flex layout so that the extra pixel is assigned
to some widget instead. It does so by basically keeping a sum of
space_per_item for the widgets that was assigned so far. This sum is
rounded and when this leads to rounding, the corresponding child widget
gets an extra pixel.
More precisely, this tracks a pos as before. Widgets get their position
still assigned based on rounding pos. However, this now also remembers
this rounded position for the next iteration of the loop. This allows to
assign the size of widgets based on the difference between the current
and last rounded position.
(Possibly) fixes: https://github.com/awesomeWM/awesome/issues/2461
Signed-off-by: Uli Schlachter <psychon@znc.in>