You are not logged in.
I think adding a little bit of flair wouldn't hurt. Take a look at this example:
The text could use some fading. I'm not exactly sure how to implement that, though. Perhaps I can add a box shadow to the right of panel-2 (i.e. the one containing the launchers) but then I fear the rule will also affect panel-0 (top), and potentially panel-1 (left-side).
Maybe also add some animation to make it look more lively? The built-in popdown-delay is awkward, to say the least.
Last edited by KBar (2022-02-11 13:17:27)
Remember to edit the subject of your topic to include the [SOLVED] tag once you're satisfied with the answers or have found a solution (in which case, don't forget to share it as well), so that other members of the community can quickly refer to it and save their time. Pretty please!
Offline
Hi, ToZ!
Here is the script:
#!/bin/sh
# This little shell script brings panel-2 above panel-0.
# First, make sure to wait until xfce4-panel is running:
until pgrep --full --exact 'xfce4-panel'
do
sleep 0.1s
done
# Next, save the PID of the running instance:
panel_pid="$(pgrep --full --exact 'xfce4-panel')"
# Set some variables:
panel2="$(wmctrl -lpG | awk '$3 == '${panel_pid}' && $6 == 68 && $7 == 24 { print $1 }' | sed -n '1p')"
panel2_hidden="$(wmctrl -lpG | awk '$3 == '${panel_pid}' && $6 == 68 && $7 == 24 { print $1 }' | sed -n '2p')"
# Finally, manage their windows in a proper way:
wmctrl -ir "${panel2_hidden}" -b add,above &&
wmctrl -ir "${panel2}" -b add,above &&
exit 0
I added an until loop in the beginning, improved comments, did some minor tweaks and converted it from bash to sh.
Two questions:
As you can see, pgrep first runs in the loop and then later in a command substitution, output of which is assigned to the panel_pid variable. Can I run it only in one place and catch its output (not exit status) for assignment? Suppose it takes 5 seconds for the panels to load and the loop runs 49 times. The moment the panels load, pgrep matches successfully (exit status is 0) and the loop breaks. How can I catch its output? To be fair, by that point it had already been ran 50 times in the loop and the 51st time shouldn't really matter but I'm just curious.
Any suggestions on those awk expressions? They look ugly. Before awk, I used tr and cut, which looked even more hideous. The full output from wmctrl looks like this:
wmctrl -lpG | awk '$3 == '${panel_pid}
0x00e00008 -1 1083 0 0 1366 24 hp xfce4-panel
0x00e00013 -1 1083 0 24 65 744 hp xfce4-panel
0x00e00019 -1 1083 0 0 68 24 hp xfce4-panel
0x00e0001e -1 1083 -9999 -9999 68 24 hp xfce4-panel
I need the last two windows be in the above state. I can simply sed them and awk the first columns but I'm not sure if that's a good idea. I don't know if their order is constant. What if I decide to change panel-2's size? What if it's adjusted dynamically? What would be your suggestions to make it as fool-proof as possible and avoid hard-coding?
Also, one flaw that I forgot to mention is the fact that the launchers are present for windows in all states. If I misplace the pointer, which doesn't happen very often, and hover over the area, the result is this:
However, I'm working on another script that will monitor the properties of an active window with the help of xprop and xwininfo and will invoke the initial script only if the active window is in a maximized state (Horz,Vert)
Another idea that I have is to adjust the panel's size according to whether the active window can be hidden or maximized. If a window cannot be maximized and hidden, shrink the length of the panel so that only the close button is visible.
Thank you. Have a splendid weekend.
Last edited by KBar (2022-02-12 17:39:32)
Remember to edit the subject of your topic to include the [SOLVED] tag once you're satisfied with the answers or have found a solution (in which case, don't forget to share it as well), so that other members of the community can quickly refer to it and save their time. Pretty please!
Offline
As you can see, pgrep first runs in the loop and then later in a command substitution, output of which is assigned to the panel_pid variable. Can I run it only in one place and catch its output (not exit status) for assignment? Suppose it takes 5 seconds for the panels to load and the loop runs 49 times. The moment the panels load, pgrep matches successfully (exit status is 0) and the loop breaks. How can I catch its output? To be fair, by that point it had already been ran 50 times in the loop and the 51st time shouldn't really matter but I'm just curious.
Try assigning the output to a variable at the same time:
until panel_pid=$(pgrep --full --exact 'xfce4-panel')
do
sleep 0.1s
done
Any suggestions on those awk expressions? They look ugly. Before awk, I used tr and cut, which looked even more hideous. The full output from wmctrl looks like this:
wmctrl -lpG | awk '$3 == '${panel_pid} 0x00e00008 -1 1083 0 0 1366 24 hp xfce4-panel 0x00e00013 -1 1083 0 24 65 744 hp xfce4-panel 0x00e00019 -1 1083 0 0 68 24 hp xfce4-panel 0x00e0001e -1 1083 -9999 -9999 68 24 hp xfce4-panel
I need the last two windows be in the above state. I can simply sed them and awk the first columns but I'm not sure if that's a good idea. I don't know if their order is constant. What if I decide to change panel-2's size? What if it's adjusted dynamically? What would be your suggestions to make it as fool-proof as possible and avoid hard-coding?
The awk commands are fine. The only thing I might suggest, if maybe slightly cleaner, is grep:
panel2="$(wmctrl -lpG | grep -E '68.*24.*xfce4-panel' | awk '{print $1}'
Also, one flaw that I forgot to mention is the fact that the launchers are present for windows in all states. If I misplace the pointer, which doesn't happen very often, and hover over the area, the result is this:
https://imgur.com/EztRMVfl.pngHowever, I'm working on another script that will monitor the properties of an active window with the help of xprop and xwininfo and will invoke the initial script only if the active window is in a maximized state (Horz,Vert)
Another idea that I have is to adjust the panel's size according to whether the active window can be hidden or maximized. If a window cannot be maximized and hidden, shrink the length of the panel so that only the close button is visible.
I think using xprop/xwininfo to act only if active window is minimized is the way to go here. Maybe embed it into the script that manages that button panel to check of window is maximized first before displaying it.
Please remember to mark your thread [SOLVED] to make it easier for others to find
--- How To Ask For Help | FAQ | Developer Wiki | Community | Contribute ---
Offline
Try assigning the output to a variable at the same time:
until panel_pid=$(pgrep --full --exact 'xfce4-panel') do sleep 0.1s done
That is quite an eye-opener. Now I know that an empty assignment produces an exit status of 1:
windows=$(pgrep 'windows')
echo $?
1
Remember to edit the subject of your topic to include the [SOLVED] tag once you're satisfied with the answers or have found a solution (in which case, don't forget to share it as well), so that other members of the community can quickly refer to it and save their time. Pretty please!
Offline
Alright, I have this while loop set up:
while :
do
sleep 1s && active_window_id="$(xprop -root _NET_ACTIVE_WINDOW |\
cut --delimiter=' ' --fields=5 | tr --delete ',')"
done
What I want is to add an if construct that calls one of the two following functions depending on another condition (window state):
toggle_below() {
wmctrl -ir "${panel2}" -b toggle,below &&
wmctrl -ir "${panel2_hidden}" -b toggle,below &&
return 0 # redundant?
}
toggle_above() {
wmctrl -ir "${panel2_hidden}" -b toggle,below &&
wmctrl -ir "${panel2}" -b toggle,below &&
return 0 # redundant?
}
but only if the active window changes. Sort of like a poor man's signal or event processing. The while loops prints out the window ID of the active window and assigns that value to active_window_id:
0x5400333
0x5400333
0x5400333
0x5400333
0x5400333
0x5400333
0x5400333
0x5400333
0x5400333
0x480002c
0x480002c
It would be wasteful to query window state every second. Instead, I need the loop to call another function or branch off only if the last output differs from the one above.
I'd greatly appreciate your suggestions.
Remember to edit the subject of your topic to include the [SOLVED] tag once you're satisfied with the answers or have found a solution (in which case, don't forget to share it as well), so that other members of the community can quickly refer to it and save their time. Pretty please!
Offline
Maybe the way to achieve this is to break the loop after variable assignment, then continue with two conditions?
# pseudo-code
if [ new_output = "${active_window_id}" ]; then :; elif [ ! get_window_state ]; then toggle_above; else :; fi
With get_window_state being a call to another function that returns 1 on unsuccessful match:
get_window_state() {
xwininfo -id "${active_window_id}" | grep 'Maximized [HV][oe]r[zt]'
exit $? # exit or return?
}
What do you think?
I'll test and research more tomorrow.
Last edited by KBar (2022-02-13 17:29:31)
Remember to edit the subject of your topic to include the [SOLVED] tag once you're satisfied with the answers or have found a solution (in which case, don't forget to share it as well), so that other members of the community can quickly refer to it and save their time. Pretty please!
Offline
How about something like this:
#!/bin/bash
last_active_window_id=0
route1 () {
echo $active_window_id
last_active_window_id=$active_window_id
}
route2 () {
echo "same"
}
while :
do
sleep 1s
active_window_id="$(xprop -root _NET_ACTIVE_WINDOW | cut --delimiter=' ' --fields=5 | tr --delete ',')"
if [ $active_window_id != $last_active_window_id ]
then
route1
else
route2
fi
done
Does the check and calls one of two functions depending on result.
Please remember to mark your thread [SOLVED] to make it easier for others to find
--- How To Ask For Help | FAQ | Developer Wiki | Community | Contribute ---
Offline
Simply beautiful!
I'm going to test this, populate the functions and then test some more, and finally report back.
Remember to edit the subject of your topic to include the [SOLVED] tag once you're satisfied with the answers or have found a solution (in which case, don't forget to share it as well), so that other members of the community can quickly refer to it and save their time. Pretty please!
Offline
Working as of now. Thanks a lot.
Two takeaways:
The toggle action doesn't seem to work as one would expect. If both above and below properties are given, it acts in a weird way, although exactly up to two properties are allowed, at least the EWMH specs and the manpage suggest so. For example, if the target window is in _NET_WM_STATE_ABOVE, it doesn't seem to be possible to place it below in one command. I was hoping that toggling the above state off and then toggling the below on state would work (in one line), but it doesn't:
wmctrl -ir "${panel2_hidden}" -b toggle,above,below &&
wmctrl -ir "${panel2}" -b toggle,above,below &&
This results in:
# Initial state:
_NET_WM_STATE(ATOM) = _NET_WM_STATE_STICKY, _NET_WM_STATE_SKIP_PAGER, _NET_WM_STATE_SKIP_TASKBAR, _NET_WM_STATE_ABOVE, _NET_WM_STATE_FOCUSED
# First run puts it below twice, as it seems. Just to make sure, I guess:
_NET_WM_STATE(ATOM) = _NET_WM_STATE_STICKY, _NET_WM_STATE_SKIP_PAGER, _NET_WM_STATE_SKIP_TASKBAR, _NET_WM_STATE_BELOW, _NET_WM_STATE_FOCUSED
_NET_WM_STATE(ATOM) = _NET_WM_STATE_STICKY, _NET_WM_STATE_SKIP_PAGER, _NET_WM_STATE_SKIP_TASKBAR, _NET_WM_STATE_BELOW, _NET_WM_STATE_FOCUSED
# Second run:
_NET_WM_STATE(ATOM) = _NET_WM_STATE_STICKY, _NET_WM_STATE_SKIP_PAGER, _NET_WM_STATE_SKIP_TASKBAR, _NET_WM_STATE_FOCUSED
# Third run will start this loop forever (above>below+below>none)
The hidden window should always be acted upon first, else their state won't be changed.
For now, the whole script looks like this:
#!/bin/sh
# This little shell script brings panel-2 above panel-0.
# First, make sure to wait until xfce4-panel is running
# and then save its PID:
until panel_pid="$(pgrep --full --exact 'xfce4-panel')"
do
sleep 0.1s
done
# Next, assign variables:
panel2="$(wmctrl -lpG | awk '$3 == '${panel_pid}' && $6 == 68 && $7 == 24 \
{ print $1 }' | sed --quiet '1p')"
panel2_hidden="$(wmctrl -lpG | awk '$3 == '${panel_pid}' && $6 == 68 && $7 \
== 24 { print $1 }' | sed --quiet '2p')"
last_active_window_id="0"
# Finally, manage their windows in a proper way:
#if [ ! "$(xprop -root _NET_SHOWING_DESKTOP)" ]
#then
# wmctrl -ir "${panel2_hidden}" -b add,above &&
# wmctrl -ir "${panel2}" -b add,above
#fi
toggle_below() {
if [ "$(xwininfo -id "${panel2_hidden}" -wm | grep -o 'Above')" ]
then
wmctrl -ir "${panel2_hidden}" -b remove,above &&
wmctrl -ir "${panel2}" -b remove,above &&
wmctrl -ir "${panel2_hidden}" -b add,below &&
wmctrl -ir "${panel2}" -b add,below
elif [ "$(xwininfo -id "${panel2_hidden}" -wm | grep -o 'Below')" ]
then
:
fi
}
toggle_above() {
if [ "$(xwininfo -id "${panel2}" -wm | grep -o 'Below')" ]
then
wmctrl -ir "${panel2_hidden}" -b remove,below &&
wmctrl -ir "${panel2}" -b remove,below &&
wmctrl -ir "${panel2_hidden}" -b add,above &&
wmctrl -ir "${panel2}" -b add,above
elif [ "$(xwininfo -id "${panel2}" -wm | grep -o 'Above')" ]
then
:
fi
}
route1() {
if [ "$(xwininfo -id "${active_window_id}" -wm | grep 'Maximized [HV][oe]r[zt]')" ]
then
toggle_below
else
toggle_above
fi
last_active_window_id=$active_window_id
echo "${last_active_window_id}"
}
while :
do
sleep 1s
active_window_id="$(xprop -root _NET_ACTIVE_WINDOW | cut --delimiter=' ' --fields=5 | tr --delete ',')"
if [ $active_window_id != $last_active_window_id ]
then
route1
else
:
fi
done
Tomorrow is a clean-up and polishing day. And of course a lot more testing.
Another idea that came to my mind is to assign last_active_window_id to the window ID of the desktop and maybe call it something like desktop_wid. I'd probably go with either wmctrl or xprop -root _NET_SHOWING_DESKTOP.
This will give me an option to control their state for the desktop, too. I'm going to let them stay above for easy shutdown action, since clicking the on close button (provided desktop is the active window) presents a logout dialog.
Remember to edit the subject of your topic to include the [SOLVED] tag once you're satisfied with the answers or have found a solution (in which case, don't forget to share it as well), so that other members of the community can quickly refer to it and save their time. Pretty please!
Offline
Today I found out that xprop can already do the job of monitoring of active windows:
xprop -spy -root _NET_ACTIVE_WINDOW
_NET_ACTIVE_WINDOW(WINDOW): window id # 0x4000003, 0x0
_NET_ACTIVE_WINDOW(WINDOW): window id # 0x480002c, 0x0
_NET_ACTIVE_WINDOW(WINDOW): window id # 0x480002c, 0x0
_NET_ACTIVE_WINDOW(WINDOW): window id # 0x4000003, 0x0
_NET_ACTIVE_WINDOW(WINDOW): window id # 0x4000003, 0x0
Remember to edit the subject of your topic to include the [SOLVED] tag once you're satisfied with the answers or have found a solution (in which case, don't forget to share it as well), so that other members of the community can quickly refer to it and save their time. Pretty please!
Offline
I had to move xfdesktop up a group or two in the priority list. Are there any side effects to this or am I safe? I found this document on the Xfce developers wiki, though it's extremely outdated. In it, a “random unrelated note” is given:
Random unrelated note: the panel should have a lower priority value so it starts in the group prior to xfdesktop. This way it'll set its struts before xfdesktop starts, which means xfdesktop won't have to redraw itself after _NET_WORKAREA changes.
Would that be a cause for concern?
UPDATE: Yes, there are. Assigning it to a higher priority group than the panel duplicates some of the items on the panel. There is probably a bunch of other quirks.
Besides, it didn't work as I hoped it would.
Last edited by KBar (2022-02-18 16:27:30)
Remember to edit the subject of your topic to include the [SOLVED] tag once you're satisfied with the answers or have found a solution (in which case, don't forget to share it as well), so that other members of the community can quickly refer to it and save their time. Pretty please!
Offline
The script has become a bit more complex and multi-purpose but it does exactly what I wanted. Some final touches and it's complete.
Is there a way to toggle panel plugins on-demand? The window control buttons are plugin-9, plugin-13 and plugin-16. Any hidden setting for hiding (i.e. not displaying) them? I have these two functions:
decrease_panel_length()
{
xfconf-query --channel xfce4-panel -p /panels/panel-2/length --set 2
}
increase_panel_length()
{
xfconf-query --channel xfce4-panel -p /panels/panel-2/length --set 5
}
…for showing only the close button on desktop but the minimize button sticks out just a little bit. I'd like to be able to toggle its visibility on and off in the script.
CSS would work but requires a restart of the whole panel, which is obviously not desired.
UPDATE: Alright, invisible characters to the rescue. I just prepended U+2000 EN QUAD (U+2800 BRAILLE PATTERN BLANK also works) to its name and also added another command to toggle the show-label property. Magic!
Last edited by KBar (2022-02-20 09:17:31)
Remember to edit the subject of your topic to include the [SOLVED] tag once you're satisfied with the answers or have found a solution (in which case, don't forget to share it as well), so that other members of the community can quickly refer to it and save their time. Pretty please!
Offline
Alright, I have finished working on my panel-2. Here's how it looks and behaves: https://webmshare.com/play/PbmAx
And here's the script:
#!/bin/sh
# This shell script changes the window state of panel-2
# depending on whether the active window is maximized or not.
# Inspired from this post by ToZ on Xfce Forums:
# https://forum.xfce.org/viewtopic.php?pid=64715#p64715
# First, save PID of xfce4-panel:
panel_pid="$(pgrep --full --exact 'xfce4-panel')"
# Next, assign window IDs to variables:
panel2_hidden="$(wmctrl -lpG | awk -v panel_pid="${panel_pid}"\
'$3 == panel_pid && $4 && $5 == -9999 { print $1 }')"
panel2="$(wmctrl -lpG | awk -v panel_pid="${panel_pid}" '$3 == panel_pid'\
' && $4 && $5 == -9999 { print panel2 } { panel2 = $1 }')"
desktop_wid="$(xprop -spy -root |
while read -r desktop_wid
do
case "${desktop_wid}" in
*XFCE_DESKTOP_WINDOW*)
printf "%s" "${desktop_wid##* # }"
break;;
*)
continue
esac
done
)"
add_panel_above()
{
case "$(xprop -id "${panel2}" _NET_WM_STATE)" in
*_NET_WM_STATE_ABOVE*)
:;;
*_NET_WM_STATE_BELOW*)
wmctrl -ir "${panel2_hidden}" -b remove,below &&
wmctrl -ir "${panel2}" -b remove,below
esac
wmctrl -ir "${panel2_hidden}" -b add,above &&
wmctrl -ir "${panel2}" -b add,above
}
add_panel_below()
{
case "$(xprop -id "${panel2_hidden}" _NET_WM_STATE)" in
*_NET_WM_STATE_BELOW*)
:;;
*_NET_WM_STATE_ABOVE*)
wmctrl -ir "${panel2_hidden}" -b remove,above &&
wmctrl -ir "${panel2}" -b remove,above
esac
wmctrl -ir "${panel2_hidden}" -b add,below &&
wmctrl -ir "${panel2}" -b add,below
}
toggle_panel_window_state()
{
case "${active_window_state}" in
*"_NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT"*)
add_panel_above;;
*)
add_panel_below
esac
}
# Set its xfconf properties for desktop:
set_panel_xfconf_properties()
{
xfconf-query \
--channel xfce4-panel \
--property /panels/panel-2/length \
--set 2
xfconf-query \
--channel xfce4-panel \
--property /plugins/plugin-13/show-label \
--set true
xfconf-query \
--channel xfce4-panel \
--property /panels/panel-2/background-image \
--set "$HOME/.config/gtk-3.0/assets/panel2_close_button.png"
}
# Reset its xfconf properties for other windows:
reset_panel_xfconf_properties()
{
if [ "$(xfconf-query \
--channel xfce4-panel \
--property /panels/panel-2/length)" -eq 2 ]
then
xfconf-query \
--channel xfce4-panel \
--property /panels/panel-2/length \
--set 5
fi
if [ "$(xfconf-query \
--channel xfce4-panel \
--property /plugins/plugin-13/show-label)" = "true" ]
then
xfconf-query \
--channel xfce4-panel \
--property /plugins/plugin-13/show-label \
--set false
fi
if [ "$(xfconf-query \
--channel xfce4-panel \
--property /panels/panel-2/background-image)" = \
"$HOME/.config/gtk-3.0/assets/panel2_close_button.png" ]
then
xfconf-query \
--channel xfce4-panel \
--property /panels/panel-2/background-image \
--set "$HOME/.config/gtk-3.0/assets/panel2.png"
fi
}
monitor_active_window_state()
{
xprop -spy -id "${active_wid}" _NET_WM_STATE |
while read -r active_window_state
do
case "${active_window_state}" in
*_NET_WM_STATE_FOCUSED*)
toggle_panel_window_state;;
*)
break
esac
done
}
# Set its state on startup:
add_panel_above & set_panel_xfconf_properties
# Use xprop to monitor and handle active window property change events:
xprop -spy -root _NET_ACTIVE_WINDOW |
while read -r active_wid
# Suggested by tirnanog from #linux on irc.libera.chat.
do
case "${active_wid}" in
*0x0,*)
continue;;
*"${desktop_wid}"*)
add_panel_above
set_panel_xfconf_properties;;
*)
active_wid="${active_wid##* # }" &&
active_wid="${active_wid%,*}" &&
monitor_active_window_state &
reset_panel_xfconf_properties
esac
done
Poking at xprop every second seemed excessive and expensive so I looked for a reasonable alternative. Its -spy option was a good start but I didn't exactly know how to use it to extract the data that I needed. So I asked this question on Libera's #linux channel and tirnanog came up with a brilliant solution which involved using read inside a while loop.
After a while, I realized the short-sightedness of my approach and discovered one major flaw: it didn't account for the window state changes of the active window. I had to add another function with a similar while construct and fixed a lot of bugs along the way. Now, it just works!
Thank you ToZ for guiding and enlightening me, and also a big shoutout to tirnanog whose piece of code was another revelation to me.
Last edited by KBar (2022-02-25 10:40:42)
Remember to edit the subject of your topic to include the [SOLVED] tag once you're satisfied with the answers or have found a solution (in which case, don't forget to share it as well), so that other members of the community can quickly refer to it and save their time. Pretty please!
Offline
Hello!
The tasklist (the deskbar on the left) has static colors and that felt a bit boring to me. So, I've been trying to re-implement this feature in a shell script using ImageMagick. Currently, it just prints out the computed average background color values for each channel:
#!/bin/sh
QUAD_CORNER_WEIGHT_NW=3
QUAD_CORNER_WEIGHT_NE=1
QUAD_CORNER_WEIGHT_SW=3
QUAD_CORNER_WEIGHT_SE=1
QUAD_CORNER_WEIGHT_CENTER=2
QUAD_CORNER_WEIGHT_TOTAL=$((\
QUAD_CORNER_WEIGHT_NW+\
QUAD_CORNER_WEIGHT_NE+\
QUAD_CORNER_WEIGHT_SW+\
QUAD_CORNER_WEIGHT_SE+\
QUAD_CORNER_WEIGHT_CENTER))
xfce_backdrop_get_average_value()
{
average_red=$((\
((corner1_red*QUAD_CORNER_WEIGHT_NW)+\
(corner2_red*QUAD_CORNER_WEIGHT_NE)+\
(corner3_red*QUAD_CORNER_WEIGHT_SW)+\
(corner4_red*QUAD_CORNER_WEIGHT_SE)+\
(center_red*QUAD_CORNER_WEIGHT_CENTER))/QUAD_CORNER_WEIGHT_TOTAL))
average_green=$((\
((corner1_green*QUAD_CORNER_WEIGHT_NW)+\
(corner2_green*QUAD_CORNER_WEIGHT_NE)+\
(corner3_green*QUAD_CORNER_WEIGHT_SW)+\
(corner4_green*QUAD_CORNER_WEIGHT_SE)+\
(center_green*QUAD_CORNER_WEIGHT_CENTER))/QUAD_CORNER_WEIGHT_TOTAL))
average_blue=$((\
((corner1_blue*QUAD_CORNER_WEIGHT_NW)+\
(corner2_blue*QUAD_CORNER_WEIGHT_NE)+\
(corner3_blue*QUAD_CORNER_WEIGHT_SW)+\
(corner4_blue*QUAD_CORNER_WEIGHT_SE)+\
(center_blue*QUAD_CORNER_WEIGHT_CENTER))/QUAD_CORNER_WEIGHT_TOTAL))
average="${average_red},${average_green},${average_blue}"
printf "${average}\n"
}
xfce_backdrop_get_quad_average()
{
# samples four corners
# c1-----c2
# | |
# c3-----c4
# I'd like to combine these two convert commands to reduce forking/execing
# but using parentheses in various places didn't allow me to achieve that
corners=$(convert "${backdrop}" -crop 2x2@ +repage +adjoin -sample 1x1 rgb:- |
od --address-radix=n --format=uC --width=12)
read -r \
corner1_red corner1_green corner1_blue \
corner2_red corner2_green corner2_blue \
corner3_red corner3_green corner3_blue \
corner4_red corner4_green corner4_blue \
<<-eof
${corners}
eof
center=$(convert "${backdrop}" -gravity Center \
-crop $((width/2))x$((height/2))+0+0 +repage -sample 1x1 rgb:- |
od --address-radix=n --format=uC --width=12)
read -r center_red center_green center_blue <<-eof
$center
eof
xfce_backdrop_get_average_value
}
xfce_backdrop_get_image_size()
{
size="$(identify -format "%wx%h" "${backdrop}")"
width="${size%x*}"
height="${size#*x}"
xfce_backdrop_get_quad_average
}
xfconf-query --channel xfce4-desktop --monitor --verbose |
while read -r xfdesktop
do
case "${xfdesktop}" in
*"/last-image ("*)
backdrop="${xfdesktop##*\(}"
backdrop="${backdrop%\)}"
xfce_backdrop_get_image_size;;
*)
continue
esac
done
As to the actual process of setting the background color of the deskbar, it seems that I have two options:
Write the newly read values directly to the gtk.css file.
requires a panel restart;
preserves the side line.
Use xfconf.
I haven't decided on this yet. Obviously, changing the color through xfconf is superior and preferable because it's applied immediately, in a more natural way. However, the fact that the following rule:
.background.panel.xfce4-panel.deskbar {
background-color: @launcher_bg;
border-right: 1px solid @side_line;
border-top-style: none;
}
does not affect external panel plugins is annoying and the resulting look is hideous. When background is set to use system style, the border is drawn correctly; the rule is applied to all plugins in the deskbar.
What would be your thoughts and suggestions? How would I solve this border problem if I were to choose the Xfconf method?
There are also xfwm-tabwin and the logout dialog, which would also need re-coloring but since they do not have the same immediate visibility of the deskbar, they don't need to be changed dynamically, so I'm fine with setting their colors in gtk.css.
Remember to edit the subject of your topic to include the [SOLVED] tag once you're satisfied with the answers or have found a solution (in which case, don't forget to share it as well), so that other members of the community can quickly refer to it and save their time. Pretty please!
Offline
How is the border initially drawn? Is it an element of the panel, or the widgets on the panel? Does the missing border after colour change only impact external plugins? What if you manually changed the colour using the panel GUI - does it exhibit the same problem?
btw, I did something similar with colour sampling and panel background changes a while back: https://forum.xfce.org/viewtopic.php?id=9597.
Please remember to mark your thread [SOLVED] to make it easier for others to find
--- How To Ask For Help | FAQ | Developer Wiki | Community | Contribute ---
Offline
How is the border initially drawn? Is it an element of the panel, or the widgets on the panel?
It's drawn as deskbar's border-right.
.background.panel.xfce4-panel.deskbar {
background-color: @launcher_bg;
border-right: 1px solid @side_line;
border-top-style: none;
}
Does the missing border after colour change only impact external plugins?
Yes, only external plugins. If background style is set to system style, external plugins pick up whatever is declared in the above rule set. If it is set to solid color, external plugins lose the border.
What if you manually changed the colour using the panel GUI - does it exhibit the same problem?
Yes, it doesn't matter how background style is changed. The border is lost as soon as it's set to solid color, which I really want for the script to work.
btw, I did something similar with colour sampling and panel background changes a while back: https://forum.xfce.org/viewtopic.php?id=9597.
That's absolutely incredible! Thank you so much.
Remember to edit the subject of your topic to include the [SOLVED] tag once you're satisfied with the answers or have found a solution (in which case, don't forget to share it as well), so that other members of the community can quickly refer to it and save their time. Pretty please!
Offline
Alright, I can add border-right to whiskermenu-button and thunar-tpa-2 individually but its color is way off. I have this color defined in my gtk.css:
@define-color side_line rgba(255, 255, 255, 0.15);
If background style is set to solid color, the background of external plugins take up as much space as possible and since the border's alpha is 0.15, both colors blend in and ruin the whole look. I've tried everything and it looks like that this cannot be fixed through CSS.
This suggests that borders should be updated automatically based on panel's snap position. Why is it not working on my system?
Remember to edit the subject of your topic to include the [SOLVED] tag once you're satisfied with the answers or have found a solution (in which case, don't forget to share it as well), so that other members of the community can quickly refer to it and save their time. Pretty please!
Offline
Oh, I see. Borders are set only if system colors are being used.
void
panel_base_window_set_borders (PanelBaseWindow *window,
PanelBorders borders)
{
PanelBaseWindowPrivate *priv = window->priv;
panel_return_if_fail (PANEL_IS_BASE_WINDOW (window));
if (priv->borders != borders)
{
priv->borders = borders;
gtk_widget_queue_resize (GTK_WIDGET (window));
/* Re-draw the borders if system colors are being used */
if (window->background_style == PANEL_BG_STYLE_NONE)
panel_base_window_reset_background_css (window);
}
}
Borders are transparent for solid color background style:
else if (window->background_style == PANEL_BG_STYLE_COLOR
&& window->background_rgba != NULL)
{
panel_base_window_set_background_color_css (window);
panel_base_window_set_plugin_data (window,
panel_base_window_set_plugin_background_color);
}
panel_base_window_set_background_color_css (PanelBaseWindow *window) {
gchar *css_string;
panel_return_if_fail (window->background_rgba != NULL);
css_string = g_strdup_printf (".xfce4-panel.background { background-color: %s; border-color: transparent; } %s",
gdk_rgba_to_string (window->background_rgba),
PANEL_BASE_CSS);
panel_base_window_set_background_css (window, css_string);
}
Last edited by KBar (2022-03-11 14:57:01)
Remember to edit the subject of your topic to include the [SOLVED] tag once you're satisfied with the answers or have found a solution (in which case, don't forget to share it as well), so that other members of the community can quickly refer to it and save their time. Pretty please!
Offline
Oh, I see. Borders are set only if system colors are being used.
Nice find.
Borders are transparent for solid color background style:
Would it work if you forced the border solid in ~/.config/gtk-3.0/gtk.css? It should have a higher priority than the application code.
Please remember to mark your thread [SOLVED] to make it easier for others to find
--- How To Ask For Help | FAQ | Developer Wiki | Community | Contribute ---
Offline
Would it work if you forced the border solid in ~/.config/gtk-3.0/gtk.css? It should have a higher priority than the application code.
For some unknown reason, it doesn't work, unfortunately.
The borders are drawn by panel_base_window_reset_background_css (window) which isn't called from panel_base_window_set_plugin_background_color:
/* Set correct border style depending on panel position and length */
if (priv->borders != PANEL_BORDER_NONE)
{
border_side = g_strdup_printf ("%s %s %s %s",
PANEL_HAS_FLAG (priv->borders, PANEL_BORDER_TOP) ? "solid" : "none",
PANEL_HAS_FLAG (priv->borders, PANEL_BORDER_RIGHT) ? "solid" : "none",
PANEL_HAS_FLAG (priv->borders, PANEL_BORDER_BOTTOM) ? "solid" : "none",
PANEL_HAS_FLAG (priv->borders, PANEL_BORDER_LEFT) ? "solid" : "none");
}
if (border_side)
{
color_text = gdk_rgba_to_string (background_rgba);
base_css = g_strdup_printf ("%s .xfce4-panel.background { border-style: %s; border-width: 1px; border-color: shade(%s, 0.7); }",
PANEL_BASE_CSS, border_side, color_text);
gtk_css_provider_load_from_data (window->priv->css_provider, base_css, -1, NULL);
g_free (base_css);
g_free (color_text);
g_free (border_side);
}
else
gtk_css_provider_load_from_data (window->priv->css_provider, PANEL_BASE_CSS, -1, NULL);
gtk_style_context_add_provider (context,
GTK_STYLE_PROVIDER (window->priv->css_provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
gdk_rgba_free (background_rgba);
}
Remember to edit the subject of your topic to include the [SOLVED] tag once you're satisfied with the answers or have found a solution (in which case, don't forget to share it as well), so that other members of the community can quickly refer to it and save their time. Pretty please!
Offline
Another test from a new user:
Conclusion: base window properties do not affect external plugins if style is set to solid color because background_rgba takes priority. panel_base_window_set_plugin_background_color is called last. It repaints over the base panel window with background_rgba.
static void
panel_base_window_set_plugin_background_color (GtkWidget *widget,
gpointer user_data)
{
PanelBaseWindow *window = PANEL_BASE_WINDOW (user_data);
GdkRGBA *color;
panel_return_if_fail (XFCE_IS_PANEL_PLUGIN_PROVIDER (widget));
panel_return_if_fail (PANEL_IS_BASE_WINDOW (user_data));
/* send null if the style is not a bg color */
color = window->background_style == PANEL_BG_STYLE_COLOR ? window->background_
rgba : NULL;
if (PANEL_IS_PLUGIN_EXTERNAL (widget))
panel_plugin_external_set_background_color (PANEL_PLUGIN_EXTERNAL (widget), color);
}
Last edited by KBar (2022-03-12 02:40:45)
Remember to edit the subject of your topic to include the [SOLVED] tag once you're satisfied with the answers or have found a solution (in which case, don't forget to share it as well), so that other members of the community can quickly refer to it and save their time. Pretty please!
Offline
This is more prominent if background's alpha channel is set all the way down to 0:
Remember to edit the subject of your topic to include the [SOLVED] tag once you're satisfied with the answers or have found a solution (in which case, don't forget to share it as well), so that other members of the community can quickly refer to it and save their time. Pretty please!
Offline
I wonder if this is by design or an oversight. I mean, it looks like its by design given that it's coded to do so, but what would the rationale be? Maybe open a bug report to see what the developer's say?
Please remember to mark your thread [SOLVED] to make it easier for others to find
--- How To Ask For Help | FAQ | Developer Wiki | Community | Contribute ---
Offline
Very sorry, I didn't have access to the Internet for the whole week.
You're right. The way it works right now doesn't make a whole lot of sense. I'm probably going to ask this on the mailing list.
Another thing I forgot to mention: the base window and internal plugins aren't updated immediately. For the tasklist buttons to pick up the new color, they have to be hovered upon, for separator it is trickier: either open a new window or close an existing one, or right-click on it and open its properties dialog.
I suspect the issue lies here (gtk_style_context_remove_provider, in particular):
static void
panel_base_window_set_background_css (PanelBaseWindow *window, gchar *css_string) {
GtkStyleContext *context;
context = gtk_widget_get_style_context (GTK_WIDGET (window));
/* Reset the css style provider */
gtk_style_context_remove_provider (context, GTK_STYLE_PROVIDER (window->priv->css_provider));
gtk_css_provider_load_from_data (window->priv->css_provider, css_string, -1, NULL);
gtk_style_context_add_provider (context,
GTK_STYLE_PROVIDER (window->priv->css_provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
g_free (css_string);
}
I can see the background-rgba updated in real-time, the new value is put into memory. I guess the old value is not being cleared correctly. Any hints or workarounds?
Last edited by KBar (2022-03-18 15:48:34)
Remember to edit the subject of your topic to include the [SOLVED] tag once you're satisfied with the answers or have found a solution (in which case, don't forget to share it as well), so that other members of the community can quickly refer to it and save their time. Pretty please!
Offline
Looks like this "drawing over" behavior was fixed somewhere along as it doesn't appear in Xubuntu 22.04
Do you know if xfwm4 theme settings can be defined in themerc file alone? Both xfwm4's xfconf channel and themerc share identical keys and loadSettings() in xfwm4 kind of suggests that they really are interchangeable.
I ask this because I want to back up my Ambiance xfwm4 theme and with themerc file it's objectively much easier.
Remember to edit the subject of your topic to include the [SOLVED] tag once you're satisfied with the answers or have found a solution (in which case, don't forget to share it as well), so that other members of the community can quickly refer to it and save their time. Pretty please!
Offline
[ Generated in 0.019 seconds, 7 queries executed - Memory usage: 777.95 KiB (Peak: 842.8 KiB) ]