1 ---------------------------------------------------------------------------
2 -- @author Uli Schlachter
3 -- @copyright 2012 Uli Schlachter
4 -- @release @AWESOME_VERSION@
5 ---------------------------------------------------------------------------
9 local abutton
= require("awful.button")
10 local aclient
= require("awful.client")
11 local beautiful
= require("beautiful")
12 local object
= require("gears.object")
13 local drawable
= require("wibox.drawable")
14 local base
= require("wibox.widget.base")
15 local imagebox
= require("wibox.widget.imagebox")
16 local textbox
= require("wibox.widget.textbox")
24 local all_titlebars
= setmetatable({}, { __mode
= 'k' })
26 -- Get a color for a titlebar, this tests many values from the array and the theme
27 local function get_color(name
, c
, args
)
28 local suffix
= "_normal"
29 if capi
.client
.focus
== c
then
32 local function get(array
)
33 return array
["titlebar_"..name
..suffix
] or array
["titlebar_"..name
] or array
[name
..suffix
] or array
[name
]
35 return get(args
) or get(beautiful
)
38 local function get_titlebar_function(c
, position
)
39 if position
== "left" then
40 return c
.titlebar_left
41 elseif position
== "right" then
42 return c
.titlebar_right
43 elseif position
== "top" then
45 elseif position
== "bottom" then
46 return c
.titlebar_bottom
48 error("Invalid titlebar position '" .. position
.. "'")
52 --- Get a client's titlebar
54 -- @param c The client for which a titlebar is wanted.
55 -- @param args An optional table with extra arguments for the titlebar. The
56 -- "size" is the height of the titlebar. Available "position" values are top,
57 -- left, right and bottom. Additionally, the foreground and background colors
58 -- can be configured via e.g. "bg_normal" and "bg_focus".
60 local function new(c
, args
)
61 local args
= args
or {}
62 local position
= args
.position
or "top"
63 local size
= args
.size
or beautiful
.get_font_height(args
.font
) * 1.5
64 local d
= get_titlebar_function(c
, position
)(c
, size
)
66 -- Make sure that there is never more than one titlebar for any given client
67 local bars
= all_titlebars
[c
]
70 all_titlebars
[c
] = bars
74 if not bars
[position
] then
75 ret
= drawable(d
, nil)
76 local function update_colors()
77 local args
= bars
[position
].args
78 ret
:set_bg(get_color("bg", c
, args
))
79 ret
:set_fg(get_color("fg", c
, args
))
85 update_colors
= update_colors
88 -- Update the colors when focus changes
89 c
:connect_signal("focus", update_colors
)
90 c
:connect_signal("unfocus", update_colors
)
92 bars
[position
].args
= args
93 ret
= bars
[position
].drawable
96 -- Make sure the titlebar has the right colors applied
97 bars
[position
].update_colors()
102 --- Show a client's titlebar.
103 -- @param c The client whose titlebar is modified
104 -- @param position Optional position of the titlebar. Must be one of "left",
105 -- "right", "top", "bottom". Default is "top".
106 function titlebar
.show(c
, position
)
107 local position
= position
or "top"
108 local bars
= all_titlebars
[c
]
109 local data
= bars
and bars
[position
]
110 local args
= data
and data
.args
114 --- Hide a client's titlebar.
115 -- @param c The client whose titlebar is modified
116 -- @param position Optional position of the titlebar. Must be one of "left",
117 -- "right", "top", "bottom". Default is "top".
118 function titlebar
.hide(c
, position
)
119 local position
= position
or "top"
120 get_titlebar_function(c
, position
)(c
, 0)
123 --- Toggle a client's titlebar, hiding it if it is visible, otherwise showing it.
124 -- @param c The client whose titlebar is modified
125 -- @param position Optional position of the titlebar. Must be one of "left",
126 -- "right", "top", "bottom". Default is "top".
127 function titlebar
.toggle(c
, position
)
128 local position
= position
or "top"
129 local drawable
, size
= get_titlebar_function(c
, position
)(c
)
131 titlebar
.show(c
, position
)
133 titlebar
.hide(c
, position
)
137 --- Create a new titlewidget. A title widget displays the name of a client.
138 -- Please note that this returns a textbox and all of textbox' API is available.
139 -- This way, you can e.g. modify the font that is used.
140 -- @param c The client for which a titlewidget should be created.
141 -- @return The title widget.
142 function titlebar
.widget
.titlewidget(c
)
143 local ret
= textbox()
144 local function update()
145 ret
:set_text(c
.name
or "<unknown>")
147 c
:connect_signal("property::name", update
)
153 --- Create a new icon widget. An icon widget displays the icon of a client.
154 -- Please note that this returns an imagebox and all of the imagebox' API is
155 -- available. This way, you can e.g. disallow resizes.
156 -- @param c The client for which an icon widget should be created.
157 -- @return The icon widget.
158 function titlebar
.widget
.iconwidget(c
)
159 local ret
= imagebox()
160 local function update()
161 ret
:set_image(c
.icon
)
163 c
:connect_signal("property::icon", update
)
169 --- Create a new button widget. A button widget displays an image and reacts to
170 -- mouse clicks. Please note that the caller has to make sure that this widget
171 -- gets redrawn when needed by calling the returned widget's update() function.
172 -- The selector function should return a value describing a state. If the value
173 -- is a boolean, either "active" or "inactive" are used. The actual image is
174 -- then found in the theme as "titlebar_[name]_button_[normal/focus]_[state]".
175 -- If that value does not exist, the focused state is ignored for the next try.
176 -- @param c The client for which a button is created.
177 -- @param name Name of the button, used for accessing the theme.
178 -- @param selector A function that selects the image that should be displayed.
179 -- @param action Function that is called when the button is clicked.
180 -- @return The widget
181 function titlebar
.widget
.button(c
, name
, selector
, action
)
182 local ret
= imagebox()
183 local function update()
184 local img
= selector(c
)
185 if type(img
) ~= "nil" then
186 -- Convert booleans automatically
187 if type(img
) == "boolean" then
194 -- First try with a prefix based on the client's focus state
195 local prefix
= "normal"
196 if capi
.client
.focus
== c
then
200 prefix
= prefix
.. "_"
202 local theme
= beautiful
["titlebar_" .. name
.. "_button_" .. prefix
.. img
]
204 -- Then try again without that prefix if nothing was found
205 theme
= beautiful
["titlebar_" .. name
.. "_button_" .. img
]
214 ret
:buttons(abutton({ }, 1, nil, function() action(c
, selector(c
)) end))
220 -- We do magic based on whether a client is focused above, so we need to
221 -- connect to the corresponding signal here.
222 local function focus_func(o
)
223 if o
== c
then update() end
225 capi
.client
.connect_signal("focus", focus_func
)
226 capi
.client
.connect_signal("unfocus", focus_func
)
231 --- Create a new float button for a client.
232 -- @param c The client for which the button is wanted.
233 function titlebar
.widget
.floatingbutton(c
)
234 local widget
= titlebar
.widget
.button(c
, "floating", aclient
.floating
.get
, aclient
.floating
.toggle
)
235 c
:connect_signal("property::floating", widget
.update
)
239 --- Create a new maximize button for a client.
240 -- @param c The client for which the button is wanted.
241 function titlebar
.widget
.maximizedbutton(c
)
242 local widget
= titlebar
.widget
.button(c
, "maximized", function(c
)
243 return c
.maximized_horizontal
or c
.maximized_vertical
244 end, function(c
, state
)
245 c
.maximized_horizontal
= not state
246 c
.maximized_vertical
= not state
248 c
:connect_signal("property::maximized_vertical", widget
.update
)
249 c
:connect_signal("property::maximized_horizontal", widget
.update
)
253 --- Create a new minimize button for a client.
254 -- @param c The client for which the button is wanted.
255 function titlebar
.widget
.minimizebutton(c
)
256 local widget
= titlebar
.widget
.button(c
, "minimize", function() return c
.minimized
end, function(c
) c
.minimized
= not c
.minimized
end)
257 c
:connect_signal("property::minimized", widget
.update
)
261 --- Create a new closing button for a client.
262 -- @param c The client for which the button is wanted.
263 function titlebar
.widget
.closebutton(c
)
264 return titlebar
.widget
.button(c
, "close", function() return "" end, function(c
) c
:kill() end)
267 --- Create a new ontop button for a client.
268 -- @param c The client for which the button is wanted.
269 function titlebar
.widget
.ontopbutton(c
)
270 local widget
= titlebar
.widget
.button(c
, "ontop", function(c
) return c
.ontop
end, function(c
, state
) c
.ontop
= not state
end)
271 c
:connect_signal("property::ontop", widget
.update
)
275 --- Create a new sticky button for a client.
276 -- @param c The client for which the button is wanted.
277 function titlebar
.widget
.stickybutton(c
)
278 local widget
= titlebar
.widget
.button(c
, "sticky", function(c
) return c
.sticky
end, function(c
, state
) c
.sticky
= not state
end)
279 c
:connect_signal("property::sticky", widget
.update
)
283 return setmetatable(titlebar
, { __call
= function(_
, ...) return new(...) end})
285 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80