diff --git a/CMakeLists.txt b/CMakeLists.txt index 232cf7c..5868732 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,6 +100,7 @@ include_directories( ${PROJECT_BINARY_DIR} src/tooltip src/util src/execplugin + src/button src/freespace src/separator ${X11_INCLUDE_DIRS} @@ -128,6 +129,7 @@ set( SOURCES src/config.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 diff --git a/ChangeLog b/ChangeLog index 8f85c01..8387e83 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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) diff --git a/doc/manual.html b/doc/manual.html index f223a9c..2e7eeff 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -229,6 +229,7 @@ It was specifically made for Openbox but it should also work with other window m
  • Tooltip

  • Battery

  • Executor

  • +
  • Button

  • Separator

  • Example configuration

  • @@ -359,6 +360,7 @@ gradient_id_pressed = 2
  • 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).

    @@ -650,6 +652,23 @@ execp_command = stdbuf -oL bwm-ng -o csv -t 1000 | awk -F ';' '/total/ { printf execp_continuous = 1 execp_interval = 1 +

    Button

    +

    Separator

    -

    Example configuration

    #---------------------------------------------
    -## 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
    -
    -

    AUTHOR

    tint2 was written by Thierry Lorthiois lorthiois@bbsoft.fr. +

    Example configuration

    See /etc/xdg/tint2/tint2rc.

    AUTHOR

    tint2 was written by Thierry Lorthiois lorthiois@bbsoft.fr. It is based on ttm, originally written by Pål Staurland staura@gmail.com.

    This manual page was originally written by Daniel Moerner dmoerner@gmail.com, for the Debian project (but may be used by others). It was adopted from the tint2 docs.

    SEE ALSO

    The main website https://gitlab.com/o9000/tint2 and the wiki page at https://gitlab.com/o9000/tint2/wikis/home.

    This documentation is also provided in HTML and Markdown format in the system's default location diff --git a/doc/tint2.1 b/doc/tint2.1 index a502a54..10a6cdf 100644 --- a/doc/tint2.1 +++ b/doc/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] @@ -294,6 +296,8 @@ gradient_id_pressed = 2 .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 .PP @@ -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 @@ execp_interval = 1 .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]\&. diff --git a/doc/tint2.md b/doc/tint2.md index 75e73d1..10b061b 100644 --- a/doc/tint2.md +++ b/doc/tint2.md @@ -58,6 +58,8 @@ Goals: * [Executor](#executor) + * [Button](#button) + * [Separator](#separator) * [Example configuration](#example-configuration) @@ -244,6 +246,7 @@ gradient_id_pressed = 2 * `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,6 +674,32 @@ execp_continuous = 1 execp_interval = 1 ``` +### Button + + * `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)* + + * `button_icon = text` : Name or path of icon (or empty). *(since 0.14)* + + * `button_text = text` : Text to display (or empty). *(since 0.14)* + + * `button_tooltip = text` : The tooltip (or empty). *(since 0.14)* + + * `button_font = [FAMILY-LIST] [STYLE-OPTIONS] [SIZE]` : The font used to draw the text. *(since 0.14)* + + * `button_font_color = color opacity` : The font color. *(since 0.14)* + + * `button_background_id = integer` : Which background to use. *(since 0.14)* + + * `button_centered = boolean (0 or 1)` : Whether to center the text. *(since 0.14)* + + * `button_padding = horizontal_padding vertical_padding spacing_between_icon_and_text` *(since 0.14)* + + * `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)* + ### Separator * `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)* @@ -687,142 +716,7 @@ execp_interval = 1 ### Example configuration -``` -#--------------------------------------------- -## 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 -``` +See /etc/xdg/tint2/tint2rc. ## AUTHOR tint2 was written by Thierry Lorthiois . diff --git a/src/button/button.c b/src/button/button.c new file mode 100644 index 0000000..19c28a0 --- /dev/null +++ b/src/button/button.c @@ -0,0 +1,543 @@ +#include "button.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/src/button/button.h b/src/button/button.h new file mode 100644 index 0000000..0e4e058 --- /dev/null +++ b/src/button/button.h @@ -0,0 +1,111 @@ +#ifndef BUTTON_H +#define BUTTON_H + +#include +#include + +#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 diff --git a/src/config.c b/src/config.c index 65799c0..c293119 100644 --- a/src/config.c +++ b/src/config.c @@ -221,6 +221,15 @@ Execp *get_or_create_last_execp() 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; @@ -738,6 +747,78 @@ void add_entry(char *key, char *value) 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 */ else if (strcmp(key, "time1_format") == 0) { if (!new_config_file) { diff --git a/src/launcher/launcher.c b/src/launcher/launcher.c index 8d6c23e..46c22d0 100644 --- a/src/launcher/launcher.c +++ b/src/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 @@ void init_launcher_panel(void *p) 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 @@ void cleanup_launcher_theme(Launcher *launcher) } 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 @@ gboolean resize_launcher(void *obj) 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 @@ void launcher_reload_icon_image(Launcher *launcher, LauncherIcon *launcherIcon) 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 @@ void launcher_reload_icon_image(Launcher *launcher, LauncherIcon *launcherIcon) 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_load_themes(Launcher *launcher) 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; } diff --git a/src/launcher/launcher.h b/src/launcher/launcher.h index a1f3b99..0ac9f88 100644 --- a/src/launcher/launcher.h +++ b/src/launcher/launcher.h @@ -12,12 +12,15 @@ #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(); diff --git a/src/panel.c b/src/panel.c index 9b037b0..9170a87 100644 --- a/src/panel.c +++ b/src/panel.c @@ -180,6 +180,8 @@ void init_panel() fprintf(stderr, "panel items: %s\n", panel_items_order); + icon_theme_wrapper = NULL; + init_tooltip(); init_systray(); init_launcher(); @@ -190,6 +192,7 @@ void init_panel() 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 @@ void init_panel() 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 @@ void set_panel_items_order(Panel *p) 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 @@ void set_panel_items_order(Panel *p) 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 @@ Execp *click_execp(Panel *panel, int x, int y) 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 @@ const char *get_default_font() 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 @@ void 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(); diff --git a/src/panel.h b/src/panel.h index f5249a3..8e56716 100644 --- a/src/panel.h +++ b/src/panel.h @@ -23,6 +23,7 @@ #include "freespace.h" #include "execplugin.h" #include "separator.h" +#include "button.h" #ifdef ENABLE_BATTERY #include "battery.h" @@ -135,6 +136,7 @@ typedef struct Panel { GList *freespace_list; GList *separator_list; GList *execp_list; + GList *button_list; // Autohide gboolean is_hidden; @@ -189,6 +191,7 @@ Battery *click_battery(Panel *panel, int x, int y); 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); @@ -200,4 +203,7 @@ 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 diff --git a/src/tint.c b/src/tint.c index cc26e0f..00ac012 100644 --- a/src/tint.c +++ b/src/tint.c @@ -393,6 +393,7 @@ void init(int argc, char *argv[]) default_taskbar(); default_tooltip(); default_execp(); + default_button(); default_panel(); // Read command line arguments @@ -612,6 +613,7 @@ void init_X11_post_config() void cleanup() { + cleanup_button(); cleanup_execp(); cleanup_systray(); cleanup_tooltip(); @@ -812,6 +814,8 @@ int tint2_handles_click(Panel *panel, XButtonEvent *e) #endif if (click_execp(panel, e->x, e->y)) return 1; + if (click_button(panel, e->x, e->y)) + return 1; return 0; } @@ -975,6 +979,15 @@ void event_button_release(XEvent *e) 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; + return; + } + if (e->xbutton.button == 1 && click_launcher(panel, e->xbutton.x, e->xbutton.y)) { LauncherIcon *icon = click_launcher_icon(panel, e->xbutton.x, e->xbutton.y); if (icon) { diff --git a/tint2.files b/tint2.files index 8abbb15..5d950a1 100644 --- a/tint2.files +++ b/tint2.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 diff --git a/tint2.includes b/tint2.includes index 102427b..b1821df 100644 --- a/tint2.includes +++ b/tint2.includes @@ -24,3 +24,4 @@ src/execplugin src/separator themes doc +src/button