all repos — tint2 @ d5dfda296f66e41b18e92f005709050bfa31f036

fork of the tint2 desktop panel for my custom setup - only minimized windows across all desktops for the taskbar

Buttons
o9000 mrovi9000@gmail.com
commit

d5dfda296f66e41b18e92f005709050bfa31f036

parent

89d57f893c3f5d716d91239eab5df261583eadee

M CMakeLists.txtCMakeLists.txt

@@ -100,6 +100,7 @@ src/launcher

src/tooltip src/util src/execplugin + src/button src/freespace src/separator ${X11_INCLUDE_DIRS}

@@ -128,6 +129,7 @@ src/taskbar/taskbar.c

src/taskbar/taskbarname.c src/tooltip/tooltip.c src/execplugin/execplugin.c + src/button/button.c src/freespace/freespace.c src/separator/separator.c src/tint2rc.c
M ChangeLogChangeLog

@@ -1,3 +1,7 @@

+2017-03-25 master +- Enhancements: + - New plugin: button. + 2017-03-25 0.13.3 - Fixes: - Fixed autohide for non-bottom panels (issue #632)
M doc/manual.htmldoc/manual.html

@@ -229,6 +229,7 @@ <li><p><a href="#clock">Clock</a></p></li>

<li><p><a href="#tooltip">Tooltip</a></p></li> <li><p><a href="#battery">Battery</a></p></li> <li><p><a href="#executor">Executor</a></p></li> +<li><p><a href="#button">Button</a></p></li> <li><p><a href="#separator">Separator</a></p></li> <li><p><a href="#example-configuration">Example configuration</a></p></li> </ul>

@@ -359,6 +360,7 @@ <li><code>B</code> shows the Battery status</li>

<li><code>C</code> shows the Clock</li> <li><code>F</code> adds an extensible spacer (freespace). You can specify more than one. Has no effect if <code>T</code> is also present. <em>(since 0.12)</em></li> <li><code>E</code> adds an executor plugin. You can specify more than one. <em>(since 0.12.4)</em></li> +<li><code>P</code> adds a push button. You can specify more than one. <em>(since 0.14)</em></li> <li><code>:</code> adds a separator. You can specify more than one. <em>(since 0.13.0)</em></li> </ul> <p>For example, <code>panel_items = STC</code> will show the systray, the taskbar and the clock (from left to right).</p></li>

@@ -650,6 +652,23 @@ execp_command = stdbuf -oL bwm-ng -o csv -t 1000 | awk -F ';' '/total/ { printf "Net: %.0f Mb/s\n", ($5*8/1.0e6) }; fflush(stdout)'

execp_continuous = 1 execp_interval = 1 </code></pre> +<h3 id="button">Button<a name="button" href="#button" class="md2man-permalink" title="permalink"></a></h3> +<ul> +<li><p><code>button = new</code> : Begins the configuration of a new button. Multiple such plugins are supported; just use multiple <code>P</code>s in <code>panel_items</code>. <em>(since 0.14)</em></p></li> +<li><p><code>button_icon = text</code> : Name or path of icon (or empty). <em>(since 0.14)</em></p></li> +<li><p><code>button_text = text</code> : Text to display (or empty). <em>(since 0.14)</em></p></li> +<li><p><code>button_tooltip = text</code> : The tooltip (or empty). <em>(since 0.14)</em></p></li> +<li><p><code>button_font = [FAMILY-LIST] [STYLE-OPTIONS] [SIZE]</code> : The font used to draw the text. <em>(since 0.14)</em></p></li> +<li><p><code>button_font_color = color opacity</code> : The font color. <em>(since 0.14)</em></p></li> +<li><p><code>button_background_id = integer</code> : Which background to use. <em>(since 0.14)</em></p></li> +<li><p><code>button_centered = boolean (0 or 1)</code> : Whether to center the text. <em>(since 0.14)</em></p></li> +<li><p><code>button_padding = horizontal_padding vertical_padding spacing_between_icon_and_text</code> <em>(since 0.14)</em></p></li> +<li><p><code>button_lclick_command = text</code> : Command to execute on left click. If not defined, <code>execp_command</code> is executed immediately, unless it is currently running. <em>(since 0.14)</em></p></li> +<li><p><code>button_mclick_command = text</code> : Command to execute on right click. If not defined, <code>execp_command</code> is executed immediately, unless it is currently running. <em>(since 0.14)</em></p></li> +<li><p><code>button_rclick_command = text</code> : Command to execute on middle click. If not defined, <code>execp_command</code> is executed immediately, unless it is currently running. <em>(since 0.14)</em></p></li> +<li><p><code>button_uwheel_command = text</code> : Command to execute on wheel scroll up. If not defined, <code>execp_command</code> is executed immediately, unless it is currently running. <em>(since 0.14)</em></p></li> +<li><p><code>button_dwheel_command = text</code> : Command to execute on wheel scroll down. If not defined, <code>execp_command</code> is executed immediately, unless it is currently running. <em>(since 0.14)</em></p></li> +</ul> <h3 id="separator">Separator<a name="separator" href="#separator" class="md2man-permalink" title="permalink"></a></h3> <ul> <li><p><code>separator = new</code> : Begins the configuration of a new separator. Multiple such plugins are supported; just use multiple <code>:</code>s in <code>panel_items</code>. <em>(since 0.13.0)</em></p></li>

@@ -659,142 +678,7 @@ <li><p><code>separator_style = [empty | line | dots]</code> : The separator style. <em>(since 0.13.0)</em></p></li>

<li><p><code>separator_size = integer</code> : The thickness of the separator. Does not include the border and padding. For example, if the style is <code>line</code>, this is the line thickness; if the style is <code>dots</code>, this is the dot&#39;s diameter. <em>(since 0.13.0)</em></p></li> <li><p><code>separator_padding = side_padding cap_padding</code> : The padding to add to the sides of the separator, in pixels. <em>(since 0.13.0)</em></p></li> </ul> -<h3 id="example-configuration">Example configuration<a name="example-configuration" href="#example-configuration" class="md2man-permalink" title="permalink"></a></h3><pre class="highlight plaintext"><code>#--------------------------------------------- -## TINT2 CONFIG FILE -#--------------------------------------------- - -#--------------------------------------------- -## BACKGROUND AND BORDER -#--------------------------------------------- -rounded = 7 -border_width = 2 -background_color = #000000 60 -border_color = #ffffff 18 - -rounded = 5 -border_width = 0 -background_color = #ffffff 40 -border_color = #ffffff 50 - -rounded = 5 -border_width = 0 -background_color = #ffffff 18 -border_color = #ffffff 70 - -#--------------------------------------------- -## PANEL -#--------------------------------------------- -panel_monitor = all -panel_position = bottom center -panel_size = 94% 30 -panel_margin = 0 0 -panel_padding = 7 0 -font_shadow = 0 -panel_background_id = 1 -wm_menu = 0 -panel_dock = 0 -panel_layer = bottom - -#--------------------------------------------- -## TASKBAR -#--------------------------------------------- -#taskbar_mode = multi_desktop -taskbar_mode = single_desktop -taskbar_padding = 2 3 2 -taskbar_background_id = 0 -#taskbar_active_background_id = 0 - -#--------------------------------------------- -## TASKS -#--------------------------------------------- -task_icon = 1 -task_text = 1 -task_maximum_size = 140 35 -task_centered = 1 -task_padding = 6 3 -task_font = sans 7 -task_font_color = #ffffff 70 -task_background_id = 3 -task_icon_asb = 100 0 0 -## replace STATUS by 'urgent', 'active' or 'iconified' -#task_STATUS_background_id = 2 -#task_STATUS_font_color = #ffffff 85 -#task_STATUS_icon_asb = 100 0 0 -## example: -task_active_background_id = 2 -task_active_font_color = #ffffff 85 -task_active_icon_asb = 100 0 0 -urgent_nb_of_blink = 8 - -#--------------------------------------------- -## SYSTRAYBAR -#--------------------------------------------- -systray = 1 -systray_padding = 0 4 5 -systray_background_id = 0 -systray_sort = left2right -systray_icon_size = 0 -systray_icon_asb = 100 0 0 - -#--------------------------------------------- -## CLOCK -#--------------------------------------------- -time1_format = %H:%M -time1_font = sans 8 -time2_format = %A %d %B -time2_font = sans 6 -clock_font_color = #ffffff 76 -clock_padding = 1 0 -clock_background_id = 0 -#clock_lclick_command = xclock -clock_rclick_command = orage -#clock_tooltip = %A %d %B -#time1_timezone = :US/Hawaii -#time2_timezone = :Europe/Berlin -#clock_tooltip_timezone = :/usr/share/zoneinfo/Europe/Paris - -#--------------------------------------------- -## BATTERY -#--------------------------------------------- -battery = 0 -battery_hide = 98 -battery_low_status = 10 -battery_low_cmd = notify-send "battery low" -bat1_font = sans 8 -bat2_font = sans 6 -battery_font_color = #ffffff 76 -battery_padding = 1 0 -battery_background_id = 0 - -#--------------------------------------------- -## TOOLTIP -#--------------------------------------------- -tooltip = 0 -tooltip_padding = 2 2 -tooltip_show_timeout = 0.7 -tooltip_hide_timeout = 0.3 -tooltip_background_id = 1 -tooltip_font_color = #OOOOOO 80 -tooltip_font = sans 10 - -#--------------------------------------------- -## MOUSE ACTION ON TASK -#--------------------------------------------- -mouse_middle = none -mouse_right = close -mouse_scroll_up = toggle -mouse_scroll_down = iconify - -#--------------------------------------------- -## AUTOHIDE OPTIONS -#--------------------------------------------- -autohide = 0 -autohide_show_timeout = 0.3 -autohide_hide_timeout = 2 -autohide_height = 4 -strut_policy = minimum -</code></pre> -<h2 id="author">AUTHOR<a name="author" href="#author" class="md2man-permalink" title="permalink"></a></h2><p>tint2 was written by Thierry Lorthiois <a href="mailto:lorthiois@bbsoft.fr">lorthiois@bbsoft.fr</a>. +<h3 id="example-configuration">Example configuration<a name="example-configuration" href="#example-configuration" class="md2man-permalink" title="permalink"></a></h3><p>See /etc/xdg/tint2/tint2rc.</p><h2 id="author">AUTHOR<a name="author" href="#author" class="md2man-permalink" title="permalink"></a></h2><p>tint2 was written by Thierry Lorthiois <a href="mailto:lorthiois@bbsoft.fr">lorthiois@bbsoft.fr</a>. It is based on ttm, originally written by Pål Staurland <a href="mailto:staura@gmail.com">staura@gmail.com</a>.</p><p>This manual page was originally written by Daniel Moerner <a href="mailto:dmoerner@gmail.com">dmoerner@gmail.com</a>, for the Debian project (but may be used by others). It was adopted from the tint2 docs.</p><h2 id="see-also">SEE ALSO<a name="see-also" href="#see-also" class="md2man-permalink" title="permalink"></a></h2><p>The main website <a href="https://gitlab.com/o9000/tint2">https://gitlab.com/o9000/tint2</a> and the wiki page at <a href="https://gitlab.com/o9000/tint2/wikis/home">https://gitlab.com/o9000/tint2/wikis/home</a>.</p><p>This documentation is also provided in HTML and Markdown format in the system&#39;s default location
M doc/tint2.1doc/tint2.1

@@ -67,6 +67,8 @@ Battery \[la]#battery\[ra]

.IP \(bu 2 Executor \[la]#executor\[ra] .IP \(bu 2 +Button \[la]#button\[ra] +.IP \(bu 2 Separator \[la]#separator\[ra] .IP \(bu 2 Example configuration \[la]#example-configuration\[ra]

@@ -293,6 +295,8 @@ .IP \(bu 2

\fB\fCF\fR adds an extensible spacer (freespace). You can specify more than one. Has no effect if \fB\fCT\fR is also present. \fI(since 0.12)\fP .IP \(bu 2 \fB\fCE\fR adds an executor plugin. You can specify more than one. \fI(since 0.12.4)\fP +.IP \(bu 2 +\fB\fCP\fR adds a push button. You can specify more than one. \fI(since 0.14)\fP .IP \(bu 2 \fB\fC:\fR adds a separator. You can specify more than one. \fI(since 0.13.0)\fP .RE

@@ -800,6 +804,37 @@ execp_continuous = 1

execp_interval = 1 .fi .RE +.SS Button +.RS +.IP \(bu 2 +\fB\fCbutton = new\fR : Begins the configuration of a new button. Multiple such plugins are supported; just use multiple \fB\fCP\fRs in \fB\fCpanel_items\fR\&. \fI(since 0.14)\fP +.IP \(bu 2 +\fB\fCbutton_icon = text\fR : Name or path of icon (or empty). \fI(since 0.14)\fP +.IP \(bu 2 +\fB\fCbutton_text = text\fR : Text to display (or empty). \fI(since 0.14)\fP +.IP \(bu 2 +\fB\fCbutton_tooltip = text\fR : The tooltip (or empty). \fI(since 0.14)\fP +.IP \(bu 2 +\fB\fCbutton_font = [FAMILY\-LIST] [STYLE\-OPTIONS] [SIZE]\fR : The font used to draw the text. \fI(since 0.14)\fP +.IP \(bu 2 +\fB\fCbutton_font_color = color opacity\fR : The font color. \fI(since 0.14)\fP +.IP \(bu 2 +\fB\fCbutton_background_id = integer\fR : Which background to use. \fI(since 0.14)\fP +.IP \(bu 2 +\fB\fCbutton_centered = boolean (0 or 1)\fR : Whether to center the text. \fI(since 0.14)\fP +.IP \(bu 2 +\fB\fCbutton_padding = horizontal_padding vertical_padding spacing_between_icon_and_text\fR \fI(since 0.14)\fP +.IP \(bu 2 +\fB\fCbutton_lclick_command = text\fR : Command to execute on left click. If not defined, \fB\fCexecp_command\fR is executed immediately, unless it is currently running. \fI(since 0.14)\fP +.IP \(bu 2 +\fB\fCbutton_mclick_command = text\fR : Command to execute on right click. If not defined, \fB\fCexecp_command\fR is executed immediately, unless it is currently running. \fI(since 0.14)\fP +.IP \(bu 2 +\fB\fCbutton_rclick_command = text\fR : Command to execute on middle click. If not defined, \fB\fCexecp_command\fR is executed immediately, unless it is currently running. \fI(since 0.14)\fP +.IP \(bu 2 +\fB\fCbutton_uwheel_command = text\fR : Command to execute on wheel scroll up. If not defined, \fB\fCexecp_command\fR is executed immediately, unless it is currently running. \fI(since 0.14)\fP +.IP \(bu 2 +\fB\fCbutton_dwheel_command = text\fR : Command to execute on wheel scroll down. If not defined, \fB\fCexecp_command\fR is executed immediately, unless it is currently running. \fI(since 0.14)\fP +.RE .SS Separator .RS .IP \(bu 2

@@ -817,144 +852,7 @@ \fB\fCseparator_padding = side_padding cap_padding\fR : The padding to add to the sides of the separator, in pixels. \fI(since 0.13.0)\fP

.RE .SS Example configuration .PP -.RS -.nf -#\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- -## TINT2 CONFIG FILE -#\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- - -#\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- -## BACKGROUND AND BORDER -#\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- -rounded = 7 -border_width = 2 -background_color = #000000 60 -border_color = #ffffff 18 - -rounded = 5 -border_width = 0 -background_color = #ffffff 40 -border_color = #ffffff 50 - -rounded = 5 -border_width = 0 -background_color = #ffffff 18 -border_color = #ffffff 70 - -#\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- -## PANEL -#\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- -panel_monitor = all -panel_position = bottom center -panel_size = 94% 30 -panel_margin = 0 0 -panel_padding = 7 0 -font_shadow = 0 -panel_background_id = 1 -wm_menu = 0 -panel_dock = 0 -panel_layer = bottom - -#\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- -## TASKBAR -#\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- -#taskbar_mode = multi_desktop -taskbar_mode = single_desktop -taskbar_padding = 2 3 2 -taskbar_background_id = 0 -#taskbar_active_background_id = 0 - -#\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- -## TASKS -#\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- -task_icon = 1 -task_text = 1 -task_maximum_size = 140 35 -task_centered = 1 -task_padding = 6 3 -task_font = sans 7 -task_font_color = #ffffff 70 -task_background_id = 3 -task_icon_asb = 100 0 0 -## replace STATUS by 'urgent', 'active' or 'iconified' -#task_STATUS_background_id = 2 -#task_STATUS_font_color = #ffffff 85 -#task_STATUS_icon_asb = 100 0 0 -## example: -task_active_background_id = 2 -task_active_font_color = #ffffff 85 -task_active_icon_asb = 100 0 0 -urgent_nb_of_blink = 8 - -#\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- -## SYSTRAYBAR -#\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- -systray = 1 -systray_padding = 0 4 5 -systray_background_id = 0 -systray_sort = left2right -systray_icon_size = 0 -systray_icon_asb = 100 0 0 - -#\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- -## CLOCK -#\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- -time1_format = %H:%M -time1_font = sans 8 -time2_format = %A %d %B -time2_font = sans 6 -clock_font_color = #ffffff 76 -clock_padding = 1 0 -clock_background_id = 0 -#clock_lclick_command = xclock -clock_rclick_command = orage -#clock_tooltip = %A %d %B -#time1_timezone = :US/Hawaii -#time2_timezone = :Europe/Berlin -#clock_tooltip_timezone = :/usr/share/zoneinfo/Europe/Paris - -#\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- -## BATTERY -#\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- -battery = 0 -battery_hide = 98 -battery_low_status = 10 -battery_low_cmd = notify\-send "battery low" -bat1_font = sans 8 -bat2_font = sans 6 -battery_font_color = #ffffff 76 -battery_padding = 1 0 -battery_background_id = 0 - -#\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- -## TOOLTIP -#\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- -tooltip = 0 -tooltip_padding = 2 2 -tooltip_show_timeout = 0.7 -tooltip_hide_timeout = 0.3 -tooltip_background_id = 1 -tooltip_font_color = #OOOOOO 80 -tooltip_font = sans 10 - -#\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- -## MOUSE ACTION ON TASK -#\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- -mouse_middle = none -mouse_right = close -mouse_scroll_up = toggle -mouse_scroll_down = iconify - -#\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- -## AUTOHIDE OPTIONS -#\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- -autohide = 0 -autohide_show_timeout = 0.3 -autohide_hide_timeout = 2 -autohide_height = 4 -strut_policy = minimum -.fi -.RE +See /etc/xdg/tint2/tint2rc. .SH AUTHOR .PP tint2 was written by Thierry Lorthiois \[la]lorthiois@bbsoft.fr\[ra]\&.
M doc/tint2.mddoc/tint2.md

@@ -58,6 +58,8 @@ * [Battery](#battery)

* [Executor](#executor) + * [Button](#button) + * [Separator](#separator) * [Example configuration](#example-configuration)

@@ -244,6 +246,7 @@ * `B` shows the Battery status

* `C` shows the Clock * `F` adds an extensible spacer (freespace). You can specify more than one. Has no effect if `T` is also present. *(since 0.12)* * `E` adds an executor plugin. You can specify more than one. *(since 0.12.4)* + * `P` adds a push button. You can specify more than one. *(since 0.14)* * `:` adds a separator. You can specify more than one. *(since 0.13.0)* For example, `panel_items = STC` will show the systray, the taskbar and the clock (from left to right).

@@ -671,158 +674,49 @@ execp_continuous = 1

execp_interval = 1 ``` -### Separator +### Button - * `separator = new` : Begins the configuration of a new separator. Multiple such plugins are supported; just use multiple `:`s in `panel_items`. *(since 0.13.0)* + * `button = new` : Begins the configuration of a new button. Multiple such plugins are supported; just use multiple `P`s in `panel_items`. *(since 0.14)* - * `separator_background_id = integer` : Which background to use. *(since 0.13.0)* + * `button_icon = text` : Name or path of icon (or empty). *(since 0.14)* - * `separator_color = color opacity` : The foreground color. *(since 0.13.0)* + * `button_text = text` : Text to display (or empty). *(since 0.14)* - * `separator_style = [empty | line | dots]` : The separator style. *(since 0.13.0)* + * `button_tooltip = text` : The tooltip (or empty). *(since 0.14)* - * `separator_size = integer` : The thickness of the separator. Does not include the border and padding. For example, if the style is `line`, this is the line thickness; if the style is `dots`, this is the dot's diameter. *(since 0.13.0)* + * `button_font = [FAMILY-LIST] [STYLE-OPTIONS] [SIZE]` : The font used to draw the text. *(since 0.14)* - * `separator_padding = side_padding cap_padding` : The padding to add to the sides of the separator, in pixels. *(since 0.13.0)* + * `button_font_color = color opacity` : The font color. *(since 0.14)* -### Example configuration + * `button_background_id = integer` : Which background to use. *(since 0.14)* -``` -#--------------------------------------------- -## TINT2 CONFIG FILE -#--------------------------------------------- + * `button_centered = boolean (0 or 1)` : Whether to center the text. *(since 0.14)* -#--------------------------------------------- -## BACKGROUND AND BORDER -#--------------------------------------------- -rounded = 7 -border_width = 2 -background_color = #000000 60 -border_color = #ffffff 18 + * `button_padding = horizontal_padding vertical_padding spacing_between_icon_and_text` *(since 0.14)* -rounded = 5 -border_width = 0 -background_color = #ffffff 40 -border_color = #ffffff 50 + * `button_lclick_command = text` : Command to execute on left click. If not defined, `execp_command` is executed immediately, unless it is currently running. *(since 0.14)* + * `button_mclick_command = text` : Command to execute on right click. If not defined, `execp_command` is executed immediately, unless it is currently running. *(since 0.14)* + * `button_rclick_command = text` : Command to execute on middle click. If not defined, `execp_command` is executed immediately, unless it is currently running. *(since 0.14)* + * `button_uwheel_command = text` : Command to execute on wheel scroll up. If not defined, `execp_command` is executed immediately, unless it is currently running. *(since 0.14)* + * `button_dwheel_command = text` : Command to execute on wheel scroll down. If not defined, `execp_command` is executed immediately, unless it is currently running. *(since 0.14)* -rounded = 5 -border_width = 0 -background_color = #ffffff 18 -border_color = #ffffff 70 +### Separator -#--------------------------------------------- -## PANEL -#--------------------------------------------- -panel_monitor = all -panel_position = bottom center -panel_size = 94% 30 -panel_margin = 0 0 -panel_padding = 7 0 -font_shadow = 0 -panel_background_id = 1 -wm_menu = 0 -panel_dock = 0 -panel_layer = bottom + * `separator = new` : Begins the configuration of a new separator. Multiple such plugins are supported; just use multiple `:`s in `panel_items`. *(since 0.13.0)* -#--------------------------------------------- -## TASKBAR -#--------------------------------------------- -#taskbar_mode = multi_desktop -taskbar_mode = single_desktop -taskbar_padding = 2 3 2 -taskbar_background_id = 0 -#taskbar_active_background_id = 0 + * `separator_background_id = integer` : Which background to use. *(since 0.13.0)* -#--------------------------------------------- -## TASKS -#--------------------------------------------- -task_icon = 1 -task_text = 1 -task_maximum_size = 140 35 -task_centered = 1 -task_padding = 6 3 -task_font = sans 7 -task_font_color = #ffffff 70 -task_background_id = 3 -task_icon_asb = 100 0 0 -## replace STATUS by 'urgent', 'active' or 'iconified' -#task_STATUS_background_id = 2 -#task_STATUS_font_color = #ffffff 85 -#task_STATUS_icon_asb = 100 0 0 -## example: -task_active_background_id = 2 -task_active_font_color = #ffffff 85 -task_active_icon_asb = 100 0 0 -urgent_nb_of_blink = 8 + * `separator_color = color opacity` : The foreground color. *(since 0.13.0)* -#--------------------------------------------- -## SYSTRAYBAR -#--------------------------------------------- -systray = 1 -systray_padding = 0 4 5 -systray_background_id = 0 -systray_sort = left2right -systray_icon_size = 0 -systray_icon_asb = 100 0 0 + * `separator_style = [empty | line | dots]` : The separator style. *(since 0.13.0)* -#--------------------------------------------- -## CLOCK -#--------------------------------------------- -time1_format = %H:%M -time1_font = sans 8 -time2_format = %A %d %B -time2_font = sans 6 -clock_font_color = #ffffff 76 -clock_padding = 1 0 -clock_background_id = 0 -#clock_lclick_command = xclock -clock_rclick_command = orage -#clock_tooltip = %A %d %B -#time1_timezone = :US/Hawaii -#time2_timezone = :Europe/Berlin -#clock_tooltip_timezone = :/usr/share/zoneinfo/Europe/Paris - -#--------------------------------------------- -## BATTERY -#--------------------------------------------- -battery = 0 -battery_hide = 98 -battery_low_status = 10 -battery_low_cmd = notify-send "battery low" -bat1_font = sans 8 -bat2_font = sans 6 -battery_font_color = #ffffff 76 -battery_padding = 1 0 -battery_background_id = 0 + * `separator_size = integer` : The thickness of the separator. Does not include the border and padding. For example, if the style is `line`, this is the line thickness; if the style is `dots`, this is the dot's diameter. *(since 0.13.0)* -#--------------------------------------------- -## TOOLTIP -#--------------------------------------------- -tooltip = 0 -tooltip_padding = 2 2 -tooltip_show_timeout = 0.7 -tooltip_hide_timeout = 0.3 -tooltip_background_id = 1 -tooltip_font_color = #OOOOOO 80 -tooltip_font = sans 10 + * `separator_padding = side_padding cap_padding` : The padding to add to the sides of the separator, in pixels. *(since 0.13.0)* -#--------------------------------------------- -## MOUSE ACTION ON TASK -#--------------------------------------------- -mouse_middle = none -mouse_right = close -mouse_scroll_up = toggle -mouse_scroll_down = iconify +### Example configuration -#--------------------------------------------- -## AUTOHIDE OPTIONS -#--------------------------------------------- -autohide = 0 -autohide_show_timeout = 0.3 -autohide_hide_timeout = 2 -autohide_height = 4 -strut_policy = minimum -``` +See /etc/xdg/tint2/tint2rc. ## AUTHOR tint2 was written by Thierry Lorthiois <lorthiois@bbsoft.fr>.
A src/button/button.c

@@ -0,0 +1,543 @@

+#include "button.h" + +#include <string.h> +#include <stdio.h> +#include <cairo.h> +#include <cairo-xlib.h> +#include <math.h> +#include <pango/pangocairo.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <time.h> +#include <fcntl.h> + +#include "window.h" +#include "server.h" +#include "panel.h" +#include "timer.h" +#include "common.h" + +char *button_get_tooltip(void *obj); +void button_init_fonts(); +int button_compute_desired_size(void *obj); +void button_dump_geometry(void *obj, int indent); + +void default_button() +{ +} + +Button *create_button() +{ + Button *button = calloc(1, sizeof(Button)); + button->backend = calloc(1, sizeof(ButtonBackend)); + button->backend->centered = TRUE; + button->backend->font_color.alpha = 0.5; + return button; +} + +gpointer create_button_frontend(gconstpointer arg, gpointer data) +{ + Button *button_backend = (Button *)arg; + + Button *button_frontend = calloc(1, sizeof(Button)); + button_frontend->backend = button_backend->backend; + button_backend->backend->instances = g_list_append(button_backend->backend->instances, button_frontend); + button_frontend->frontend = calloc(1, sizeof(ButtonFrontend)); + return button_frontend; +} + +void destroy_button(void *obj) +{ + Button *button = (Button *)obj; + if (button->frontend) { + // This is a frontend element + if (button->frontend->icon) { + imlib_context_set_image(button->frontend->icon); + imlib_free_image(); + button->frontend->icon = NULL; + } + button->backend->instances = g_list_remove_all(button->backend->instances, button); + free_and_null(button->frontend); + remove_area(&button->area); + free_area(&button->area); + free_and_null(button); + } else { + // This is a backend element + free_and_null(button->backend->text); + free_and_null(button->backend->icon_name); + free_and_null(button->backend->tooltip); + + button->backend->bg = NULL; + pango_font_description_free(button->backend->font_desc); + button->backend->font_desc = NULL; + free_and_null(button->backend->lclick_command); + free_and_null(button->backend->mclick_command); + free_and_null(button->backend->rclick_command); + free_and_null(button->backend->dwheel_command); + free_and_null(button->backend->uwheel_command); + + if (button->backend->instances) { + fprintf(stderr, "Error: Attempt to destroy backend while there are still frontend instances!\n"); + exit(-1); + } + free(button->backend); + free(button); + } +} + +void init_button() +{ + GList *to_remove = panel_config.button_list; + for (int k = 0; k < strlen(panel_items_order) && to_remove; k++) { + if (panel_items_order[k] == 'E') { + to_remove = to_remove->next; + } + } + + if (to_remove) { + if (to_remove == panel_config.button_list) { + g_list_free_full(to_remove, destroy_button); + panel_config.button_list = NULL; + } else { + // Cut panel_config.button_list + if (to_remove->prev) + to_remove->prev->next = NULL; + to_remove->prev = NULL; + // Remove all elements of to_remove and to_remove itself + g_list_free_full(to_remove, destroy_button); + } + } + + button_init_fonts(); + for (GList *l = panel_config.button_list; l; l = l->next) { + Button *button = l->data; + + // Set missing config options + if (!button->backend->bg) + button->backend->bg = &g_array_index(backgrounds, Background, 0); + } +} + +void init_button_panel(void *p) +{ + Panel *panel = (Panel *)p; + + // Make sure this is only done once if there are multiple items + if (panel->button_list && ((Button *)panel->button_list->data)->frontend) + return; + + // panel->button_list is now a copy of the pointer panel_config.button_list + // We make it a deep copy + panel->button_list = g_list_copy_deep(panel_config.button_list, create_button_frontend, NULL); + + load_icon_themes(); + + for (GList *l = panel->button_list; l; l = l->next) { + Button *button = l->data; + button->area.bg = button->backend->bg; + button->area.paddingx = button->backend->paddingx; + button->area.paddingy = button->backend->paddingy; + button->area.paddingxlr = button->backend->paddingxlr; + button->area.parent = panel; + button->area.panel = panel; + button->area._dump_geometry = button_dump_geometry; + button->area._compute_desired_size = button_compute_desired_size; + snprintf(button->area.name, sizeof(button->area.name), "Button"); + button->area._draw_foreground = draw_button; + button->area.size_mode = LAYOUT_FIXED; + button->area._resize = resize_button; + button->area._get_tooltip_text = button_get_tooltip; + button->area._is_under_mouse = full_width_area_is_under_mouse; + button->area.has_mouse_press_effect = + panel_config.mouse_effects && + (button->area.has_mouse_over_effect = button->backend->lclick_command || button->backend->mclick_command || + button->backend->rclick_command || button->backend->uwheel_command || + button->backend->dwheel_command); + + button->area.resize_needed = TRUE; + button->area.on_screen = TRUE; + instantiate_area_gradients(&button->area); + + button_reload_icon(button); + } +} + +void button_init_fonts() +{ + for (GList *l = panel_config.button_list; l; l = l->next) { + Button *button = l->data; + if (!button->backend->font_desc) + button->backend->font_desc = pango_font_description_from_string(get_default_font()); + } +} + +void button_default_font_changed() +{ + gboolean needs_update = FALSE; + for (GList *l = panel_config.button_list; l; l = l->next) { + Button *button = l->data; + + if (!button->backend->has_font) { + pango_font_description_free(button->backend->font_desc); + button->backend->font_desc = NULL; + needs_update = TRUE; + } + } + if (!needs_update) + return; + + button_init_fonts(); + for (int i = 0; i < num_panels; i++) { + for (GList *l = panels[i].button_list; l; l = l->next) { + Button *button = l->data; + + if (!button->backend->has_font) { + button->area.resize_needed = TRUE; + schedule_redraw(&button->area); + } + } + } + schedule_panel_redraw(); +} + +void button_reload_icon(Button *button) +{ + free_icon(button->frontend->icon); + free_icon(button->frontend->icon_hover); + free_icon(button->frontend->icon_pressed); + button->frontend->icon = NULL; + + button->frontend->icon_load_size = button->frontend->iconw; + + char *new_icon_path = get_icon_path(icon_theme_wrapper, button->backend->icon_name, button->frontend->iconw, TRUE); + if (new_icon_path) + button->frontend->icon = imlib_load_image_immediately(new_icon_path); + free(new_icon_path); + // On loading error, fallback to default + if (!button->frontend->icon) { + new_icon_path = get_icon_path(icon_theme_wrapper, DEFAULT_ICON, button->frontend->iconw, TRUE); + if (new_icon_path) + button->frontend->icon = imlib_load_image_immediately(new_icon_path); + free(new_icon_path); + } + Imlib_Image original = button->frontend->icon; + button->frontend->icon = scale_icon(button->frontend->icon, button->frontend->iconw); + free_icon(original); + + if (panel_config.mouse_effects) { + button->frontend->icon_hover = adjust_icon(button->frontend->icon, + panel_config.mouse_over_alpha, + panel_config.mouse_over_saturation, + panel_config.mouse_over_brightness); + button->frontend->icon_pressed = adjust_icon(button->frontend->icon, + panel_config.mouse_pressed_alpha, + panel_config.mouse_pressed_saturation, + panel_config.mouse_pressed_brightness); + } + schedule_redraw(&button->area); +} + +void button_default_icon_theme_changed() +{ + for (int i = 0; i < num_panels; i++) { + for (GList *l = panels[i].button_list; l; l = l->next) { + Button *button = l->data; + button_reload_icon(button); + } + } + schedule_panel_redraw(); +} + +void cleanup_button() +{ + // Cleanup frontends + for (int i = 0; i < num_panels; i++) { + g_list_free_full(panels[i].button_list, destroy_button); + panels[i].button_list = NULL; + } + + // Cleanup backends + g_list_free_full(panel_config.button_list, destroy_button); + panel_config.button_list = NULL; +} + +int button_compute_desired_size(void *obj) +{ + Button *button = (Button *)obj; + Panel *panel = (Panel *)button->area.panel; + int horiz_padding = (panel_horizontal ? button->area.paddingxlr : button->area.paddingy); + int vert_padding = (panel_horizontal ? button->area.paddingy : button->area.paddingxlr); + int interior_padding = button->area.paddingx; + + int icon_w, icon_h; + if (button->backend->icon_name) { + if (panel_horizontal) + icon_h = icon_w = button->area.height - top_bottom_border_width(&button->area) - 2 * vert_padding; + else + icon_h = icon_w = button->area.width - left_right_border_width(&button->area) - 2 * horiz_padding; + } else { + icon_h = icon_w = 0; + } + + int txt_height_ink, txt_height, txt_width; + if (button->backend->text) { + if (panel_horizontal) { + get_text_size2(button->backend->font_desc, + &txt_height_ink, + &txt_height, + &txt_width, + panel->area.height, + panel->area.width, + button->backend->text, + strlen(button->backend->text), + PANGO_WRAP_WORD_CHAR, + PANGO_ELLIPSIZE_NONE, + FALSE); + } else { + get_text_size2(button->backend->font_desc, + &txt_height_ink, + &txt_height, + &txt_width, + panel->area.height, + button->area.width - icon_w - (icon_w ? interior_padding : 0) - + 2 * horiz_padding - left_right_border_width(&button->area), + button->backend->text, + strlen(button->backend->text), + PANGO_WRAP_WORD_CHAR, + PANGO_ELLIPSIZE_NONE, + FALSE); + } + } else { + txt_height_ink = txt_height = txt_width = 0; + } + + if (panel_horizontal) { + int new_size = txt_width + icon_w + (txt_width && icon_w ? interior_padding : 0); + new_size += 2 * horiz_padding + left_right_border_width(&button->area); + return new_size; + } else { + int new_size; + new_size = txt_height + 2 * vert_padding + top_bottom_border_width(&button->area); + new_size = MAX(new_size, icon_h + 2 * vert_padding + top_bottom_border_width(&button->area)); + return new_size; + } +} + +gboolean resize_button(void *obj) +{ + Button *button = (Button *)obj; + Panel *panel = (Panel *)button->area.panel; + int horiz_padding = (panel_horizontal ? button->area.paddingxlr : button->area.paddingy); + int vert_padding = (panel_horizontal ? button->area.paddingy : button->area.paddingxlr); + int interior_padding = button->area.paddingx; + + int icon_w, icon_h; + if (button->backend->icon_name) { + if (panel_horizontal) + icon_h = icon_w = button->area.height - top_bottom_border_width(&button->area) - 2 * vert_padding; + else + icon_h = icon_w = button->area.width - left_right_border_width(&button->area) - 2 * horiz_padding; + } else { + icon_h = icon_w = 0; + } + + button->frontend->iconw = icon_w; + button->frontend->iconh = icon_h; + if (button->frontend->icon_load_size != button->frontend->iconw) + button_reload_icon(button); + + int txt_height_ink, txt_height, txt_width; + if (button->backend->text) { + if (panel_horizontal) { + get_text_size2(button->backend->font_desc, + &txt_height_ink, + &txt_height, + &txt_width, + panel->area.height, + panel->area.width, + button->backend->text, + strlen(button->backend->text), + PANGO_WRAP_WORD_CHAR, + PANGO_ELLIPSIZE_NONE, + FALSE); + } else { + get_text_size2(button->backend->font_desc, + &txt_height_ink, + &txt_height, + &txt_width, + panel->area.height, + button->area.width - icon_w - (icon_w ? interior_padding : 0) - + 2 * horiz_padding - left_right_border_width(&button->area), + button->backend->text, + strlen(button->backend->text), + PANGO_WRAP_WORD_CHAR, + PANGO_ELLIPSIZE_NONE, + FALSE); + } + } else { + txt_height_ink = txt_height = txt_width = 0; + } + + gboolean result = FALSE; + if (panel_horizontal) { + int new_size = txt_width + icon_w + (txt_width && icon_w ? interior_padding : 0); + new_size += 2 * horiz_padding + left_right_border_width(&button->area); + if (new_size != button->area.width) { + button->area.width = new_size; + result = TRUE; + } + } else { + int new_size; + new_size = txt_height + 2 * vert_padding + top_bottom_border_width(&button->area); + new_size = MAX(new_size, icon_h + 2 * vert_padding + top_bottom_border_width(&button->area)); + if (new_size != button->area.height) { + button->area.height = new_size; + result = TRUE; + } + } + button->frontend->textw = txt_width; + button->frontend->texth = txt_height; + if (button->backend->centered) { + if (icon_w) { + button->frontend->icony = (button->area.height - icon_h) / 2; + button->frontend->iconx = (button->area.width - txt_width - (txt_width ? interior_padding : 0) - icon_w) / 2; + button->frontend->texty = (button->area.height - txt_height) / 2; + button->frontend->textx = button->frontend->iconx + icon_w + interior_padding; + } else { + button->frontend->texty = (button->area.height - txt_height) / 2; + button->frontend->textx = (button->area.width - txt_width) / 2; + } + } else { + if (icon_w) { + button->frontend->icony = (button->area.height - icon_h) / 2; + button->frontend->iconx = left_border_width(&button->area) + horiz_padding; + button->frontend->texty = (button->area.height - txt_height) / 2; + button->frontend->textx = button->frontend->iconx + icon_w + interior_padding; + } else { + button->frontend->texty = (button->area.height - txt_height) / 2; + button->frontend->textx = left_border_width(&button->area) + horiz_padding; + } + } + + schedule_redraw(&button->area); + + return result; +} + +void draw_button(void *obj, cairo_t *c) +{ + Button *button = obj; + + if (button->frontend->icon) { + imlib_context_set_image(button->frontend->icon); + // Render icon + render_image(button->area.pix, button->frontend->iconx, button->frontend->icony); + } + + // Render text + if (button->backend->text) { + PangoLayout *layout = pango_cairo_create_layout(c); + + pango_layout_set_font_description(layout, button->backend->font_desc); + pango_layout_set_width(layout, button->frontend->textw * PANGO_SCALE); + pango_layout_set_alignment(layout, button->backend->centered ? PANGO_ALIGN_CENTER : PANGO_ALIGN_LEFT); + pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); + pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE); + pango_layout_set_text(layout, button->backend->text, strlen(button->backend->text)); + + pango_cairo_update_layout(c, layout); + draw_text(layout, + c, + button->frontend->textx, + button->frontend->texty, + &button->backend->font_color, + panel_config.font_shadow); + + g_object_unref(layout); + } +} + +void button_dump_geometry(void *obj, int indent) +{ + Button *button = obj; + + if (button->frontend->icon) { + Imlib_Image tmp = imlib_context_get_image(); + imlib_context_set_image(button->frontend->icon); + fprintf(stderr, + "%*sIcon: x = %d, y = %d, w = %d, h = %d\n", + indent, + "", + button->frontend->iconx, + button->frontend->icony, + imlib_image_get_width(), + imlib_image_get_height()); + if (tmp) + imlib_context_set_image(tmp); + } + fprintf(stderr, + "%*sText: x = %d, y = %d, w = %d, align = %s, text = %s\n", + indent, + "", + button->frontend->textx, + button->frontend->texty, + button->frontend->textw, + button->backend->centered ? "center" : "left", + button->backend->text); +} + +void button_action(void *obj, int mouse_button, int x, int y) +{ + Button *button = obj; + char *command = NULL; + switch (mouse_button) { + case 1: + command = button->backend->lclick_command; + break; + case 2: + command = button->backend->mclick_command; + break; + case 3: + command = button->backend->rclick_command; + break; + case 4: + command = button->backend->uwheel_command; + break; + case 5: + command = button->backend->dwheel_command; + break; + } + if (command) { + char *full_cmd = g_strdup_printf("export BUTTON_X=%d;" + "export BUTTON_Y=%d;" + "export BUTTON_W=%d;" + "export BUTTON_H=%d; %s", + x, + y, + button->area.width, + button->area.height, + command); + pid_t pid = fork(); + if (pid < 0) { + fprintf(stderr, "Could not fork\n"); + } else if (pid == 0) { + // Child process + // Allow children to exist after parent destruction + setsid(); + // Run the command + execl("/bin/sh", "/bin/sh", "-c", full_cmd, NULL); + fprintf(stderr, "Failed to execlp %s\n", full_cmd); + exit(1); + } + } +} + +char *button_get_tooltip(void *obj) +{ + Button *button = obj; + + if (button->backend->tooltip && strlen(button->backend->tooltip) > 0) + return strdup(button->backend->tooltip); + return NULL; +}
A src/button/button.h

@@ -0,0 +1,111 @@

+#ifndef BUTTON_H +#define BUTTON_H + +#include <sys/time.h> +#include <pango/pangocairo.h> + +#include "area.h" +#include "common.h" +#include "timer.h" + +// Architecture: +// Panel panel_config contains an array of Button, each storing all config options and all the state variables. +// Only these run commands. +// +// Tint2 maintains an array of Panels, one for each monitor. Each stores an array of Button which was initially copied +// from panel_config. Each works as a frontend to the corresponding Button in panel_config as backend, using the +// backend's config and state variables. + +typedef struct ButtonBackend { + // Config: + char *icon_name; + char *text; + char *tooltip; + gboolean centered; + gboolean has_font; + PangoFontDescription *font_desc; + Color font_color; + char *lclick_command; + char *mclick_command; + char *rclick_command; + char *uwheel_command; + char *dwheel_command; + // paddingxlr = horizontal padding left/right + // paddingx = horizontal padding between childs + int paddingxlr, paddingx, paddingy; + Background *bg; + + // List of Button which are frontends for this backend, one for each panel + GList *instances; +} ButtonBackend; + +typedef struct ButtonFrontend { + // Frontend state: + Imlib_Image icon; + Imlib_Image icon_hover; + Imlib_Image icon_pressed; + int icon_load_size; + int iconx; + int icony; + int iconw; + int iconh; + int textx; + int texty; + int textw; + int texth; +} ButtonFrontend; + +typedef struct Button { + Area area; + // All elements have the backend pointer set. However only backend elements have ownership. + ButtonBackend *backend; + // Set only for frontend Button items. + ButtonFrontend *frontend; +} Button; + +// Called before the config is read and panel_config/panels are created. +// Afterwards, the config parsing code creates the array of Button in panel_config and populates the configuration fields +// in the backend. +// Probably does nothing. +void default_button(); + +// Creates a new Button item with only the backend field set. The state is NOT initialized. The config is initialized to +// the default values. +// This will be used by the config code to populate its backedn config fields. +Button *create_button(); + +void destroy_button(void *obj); + +// Called after the config is read and panel_config is populated, but before panels are created. +// Initializes the state of the backend items. +// panel_config.panel_items is used to determine which backend items are enabled. The others should be destroyed and +// removed from panel_config.button_list. +void init_button(); + +// Called after each on-screen panel is created, with a pointer to the panel. +// Initializes the state of the frontend items. Also adds a pointer to it in backend->instances. +// At this point the Area has not been added yet to the GUI tree, but it will be added right away. +void init_button_panel(void *panel); + +// Called just before the panels are destroyed. Afterwards, tint2 exits or restarts and reads the config again. +// Releases all frontends and then all the backends. +// The frontend items are not freed by this function, only their members. The items are Areas which are freed in the +// GUI element tree cleanup function (remove_area). +void cleanup_button(); + +// Called on draw, obj = pointer to the front-end Button item. +void draw_button(void *obj, cairo_t *c); + +// Called on resize, obj = pointer to the front-end Button item. +// Returns 1 if the new size is different than the previous size. +gboolean resize_button(void *obj); + +// Called on mouse click event. +void button_action(void *obj, int button, int x, int y); + +void button_default_font_changed(); +void button_default_icon_theme_changed(); + +void button_reload_icon(Button *button); + +#endif // BUTTON_H
M src/config.csrc/config.c

@@ -221,6 +221,15 @@ }

return (Execp *)g_list_last(panel_config.execp_list)->data; } +Button *get_or_create_last_button() +{ + if (!panel_config.button_list) { + fprintf(stderr, "Warning: button items should start with 'button = new'\n"); + panel_config.button_list = g_list_append(panel_config.button_list, create_button()); + } + return (Button *)g_list_last(panel_config.button_list)->data; +} + void add_entry(char *key, char *value) { char *value1 = 0, *value2 = 0, *value3 = 0;

@@ -736,6 +745,78 @@ Execp *execp = get_or_create_last_execp();

free_and_null(execp->backend->dwheel_command); if (strlen(value) > 0) execp->backend->dwheel_command = strdup(value); + } + + /* Button */ + else if (strcmp(key, "button") == 0) { + panel_config.button_list = g_list_append(panel_config.button_list, create_button()); + } else if (strcmp(key, "button_icon") == 0) { + Button *button = get_or_create_last_button(); + button->backend->icon_name = strdup(value); + } else if (strcmp(key, "button_text") == 0) { + Button *button = get_or_create_last_button(); + free_and_null(button->backend->text); + button->backend->text = strdup(value); + } else if (strcmp(key, "button_tooltip") == 0) { + Button *button = get_or_create_last_button(); + free_and_null(button->backend->tooltip); + button->backend->tooltip = strdup(value); + } else if (strcmp(key, "button_font") == 0) { + Button *button = get_or_create_last_button(); + pango_font_description_free(button->backend->font_desc); + button->backend->font_desc = pango_font_description_from_string(value); + button->backend->has_font = TRUE; + } else if (strcmp(key, "button_font_color") == 0) { + Button *button = get_or_create_last_button(); + extract_values(value, &value1, &value2, &value3); + get_color(value1, button->backend->font_color.rgb); + if (value2) + button->backend->font_color.alpha = atoi(value2) / 100.0; + else + button->backend->font_color.alpha = 0.5; + } else if (strcmp(key, "button_padding") == 0) { + Button *button = get_or_create_last_button(); + extract_values(value, &value1, &value2, &value3); + button->backend->paddingxlr = button->backend->paddingx = atoi(value1); + if (value2) + button->backend->paddingy = atoi(value2); + else + button->backend->paddingy = 0; + if (value3) + button->backend->paddingx = atoi(value3); + } else if (strcmp(key, "button_background_id") == 0) { + Button *button = get_or_create_last_button(); + int id = atoi(value); + id = (id < backgrounds->len && id >= 0) ? id : 0; + button->backend->bg = &g_array_index(backgrounds, Background, id); + } else if (strcmp(key, "button_centered") == 0) { + Button *button = get_or_create_last_button(); + button->backend->centered = atoi(value); + } else if (strcmp(key, "button_lclick_command") == 0) { + Button *button = get_or_create_last_button(); + free_and_null(button->backend->lclick_command); + if (strlen(value) > 0) + button->backend->lclick_command = strdup(value); + } else if (strcmp(key, "button_mclick_command") == 0) { + Button *button = get_or_create_last_button(); + free_and_null(button->backend->mclick_command); + if (strlen(value) > 0) + button->backend->mclick_command = strdup(value); + } else if (strcmp(key, "button_rclick_command") == 0) { + Button *button = get_or_create_last_button(); + free_and_null(button->backend->rclick_command); + if (strlen(value) > 0) + button->backend->rclick_command = strdup(value); + } else if (strcmp(key, "button_uwheel_command") == 0) { + Button *button = get_or_create_last_button(); + free_and_null(button->backend->uwheel_command); + if (strlen(value) > 0) + button->backend->uwheel_command = strdup(value); + } else if (strcmp(key, "button_dwheel_command") == 0) { + Button *button = get_or_create_last_button(); + free_and_null(button->backend->dwheel_command); + if (strlen(value) > 0) + button->backend->dwheel_command = strdup(value); } /* Clock */
M src/launcher/launcher.csrc/launcher/launcher.c

@@ -54,6 +54,8 @@ int startup_notifications;

Background *launcher_icon_bg; GList *launcher_icon_gradients; +IconThemeWrapper *icon_theme_wrapper; + Imlib_Image scale_icon(Imlib_Image original, int icon_size); void free_icon(Imlib_Image icon); void launcher_icon_dump_geometry(void *obj, int indent);

@@ -114,10 +116,16 @@ launcher->area.on_screen = TRUE;

schedule_panel_redraw(); instantiate_area_gradients(&launcher->area); - launcher_load_themes(launcher); + load_icon_themes(); launcher_load_icons(launcher); } +void free_icon_themes() +{ + free_themes(icon_theme_wrapper); + icon_theme_wrapper = NULL; +} + void cleanup_launcher() { for (int i = 0; i < num_panels; i++) {

@@ -160,9 +168,6 @@ free(launcherIcon);

} g_slist_free(launcher->list_icons); launcher->list_icons = NULL; - - free_themes(launcher->icon_theme_wrapper); - launcher->icon_theme_wrapper = NULL; } int launcher_compute_icon_size(Launcher *launcher)

@@ -246,7 +251,7 @@ launcherIcon->area.height = launcherIcon->icon_size;

launcher_reload_icon_image(launcher, launcherIcon); } } - save_icon_cache(launcher->icon_theme_wrapper); + save_icon_cache(icon_theme_wrapper); int count = 0; gboolean needs_repositioning = FALSE;

@@ -565,13 +570,13 @@ free_icon(launcherIcon->image_hover);

free_icon(launcherIcon->image_pressed); launcherIcon->image = NULL; - char *new_icon_path = get_icon_path(launcher->icon_theme_wrapper, launcherIcon->icon_name, launcherIcon->icon_size, TRUE); + char *new_icon_path = get_icon_path(icon_theme_wrapper, launcherIcon->icon_name, launcherIcon->icon_size, TRUE); if (new_icon_path) launcherIcon->image = load_image(new_icon_path, 1); // On loading error, fallback to default if (!launcherIcon->image) { free(new_icon_path); - new_icon_path = get_icon_path(launcher->icon_theme_wrapper, DEFAULT_ICON, launcherIcon->icon_size, TRUE); + new_icon_path = get_icon_path(icon_theme_wrapper, DEFAULT_ICON, launcherIcon->icon_size, TRUE); if (new_icon_path) launcherIcon->image = imlib_load_image_immediately(new_icon_path); }

@@ -595,10 +600,11 @@ }

schedule_redraw(&launcherIcon->area); } -// Populates the icon_theme_wrapper list -void launcher_load_themes(Launcher *launcher) +void load_icon_themes() { - launcher->icon_theme_wrapper = + if (icon_theme_wrapper) + return; + icon_theme_wrapper = load_themes(launcher_icon_theme_override ? (icon_theme_name_config ? icon_theme_name_config : icon_theme_name_xsettings ? icon_theme_name_xsettings : "hicolor")

@@ -608,14 +614,9 @@ }

void launcher_default_icon_theme_changed() { - if (!launcher_enabled) - return; - if (launcher_icon_theme_override && icon_theme_name_config) - return; for (int i = 0; i < num_panels; i++) { Launcher *launcher = &panels[i].launcher; cleanup_launcher_theme(launcher); - launcher_load_themes(launcher); launcher_load_icons(launcher); launcher->area.resize_needed = 1; }
M src/launcher/launcher.hsrc/launcher/launcher.h

@@ -12,12 +12,15 @@ #include "area.h"

#include "xsettings-client.h" #include "icon-theme-common.h" +extern IconThemeWrapper *icon_theme_wrapper; +void load_icon_themes(); +void free_icon_themes(); + typedef struct Launcher { // always start with area Area area; GSList *list_apps; // List of char*, each is a path to a app.desktop file GSList *list_icons; // List of LauncherIcon* - IconThemeWrapper *icon_theme_wrapper; int icon_size; } Launcher;

@@ -65,8 +68,6 @@ void launcher_default_icon_theme_changed();

// Populates the list_icons list void launcher_load_icons(Launcher *launcher); -// Populates the list_themes list -void launcher_load_themes(Launcher *launcher); void launcher_action(LauncherIcon *icon, XEvent *e); void test_launcher_read_desktop_file();
M src/panel.csrc/panel.c

@@ -180,6 +180,8 @@ }

fprintf(stderr, "panel items: %s\n", panel_items_order); + icon_theme_wrapper = NULL; + init_tooltip(); init_systray(); init_launcher();

@@ -190,6 +192,7 @@ #endif

init_taskbar(); init_separator(); init_execp(); + init_button(); // number of panels (one monitor or 'all' monitors) if (panel_config.monitor >= 0)

@@ -247,6 +250,8 @@ if (panel_items_order[k] == ':')

init_separator_panel(p); if (panel_items_order[k] == 'E') init_execp_panel(p); + if (panel_items_order[k] == 'P') + init_button_panel(p); } set_panel_items_order(p);

@@ -603,6 +608,7 @@

int i_execp = 0; int i_separator = 0; int i_freespace = 0; + int i_button = 0; for (int k = 0; k < strlen(panel_items_order); k++) { if (panel_items_order[k] == 'L') { p->area.children = g_list_append(p->area.children, &p->launcher);

@@ -640,6 +646,12 @@ i_execp++;

if (item) p->area.children = g_list_append(p->area.children, (Area *)item->data); } + if (panel_items_order[k] == 'P') { + GList *item = g_list_nth(p->button_list, i_button); + i_button++; + if (item) + p->area.children = g_list_append(p->area.children, (Area *)item->data); + } } initialize_positions(&p->area, 0); }

@@ -986,6 +998,16 @@ }

return NULL; } +Button *click_button(Panel *panel, int x, int y) +{ + for (GList *l = panel->button_list; l; l = l->next) { + Button *button = (Button *)l->data; + if (area_is_under_mouse(button, x, y)) + return button; + } + return NULL; +} + void stop_autohide_timeout(Panel *p) { stop_timeout(p->autohide_timeout);

@@ -1082,7 +1104,16 @@ }

void default_icon_theme_changed() { + if (!launcher_enabled && !panel_config.button_list) + return; + if (launcher_icon_theme_override && icon_theme_name_config) + return; + + free_icon_themes(); + load_icon_themes(); + launcher_default_icon_theme_changed(); + button_default_icon_theme_changed(); } void default_font_changed()

@@ -1092,6 +1123,7 @@ battery_default_font_changed();

#endif clock_default_font_changed(); execp_default_font_changed(); + button_default_font_changed(); taskbar_default_font_changed(); taskbarname_default_font_changed(); tooltip_default_font_changed();
M src/panel.hsrc/panel.h

@@ -23,6 +23,7 @@ #include "launcher.h"

#include "freespace.h" #include "execplugin.h" #include "separator.h" +#include "button.h" #ifdef ENABLE_BATTERY #include "battery.h"

@@ -135,6 +136,7 @@ Launcher launcher;

GList *freespace_list; GList *separator_list; GList *execp_list; + GList *button_list; // Autohide gboolean is_hidden;

@@ -189,6 +191,7 @@ #endif

Area *click_area(Panel *panel, int x, int y); Execp *click_execp(Panel *panel, int x, int y); +Button *click_button(Panel *panel, int x, int y); void autohide_show(void *p); void autohide_hide(void *p);

@@ -199,5 +202,8 @@ const char *get_default_font();

void default_icon_theme_changed(); void default_font_changed(); + +void free_icon(Imlib_Image icon); +Imlib_Image scale_icon(Imlib_Image original, int icon_size); #endif
M src/tint.csrc/tint.c

@@ -393,6 +393,7 @@ default_launcher();

default_taskbar(); default_tooltip(); default_execp(); + default_button(); default_panel(); // Read command line arguments

@@ -612,6 +613,7 @@ }

void cleanup() { + cleanup_button(); cleanup_execp(); cleanup_systray(); cleanup_tooltip();

@@ -811,6 +813,8 @@ return 0;

} #endif if (click_execp(panel, e->x, e->y)) + return 1; + if (click_button(panel, e->x, e->y)) return 1; return 0; }

@@ -969,6 +973,15 @@

Execp *execp = click_execp(panel, e->xbutton.x, e->xbutton.y); if (execp) { execp_action(execp, e->xbutton.button, e->xbutton.x - execp->area.posx, e->xbutton.y - execp->area.posy); + if (panel_layer == BOTTOM_LAYER) + XLowerWindow(server.display, panel->main_win); + task_drag = 0; + return; + } + + Button *button = click_button(panel, e->xbutton.x, e->xbutton.y); + if (button) { + button_action(button, e->xbutton.button, e->xbutton.x - button->area.posx, e->xbutton.y - button->area.posy); if (panel_layer == BOTTOM_LAYER) XLowerWindow(server.display, panel->main_win); task_drag = 0;
M tint2.filestint2.files

@@ -223,3 +223,5 @@ src/tint2conf/md4.h

src/tint2conf/md4.c src/tint2rc.c src/tint2rc.h +src/button/button.c +src/button/button.h
M tint2.includestint2.includes

@@ -24,3 +24,4 @@ src/execplugin

src/separator themes doc +src/button