Compare commits
69 Commits
v16.1
...
thumb-xren
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36c8d41914 | ||
|
|
4dafea185f | ||
|
|
77890d463a | ||
|
|
e1211a929f | ||
|
|
00f0bbd354 | ||
|
|
15d2570a3e | ||
|
|
c76f056746 | ||
|
|
cacd4b8dad | ||
|
|
b539c0a1c0 | ||
|
|
970c597796 | ||
|
|
a82b9a1d7f | ||
|
|
89a6cadfcd | ||
|
|
fb9da655df | ||
|
|
cb137674e4 | ||
|
|
1054aac7ca | ||
|
|
81c7c65a9f | ||
|
|
044bad6c40 | ||
|
|
aaa0e40af7 | ||
|
|
34f9fcaca4 | ||
|
|
f8c6dc1ecc | ||
|
|
11c468816d | ||
|
|
595d04451b | ||
|
|
6681cfbca6 | ||
|
|
14074894f9 | ||
|
|
3fcbf58873 | ||
|
|
1c2a12eb05 | ||
|
|
ec5bda6ddf | ||
|
|
5875015c11 | ||
|
|
21e9303502 | ||
|
|
94d4a219ee | ||
|
|
8a7ba9bf50 | ||
|
|
ffa6e5ba49 | ||
|
|
d1f5a46a73 | ||
|
|
131704081c | ||
|
|
21466cc94e | ||
|
|
e06b63e1dc | ||
|
|
9a03b8b4e6 | ||
|
|
47bc01d608 | ||
|
|
0e4b3bd32e | ||
|
|
9ac0cd1254 | ||
|
|
73ab9b6930 | ||
|
|
96361ab1cd | ||
|
|
b9589450bb | ||
|
|
b810bad93f | ||
|
|
b85362b5c7 | ||
|
|
03675b152d | ||
|
|
c3fdd76b58 | ||
|
|
04ba5a6617 | ||
|
|
f5f8792d42 | ||
|
|
965a2665b0 | ||
|
|
b2b0119f4d | ||
|
|
41e49ef4e6 | ||
|
|
25dd623618 | ||
|
|
28b1174c0f | ||
|
|
b70edc437c | ||
|
|
bf58e16b83 | ||
|
|
3190c5b7de | ||
|
|
5db0dceec2 | ||
|
|
5c5f507e54 | ||
|
|
d301ada47a | ||
|
|
b3f9834313 | ||
|
|
c7b23ee94a | ||
|
|
12f04e3055 | ||
|
|
7f62594cf6 | ||
|
|
405c2c9286 | ||
|
|
90a445868c | ||
|
|
427afc61b5 | ||
|
|
ee92fac10e | ||
|
|
95eea350fe |
2
AUTHORS
2
AUTHORS
@@ -6,6 +6,7 @@ tint2 is developped by :
|
||||
- Ovidiu M <mrovi9000 at gmail.com> : launcher, bug fixes
|
||||
- Mishael A Sibiryakov (death@junki.org) : freespace
|
||||
- Sebastian Reichel <sre@ring0.de> : battery, various fixes, debian package maintainer
|
||||
- Chris Lee <chrlee at protonmail> : bug fixes, maintainer starting with v16.3
|
||||
|
||||
tint2 is based on the ttm source code (http://code.google.com/p/ttm/)
|
||||
- 2007-2008 Pål Staurland <staura@gmail.com>
|
||||
@@ -32,6 +33,7 @@ Contributors:
|
||||
Ryan Gray, Jeff Blake (https://gitlab.com/berkley4) : battery format
|
||||
aaaz (https://gitlab.com/aaaz) : clock fixes
|
||||
heisenbug (https://gitlab.com/heisenbugh) : taskbar button tinting with icon color
|
||||
Fabian Carlström : taskbar sort order by app name
|
||||
|
||||
Translations:
|
||||
Bosnian:
|
||||
|
||||
@@ -152,6 +152,7 @@ set( SOURCES src/config.c
|
||||
src/separator/separator.c
|
||||
src/tint2rc.c
|
||||
src/util/area.c
|
||||
src/util/bt.c
|
||||
src/util/common.c
|
||||
src/util/fps_distribution.c
|
||||
src/util/strnatcmp.c
|
||||
|
||||
40
ChangeLog
40
ChangeLog
@@ -1,3 +1,38 @@
|
||||
2019-02-17 master
|
||||
- Fix spacing around icons in executor without text in vertical panels (issue #716)
|
||||
- Fix Bug: Clock Only Updates Every Minute With Format %s (issue #724)
|
||||
- Fix markup drawing when font shadow enabled (issue #709)
|
||||
- Blink battery when low (issue #723)
|
||||
|
||||
2018-08-05 16.6.1
|
||||
- Fix packaging regression for debian (issue #715)
|
||||
|
||||
2018-08-04 16.6
|
||||
- Fix regression in task icon brightness (issue #714)
|
||||
|
||||
2018-08-04 16.5
|
||||
- Add new build script
|
||||
- Add option to sort taskbar by application name
|
||||
- Fix regression in image loading
|
||||
|
||||
2018-05-03 16.4
|
||||
- Update AUTHORS
|
||||
- Fixes:
|
||||
- Fix leak in image loading (issue #704)
|
||||
- Executors no longer log unless env var DEBUG_EXECUTORS is set
|
||||
|
||||
2018-04-17 16.3
|
||||
- Fixes:
|
||||
- Layout in executor (issue #695)
|
||||
- Other small issues
|
||||
|
||||
2018-01-21 16.2
|
||||
- Fixes:
|
||||
- Proper fix for issue #688
|
||||
- Fix bad word wrapping (issue #693)
|
||||
- Enhancements:
|
||||
- Preliminary high DPI support
|
||||
|
||||
2017-12-30 16.1
|
||||
- Fixes:
|
||||
- Fixed several use-after-free errors in the timer code
|
||||
@@ -985,3 +1020,8 @@ released tint-0.2
|
||||
.
|
||||
.
|
||||
.
|
||||
.
|
||||
.
|
||||
.
|
||||
.
|
||||
.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Latest stable release: 16.1
|
||||
Changes: https://gitlab.com/o9000/tint2/blob/16.1/ChangeLog
|
||||
# Latest stable release: 16.6.1
|
||||
Changes: https://gitlab.com/o9000/tint2/blob/16.6.1/ChangeLog
|
||||
|
||||
Documentation: [doc/tint2.md](doc/tint2.md)
|
||||
|
||||
@@ -8,7 +8,7 @@ Compile it with (after you install the [dependencies](https://gitlab.com/o9000/t
|
||||
```
|
||||
git clone https://gitlab.com/o9000/tint2.git
|
||||
cd tint2
|
||||
git checkout 16.1
|
||||
git checkout 16.6.1
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
@@ -97,4 +97,3 @@ tint2 is a simple panel/taskbar made for modern X window managers. It was specif
|
||||
## More
|
||||
|
||||
* [Tint2 wiki](https://gitlab.com/o9000/tint2/wikis/Home)
|
||||
Home)
|
||||
|
||||
@@ -386,6 +386,8 @@ gradient_id_pressed = 2
|
||||
<li><code>width</code> and <code>height</code> can be specified without units (e.g. <code>123</code>) as pixels, or followed by <code>%</code> as percentages of the monitor size (e.g. <code>50%</code>). Use <code>100%</code> for full monitor width/height.
|
||||
Example:</li>
|
||||
</ul></li>
|
||||
<li><p><code>scale_relative_to_dpi = integer</code> : If set to a non-zero value, HiDPI scaling is enabled. Each panel is visible on a different monitor. Thus each panel has a specific scaling factor. The scaling factor is computed as the ratio between the monitor DPI (obtained from the dimensions in pixels and millimeters from RandR) and a configured reference DPI - this is the DPI for which exising user configs looked normal, for backward compatibility.</p></li>
|
||||
<li><p><code>scale_relative_to_screen_height = integer</code> : Similar to <code>scale_relative_to_dpi</code>, except the scaling factor is computed as the ratio between the monitor height and <code>scale_relative_to_screen_height</code>. The effect is cumulative with <code>scale_relative_to_dpi</code>, i.e. if both options are present, the factors are multiplied.</p></li>
|
||||
</ul>
|
||||
<pre class="highlight plaintext"><code># The panel's width is 94% the size of the monitor, the height is 30 pixels:
|
||||
panel_size = 94% 30
|
||||
@@ -464,6 +466,7 @@ panel_size = 94% 30
|
||||
<ul>
|
||||
<li><code>none</code> : No sorting. New tasks are simply appended at the end of the taskbar when they appear.</li>
|
||||
<li><code>title</code> : Sorts the tasks by title.</li>
|
||||
<li><code>application</code> : Sorts the tasks by application name. <em>(since 16.3)</em></li>
|
||||
<li><code>center</code> : Sorts the tasks by their window centers.</li>
|
||||
<li><code>mru</code> : Shows the most recently used tasks first. <em>(since 0.12.4)</em></li>
|
||||
<li><code>lru</code> : Shows the most recently used tasks last. <em>(since 0.12.4)</em></li>
|
||||
@@ -570,7 +573,7 @@ panel_size = 94% 30
|
||||
<ul>
|
||||
<li><p><code>battery_hide = never/integer (0 to 100)</code> : At what battery percentage the battery item is hidden.</p></li>
|
||||
<li><p><code>battery_low_status = integer</code>: At what battery percentage the low command is executed.</p></li>
|
||||
<li><p><code>battery_low_cmd = notify-send "battery low"</code> : Command to execute when the battery is low.</p></li>
|
||||
<li><p><code>battery_low_cmd = xmessage 'tint2: Battery low!'</code> : Command to execute when the battery is low.</p></li>
|
||||
<li><p><code>battery_full_cmd = notify-send "battery full"</code> : Command to execute when the battery is full.</p></li>
|
||||
<li><p><code>bat1_font = [FAMILY-LIST] [STYLE-OPTIONS] [SIZE]</code></p></li>
|
||||
<li><p><code>bat2_font = [FAMILY-LIST] [STYLE-OPTIONS] [SIZE]</code></p></li>
|
||||
|
||||
@@ -199,9 +199,9 @@ pre {
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="latest-stable-release-16-1"><span class="md2man-title">Latest</span> <span class="md2man-section">stable</span> <span class="md2man-date">release:</span> <span class="md2man-source">16.1</span><a name="latest-stable-release-16-1" href="#latest-stable-release-16-1" class="md2man-permalink" title="permalink"></a></h1><p>Changes: <a href="https://gitlab.com/o9000/tint2/blob/16.1/ChangeLog">https://gitlab.com/o9000/tint2/blob/16.1/ChangeLog</a></p><p>Documentation: <a href="manual.html">manual.html</a></p><p>Compile it with (after you install the <a href="https://gitlab.com/o9000/tint2/wikis/Install#dependencies">dependencies</a>):</p><pre class="highlight plaintext"><code>git clone https://gitlab.com/o9000/tint2.git
|
||||
<h1 id="latest-stable-release-16-6-1"><span class="md2man-title">Latest</span> <span class="md2man-section">stable</span> <span class="md2man-date">release:</span> <span class="md2man-source">16.6.1</span><a name="latest-stable-release-16-6-1" href="#latest-stable-release-16-6-1" class="md2man-permalink" title="permalink"></a></h1><p>Changes: <a href="https://gitlab.com/o9000/tint2/blob/16.6.1/ChangeLog">https://gitlab.com/o9000/tint2/blob/16.6.1/ChangeLog</a></p><p>Documentation: <a href="manual.html">manual.html</a></p><p>Compile it with (after you install the <a href="https://gitlab.com/o9000/tint2/wikis/Install#dependencies">dependencies</a>):</p><pre class="highlight plaintext"><code>git clone https://gitlab.com/o9000/tint2.git
|
||||
cd tint2
|
||||
git checkout 16.1
|
||||
git checkout 16.6.1
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
@@ -269,8 +269,7 @@ update-mime-database /usr/local/share/mime
|
||||
</ul>
|
||||
<h2 id="more">More<a name="more" href="#more" class="md2man-permalink" title="permalink"></a></h2>
|
||||
<ul>
|
||||
<li><a href="https://gitlab.com/o9000/tint2/wikis/Home">Tint2 wiki</a>
|
||||
Home)</li>
|
||||
<li><a href="https://gitlab.com/o9000/tint2/wikis/Home">Tint2 wiki</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
10
doc/tint2.1
10
doc/tint2.1
@@ -1,4 +1,4 @@
|
||||
.TH TINT2 1 "2017\-12\-30" 16.1
|
||||
.TH TINT2 1 "2018\-08\-05" 16.6.1
|
||||
.SH NAME
|
||||
.PP
|
||||
tint2 \- lightweight panel/taskbar
|
||||
@@ -343,6 +343,10 @@ Use \fB\fCpanel_monitor = all\fR to get a separate panel per monitor
|
||||
\fB\fCwidth\fR and \fB\fCheight\fR can be specified without units (e.g. \fB\fC123\fR) as pixels, or followed by \fB\fC%\fR as percentages of the monitor size (e.g. \fB\fC50%\fR). Use \fB\fC100%\fR for full monitor width/height.
|
||||
Example:
|
||||
.RE
|
||||
.IP \(bu 2
|
||||
\fB\fCscale_relative_to_dpi = integer\fR : If set to a non\-zero value, HiDPI scaling is enabled. Each panel is visible on a different monitor. Thus each panel has a specific scaling factor. The scaling factor is computed as the ratio between the monitor DPI (obtained from the dimensions in pixels and millimeters from RandR) and a configured reference DPI \- this is the DPI for which exising user configs looked normal, for backward compatibility.
|
||||
.IP \(bu 2
|
||||
\fB\fCscale_relative_to_screen_height = integer\fR : Similar to \fB\fCscale_relative_to_dpi\fR, except the scaling factor is computed as the ratio between the monitor height and \fB\fCscale_relative_to_screen_height\fR\&. The effect is cumulative with \fB\fCscale_relative_to_dpi\fR, i.e. if both options are present, the factors are multiplied.
|
||||
.RE
|
||||
.PP
|
||||
.RS
|
||||
@@ -476,6 +480,8 @@ You can switch between virtual desktops.
|
||||
.IP \(bu 2
|
||||
\fB\fCtitle\fR : Sorts the tasks by title.
|
||||
.IP \(bu 2
|
||||
\fB\fCapplication\fR : Sorts the tasks by application name. \fI(since 16.3)\fP
|
||||
.IP \(bu 2
|
||||
\fB\fCcenter\fR : Sorts the tasks by their window centers.
|
||||
.IP \(bu 2
|
||||
\fB\fCmru\fR : Shows the most recently used tasks first. \fI(since 0.12.4)\fP
|
||||
@@ -659,7 +665,7 @@ To hide the clock, comment \fB\fCtime1_format\fR and \fB\fCtime2_format\fR\&.
|
||||
.IP \(bu 2
|
||||
\fB\fCbattery_low_status = integer\fR: At what battery percentage the low command is executed.
|
||||
.IP \(bu 2
|
||||
\fB\fCbattery_low_cmd = notify\-send "battery low"\fR : Command to execute when the battery is low.
|
||||
\fB\fCbattery_low_cmd = xmessage 'tint2: Battery low!'\fR : Command to execute when the battery is low.
|
||||
.IP \(bu 2
|
||||
\fB\fCbattery_full_cmd = notify\-send "battery full"\fR : Command to execute when the battery is full.
|
||||
.IP \(bu 2
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# TINT2 1 "2017-12-30" 16.1
|
||||
# TINT2 1 "2018-08-05" 16.6.1
|
||||
|
||||
## NAME
|
||||
tint2 - lightweight panel/taskbar
|
||||
@@ -279,6 +279,10 @@ gradient_id_pressed = 2
|
||||
* `width` and `height` can be specified without units (e.g. `123`) as pixels, or followed by `%` as percentages of the monitor size (e.g. `50%`). Use `100%` for full monitor width/height.
|
||||
Example:
|
||||
|
||||
* `scale_relative_to_dpi = integer` : If set to a non-zero value, HiDPI scaling is enabled. Each panel is visible on a different monitor. Thus each panel has a specific scaling factor. The scaling factor is computed as the ratio between the monitor DPI (obtained from the dimensions in pixels and millimeters from RandR) and a configured reference DPI - this is the DPI for which exising user configs looked normal, for backward compatibility.
|
||||
|
||||
* `scale_relative_to_screen_height = integer` : Similar to `scale_relative_to_dpi`, except the scaling factor is computed as the ratio between the monitor height and `scale_relative_to_screen_height`. The effect is cumulative with `scale_relative_to_dpi`, i.e. if both options are present, the factors are multiplied.
|
||||
|
||||
```
|
||||
# The panel's width is 94% the size of the monitor, the height is 30 pixels:
|
||||
panel_size = 94% 30
|
||||
@@ -381,6 +385,7 @@ panel_size = 94% 30
|
||||
* `taskbar_sort_order = none/title/center` : Specifies the sort order of the tasks on the taskbar. *(since 0.12)*
|
||||
* `none` : No sorting. New tasks are simply appended at the end of the taskbar when they appear.
|
||||
* `title` : Sorts the tasks by title.
|
||||
* `application` : Sorts the tasks by application name. *(since 16.3)*
|
||||
* `center` : Sorts the tasks by their window centers.
|
||||
* `mru` : Shows the most recently used tasks first. *(since 0.12.4)*
|
||||
* `lru` : Shows the most recently used tasks last. *(since 0.12.4)*
|
||||
@@ -542,7 +547,7 @@ The action semantics:
|
||||
|
||||
* `battery_low_status = integer`: At what battery percentage the low command is executed.
|
||||
|
||||
* `battery_low_cmd = notify-send "battery low"` : Command to execute when the battery is low.
|
||||
* `battery_low_cmd = xmessage 'tint2: Battery low!'` : Command to execute when the battery is low.
|
||||
|
||||
* `battery_full_cmd = notify-send "battery full"` : Command to execute when the battery is full.
|
||||
|
||||
|
||||
@@ -76,19 +76,23 @@ def get_last_version():
|
||||
return tags[-1]
|
||||
|
||||
|
||||
def inc_version(v, feature=False):
|
||||
def inc_version(v, feature=False, tiny=False):
|
||||
if v.startswith("v0."):
|
||||
assert v == "v0.14.6"
|
||||
return "v15.0"
|
||||
# v4.11 -> v4.12 or v5.0
|
||||
# v4.11 -> v4.12 or v5.0 or v4.11.1
|
||||
parts = v.split(".")
|
||||
while len(parts) < 2:
|
||||
while len(parts) < 3:
|
||||
parts.append("0")
|
||||
assert len(parts) == 2
|
||||
assert len(parts) == 3
|
||||
if feature:
|
||||
del parts[-1]
|
||||
parts[-2] = "v" + str(int(parts[-2].replace("v", "")) + 1)
|
||||
parts[-1] = "0"
|
||||
elif tiny:
|
||||
parts[-1] = str(int(parts[-1]) + 1)
|
||||
else:
|
||||
del parts[-1]
|
||||
parts[-1] = str(int(parts[-1]) + 1)
|
||||
return ".".join([s for s in parts if s])
|
||||
|
||||
@@ -153,23 +157,14 @@ def update_log(path, version, date):
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--feature", action="store_true")
|
||||
parser.add_argument("--undo", action="store_true")
|
||||
parser.add_argument("--tiny", action="store_true")
|
||||
args = parser.parse_args()
|
||||
logging.basicConfig(format=ansi_lblue + "%(asctime)s %(pathname)s %(levelname)s" + ansi_reset + " %(message)s", level=logging.DEBUG)
|
||||
test_inc_version()
|
||||
# Read version from last tag and increment
|
||||
old_version = get_last_version()
|
||||
if args.undo:
|
||||
info("Revering last commit...")
|
||||
run("git tag -d %s" % old_version)
|
||||
run("git tag -d %s" % old_version.replace("v", ""))
|
||||
run("git reset --soft HEAD~")
|
||||
run("git reset")
|
||||
run("git stash")
|
||||
os.system("git log -1")
|
||||
sys.exit(0)
|
||||
info("Old version:", old_version)
|
||||
version = inc_version(old_version, args.feature)
|
||||
version = inc_version(old_version, args.feature, args.tiny)
|
||||
readable_version = version.replace("v", "")
|
||||
date = datetime.datetime.now().strftime("%Y-%m-%d")
|
||||
info("New version:", readable_version, version, date)
|
||||
@@ -194,3 +189,9 @@ if __name__ == '__main__':
|
||||
choice = raw_input().lower()
|
||||
if choice != "y":
|
||||
run("git reset --hard HEAD~ ; git tag -d %s ; git tag -d %s" % (version, readable_version))
|
||||
sys.exit(1)
|
||||
print "Publish? [y/n]"
|
||||
choice = raw_input().lower()
|
||||
if choice != "y":
|
||||
sys.exit(1)
|
||||
run("git push origin master && git push --tags origin master")
|
||||
|
||||
544
packaging/configure
vendored
Executable file
544
packaging/configure
vendored
Executable file
@@ -0,0 +1,544 @@
|
||||
#!/usr/bin/env python2.7
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import errno
|
||||
import os
|
||||
import shlex
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
|
||||
def check_c_compiles(cmd, code):
|
||||
with tempfile.NamedTemporaryFile(suffix='.c') as f:
|
||||
f.write(code)
|
||||
f.flush()
|
||||
cmd += [f.name, '-o', '/dev/null']
|
||||
proc = subprocess.Popen(
|
||||
cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
out, err = proc.communicate()
|
||||
ret = proc.returncode
|
||||
return ret == 0
|
||||
|
||||
|
||||
def makedirs(path):
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except OSError as e:
|
||||
if e.errno == errno.EEXIST and os.path.isdir(path):
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
def pkg_config(lib):
|
||||
def _pkgconfig(lib, query):
|
||||
lib = lib.replace('>=', ' >= ')
|
||||
cmd = 'pkg-config {} {}'.format(query, lib).split()
|
||||
popen = subprocess.Popen(cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
out, err = popen.communicate()
|
||||
if popen.returncode != 0:
|
||||
print(cmd)
|
||||
print(err)
|
||||
raise ValueError("Could not find library: {}".format(lib))
|
||||
return out.split()
|
||||
|
||||
lf = _pkgconfig(lib, '--libs-only-l')
|
||||
cf = _pkgconfig(lib, '--cflags')
|
||||
ldf = _pkgconfig(lib, '--libs-only-L')
|
||||
return (lf, cf, ldf)
|
||||
|
||||
|
||||
def ninja_escape(s):
|
||||
s = s.replace(' ', '$ ')
|
||||
s = s.replace('\n', '$\n')
|
||||
return s
|
||||
|
||||
|
||||
def ninja_join(words):
|
||||
indent = ' '
|
||||
if len(words) > 1:
|
||||
prefix = '$\n' + indent
|
||||
else:
|
||||
prefix = ''
|
||||
spacer = ' $\n' + indent
|
||||
return prefix + spacer.join(ninja_escape(s) for s in words)
|
||||
|
||||
|
||||
def ninja_write_vars(f, **kwargs):
|
||||
for k, v in kwargs.items():
|
||||
f.write('{} = {}\n'.format(k, v))
|
||||
f.write('\n')
|
||||
|
||||
|
||||
def ninja_write_rule(f, name, **kwargs):
|
||||
f.write('rule {}\n'.format(name))
|
||||
for k, v in kwargs.items():
|
||||
f.write(' {} = {}\n'.format(k, v))
|
||||
f.write('\n')
|
||||
|
||||
|
||||
def remove_prefix(s, prefix):
|
||||
while prefix and s.startswith(prefix):
|
||||
s = s[len(prefix):]
|
||||
return s
|
||||
|
||||
|
||||
def install(prefix, suffix, dest_dir, dest_suffix=''):
|
||||
src_path = os.path.join(prefix, suffix) if suffix else prefix
|
||||
fname = os.path.basename(src_path)
|
||||
if dest_suffix:
|
||||
dest_dir = os.path.join(dest_dir, dest_suffix)
|
||||
dst_path = os.path.join(dest_dir, fname)
|
||||
return [(src_path, dst_path)]
|
||||
|
||||
|
||||
def install_dir(prefix, suffix, dest_dir, dest_suffix=''):
|
||||
result = []
|
||||
src_path = os.path.join(prefix, suffix)
|
||||
for root, dirs, files in os.walk(src_path):
|
||||
for f in files:
|
||||
fname = os.path.join(root, f)
|
||||
fsuffix = remove_prefix(remove_prefix(fname, prefix), '/')
|
||||
result += install(prefix, fsuffix, dest_dir, os.path.join(dest_suffix, os.path.dirname(fsuffix)))
|
||||
return result
|
||||
|
||||
|
||||
class Executable(object):
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.cc = 'cc'
|
||||
self.cflags = []
|
||||
self.lflags = []
|
||||
self.libs = []
|
||||
self.sources = []
|
||||
self.pos = []
|
||||
self.install_exec = []
|
||||
self.install_data = []
|
||||
|
||||
def write_ninja(self, f):
|
||||
f.write('# Executable: {}\n'.format(self.name))
|
||||
ninja_write_vars(f, **{
|
||||
'cc_' + self.name: self.cc,
|
||||
'cflags_' + self.name: ninja_join(self.cflags),
|
||||
'lflags_' + self.name: ninja_join(self.lflags),
|
||||
'libs_' + self.name: ninja_join(self.libs)})
|
||||
ninja_write_rule(f, 'cc_' + self.name,
|
||||
command='$cc_{} -MMD -MT $out -MF $out.d $cflags_{} -c $in -o $out'.format(self.name, self.name),
|
||||
description='CC $out',
|
||||
depfile='$out.d',
|
||||
deps='gcc')
|
||||
ninja_write_rule(f, 'link_' + self.name,
|
||||
command='$cc_{} $lflags_{} -o $out $in $libs_{}'.format(self.name, self.name, self.name),
|
||||
description='LINK $out')
|
||||
ninja_write_rule(f, 'po2mo_' + self.name,
|
||||
command='msgfmt -o $out $in',
|
||||
description='GEN $out')
|
||||
f.write('# Compilation\n')
|
||||
for src in self.sources:
|
||||
f.write('build $build_dir/{}.{}.o: cc_{} $source_dir/{}\n'.format(src, self.name, self.name, src))
|
||||
f.write('# Translation\n')
|
||||
for po in self.pos:
|
||||
f.write('build $build_dir/{}.mo: po2mo_{} $source_dir/{}\n'.format(os.path.splitext(po)[0], self.name, po))
|
||||
f.write('# Linking\n')
|
||||
f.write('build $build_dir/{}: link_{} '.format(self.name, self.name))
|
||||
f.write(ninja_join(['$build_dir/{}.{}.o'.format(src, self.name) for src in self.sources]))
|
||||
f.write('\n')
|
||||
f.write('# Installation\n')
|
||||
for fin, fout in self.install_exec:
|
||||
f.write('build {}: install_exec {}\n'.format(fout, fin))
|
||||
for fin, fout in self.install_data:
|
||||
f.write('build {}: install_data {}\n'.format(fout, fin))
|
||||
f.write('build install_{}: phony '.format(self.name))
|
||||
f.write(ninja_join([fout for fin, fout in self.install_exec + self.install_data]))
|
||||
f.write('\n')
|
||||
f.write('# Uninstallation\n')
|
||||
for fin, fout in self.install_exec + self.install_data:
|
||||
f.write('build uninstall_{}: uninstall {}\n'.format(fout, fout))
|
||||
f.write('build uninstall_{}: phony '.format(self.name))
|
||||
f.write(ninja_join(['uninstall_{}'.format(fout) for fin, fout in self.install_exec + self.install_data]))
|
||||
f.write('\n')
|
||||
f.write('\n')
|
||||
|
||||
|
||||
|
||||
def generate_ninja(targets, source_dir, build_dir):
|
||||
ninja_file_name = os.path.join(build_dir, 'build.ninja')
|
||||
f = open(ninja_file_name, 'w')
|
||||
# `deps` was introduced in ninja 1.3.
|
||||
ninja_write_vars(f, ninja_required_version='1.3')
|
||||
ninja_write_vars(f, **{
|
||||
'source_dir':source_dir,
|
||||
'build_dir':build_dir
|
||||
})
|
||||
ninja_write_rule(f, 'install_exec',
|
||||
command='install -D -m0755 $in $out',
|
||||
description='INSTALL $out')
|
||||
ninja_write_rule(f, 'install_data',
|
||||
command='install -D -m0644 $in $out',
|
||||
description='INSTALL $out')
|
||||
ninja_write_rule(f, 'uninstall',
|
||||
command='rm -f $in',
|
||||
description='RM $in')
|
||||
for t in targets:
|
||||
t.write_ninja(f)
|
||||
f.write('# Targets\n')
|
||||
f.write('build all: phony ')
|
||||
f.write(ninja_join(['$build_dir/{}'.format(t.name) for t in targets]))
|
||||
f.write('\n')
|
||||
installs = sum([(t.install_exec + t.install_data) for t in targets], [])
|
||||
if installs:
|
||||
f.write('build install: phony ')
|
||||
f.write(ninja_join(['install_{}'.format(t.name) for t in targets]))
|
||||
f.write('\n')
|
||||
f.write('build uninstall: phony ')
|
||||
f.write(ninja_join(['uninstall_{}'.format(t.name) for t in targets]))
|
||||
f.write('\n')
|
||||
f.write('\n')
|
||||
f.write('default all\n')
|
||||
f.close()
|
||||
print('Wrote {}.'.format(ninja_file_name))
|
||||
print('Run `ninja -v -C {} all` to compile.'.format(build_dir))
|
||||
print('Run `ninja -v -C {} install` to install.'.format(build_dir))
|
||||
|
||||
|
||||
# Parse CLI options
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--uevent', dest='uevent', action='store_true',
|
||||
help='Enable uevent support. Default: on under Linux')
|
||||
parser.add_argument('--debug', dest='debug', action='store_true',
|
||||
help='Enable debug build. Default: off')
|
||||
parser.add_argument('--asan', dest='asan', action='store_true',
|
||||
help='Enable AddressSanitizer. Default: off')
|
||||
parser.add_argument('--tracing', dest='tracing', action='store_true',
|
||||
help='Enable tracing. Default: off')
|
||||
parser.add_argument('--memory-tracing', dest='memory_tracing', action='store_true',
|
||||
help='Enable memory allocation tracing. Default: off')
|
||||
parser.add_argument('--prefix', help='Prefix for constructing the file installation paths. Default: /usr/local', default=None)
|
||||
parser.add_argument('--exec_prefix', help='Prefix for binary paths. Default: $prefix', default=None)
|
||||
parser.add_argument('--bindir', help='Path where executables must be installed. Default: $exec_prefix/bin', default=None)
|
||||
parser.add_argument('--sysconfdir', help='Path where config files must be installed. Default: /etc', default=None)
|
||||
parser.add_argument('--datarootdir', help='Path where data files must be installed. Default: $prefix/share', default=None)
|
||||
parser.add_argument('--localedir', help='Path where locale files must be installed. Default: $datarootdir/locale', default=None)
|
||||
parser.add_argument('--docdir', help='Path where documentation files must be installed. Default: $datarootdir/doc/tint2', default=None)
|
||||
parser.add_argument('--htmldir', help='Path where documentation files must be installed. Default: $docdir/html', default=None)
|
||||
parser.add_argument('--mandir', help='Path where man files must be installed. Default: $datarootdir/man', default=None)
|
||||
parser.add_argument('--home', dest='home', action='store_true',
|
||||
help='Install to $HOME (sets all paths accordingly). Default: off')
|
||||
args = parser.parse_args()
|
||||
|
||||
# Get relevant environment variables
|
||||
CC = os.environ.get('CC', 'cc')
|
||||
CFLAGS = shlex.split(os.environ.get('CFLAGS', ''))
|
||||
LFLAGS = shlex.split(os.environ.get('LDFLAGS', ''))
|
||||
LIBS = []
|
||||
|
||||
# Get paths
|
||||
source_dir = os.path.realpath(os.path.dirname(os.path.realpath(__file__)) + '/..')
|
||||
build_dir = os.path.join(os.getcwd(), 'build')
|
||||
if not args.home:
|
||||
prefix = args.prefix or '/usr/local'
|
||||
exec_prefix = args.exec_prefix or prefix
|
||||
bindir = args.bindir or os.path.join(exec_prefix, 'bin')
|
||||
datarootdir = args.datarootdir or os.path.join(prefix, 'share')
|
||||
sysconfdir = args.sysconfdir or '/etc'
|
||||
docdir = args.docdir or os.path.join(datarootdir, 'doc/tint2')
|
||||
htmldir = args.htmldir or os.path.join(docdir, 'html')
|
||||
localedir = args.localedir or os.path.join(datarootdir, 'locale')
|
||||
mandir = args.mandir or os.path.join(datarootdir, 'man')
|
||||
else:
|
||||
prefix = args.prefix or os.path.expanduser("~")
|
||||
exec_prefix = args.exec_prefix or prefix
|
||||
bindir = args.bindir or os.path.join(exec_prefix, 'bin')
|
||||
datarootdir = args.datarootdir or os.path.join(prefix, '.local/share')
|
||||
sysconfdir = args.sysconfdir or os.path.expanduser("~/.config/tint2")
|
||||
docdir = args.docdir or os.path.join(datarootdir, 'doc/tint2')
|
||||
htmldir = args.htmldir or os.path.join(docdir, 'html')
|
||||
localedir = args.localedir or os.path.join(datarootdir, 'locale')
|
||||
mandir = args.mandir or os.path.join(datarootdir, 'man')
|
||||
|
||||
|
||||
# Check if C11 is supported by the compiler, fall back to C99
|
||||
if check_c_compiles([CC],
|
||||
'''#define print(x) _Generic((x), default : print_unknown)(x)
|
||||
void print_unknown() {
|
||||
}
|
||||
int main () {
|
||||
print(0);
|
||||
}'''):
|
||||
CFLAGS += ['-std=c11', '-DHAS_GENERIC']
|
||||
else:
|
||||
print("No C11 support.")
|
||||
CFLAGS += ['-std=c99']
|
||||
|
||||
# Set mandatory flags
|
||||
CFLAGS += ['-g',
|
||||
'-Wall',
|
||||
'-Wextra',
|
||||
'-Wshadow',
|
||||
'-Wpointer-arith',
|
||||
'-Wno-deprecated',
|
||||
'-Wno-missing-field-initializers',
|
||||
'-Wno-unused-parameter',
|
||||
'-Wno-sign-compare',
|
||||
'-fno-strict-aliasing',
|
||||
'-pthread',
|
||||
'-D_BSD_SOURCE',
|
||||
'-D_DEFAULT_SOURCE',
|
||||
'-D_WITH_GETLINE',
|
||||
'-DENABLE_BATTERY']
|
||||
LFLAGS += ['-fno-strict-aliasing',
|
||||
'-pthread']
|
||||
LFLAGS += ['-L' + build_dir]
|
||||
|
||||
# Set platform dependent C flags
|
||||
if sys.platform.startswith('linux'):
|
||||
CFLAGS += ['-D_POSIX_C_SOURCE=200809L']
|
||||
|
||||
if sys.platform.startswith('freebsd') or sys.platform.startswith('openbsd') or sys.platform.startswith('dragonfly'):
|
||||
CFLAGS += ['-I/usr/local/include']
|
||||
LFLAGS += ['-L/usr/local/lib']
|
||||
|
||||
if sys.platform.startswith('linux') or args.uevent:
|
||||
CFLAGS += ['-DENABLE_UEVENT']
|
||||
|
||||
# Turn on color messages if supported
|
||||
if check_c_compiles([CC, '-fdiagnostics-color', '-c', '-x', 'c'], ''):
|
||||
CFLAGS += ['-fdiagnostics-color=always']
|
||||
|
||||
# Set project-specific include dirs
|
||||
CFLAGS += ['-I.']
|
||||
for inc in ['src',
|
||||
'src/battery',
|
||||
'src/clock',
|
||||
'src/systray',
|
||||
'src/taskbar',
|
||||
'src/launcher',
|
||||
'src/tooltip',
|
||||
'src/util',
|
||||
'src/execplugin',
|
||||
'src/button',
|
||||
'src/freespace',
|
||||
'src/separator']:
|
||||
CFLAGS += ['-I' + os.path.join(source_dir, inc)]
|
||||
|
||||
# Add mandatory library dependencies
|
||||
LIBS += ['-lm', '-lrt']
|
||||
|
||||
# Add mandatory libray dependencies detected with pkg-config
|
||||
for dep in ['x11',
|
||||
'xcomposite',
|
||||
'xdamage',
|
||||
'xinerama',
|
||||
'xext',
|
||||
'xrender',
|
||||
'xrandr>=1.3',
|
||||
'pangocairo',
|
||||
'pango',
|
||||
'cairo',
|
||||
'glib-2.0',
|
||||
'gobject-2.0',
|
||||
'imlib2>=1.4.2']:
|
||||
lib, cf, lf = pkg_config(dep)
|
||||
LIBS += lib
|
||||
CFLAGS += cf
|
||||
LFLAGS += lf
|
||||
|
||||
# Add optional library dependencies detected with pkg-config
|
||||
try:
|
||||
lib, cf, lf = pkg_config('librsvg-2.0>=2.14.0')
|
||||
LIBS += lib
|
||||
CFLAGS += cf + ['-DHAVE_RSVG']
|
||||
LFLAGS += lf
|
||||
except:
|
||||
print("No SVG support.")
|
||||
|
||||
try:
|
||||
lib, cf, lf = pkg_config('libstartup-notification-1.0>=0.12')
|
||||
LIBS += lib
|
||||
CFLAGS += cf + ['-DHAVE_SN', '-DSN_API_NOT_YET_FROZEN']
|
||||
LFLAGS += lf
|
||||
except:
|
||||
print("No startup notification support.")
|
||||
|
||||
# Add library dependencies detected with using successful compilation test
|
||||
bt = False
|
||||
if not bt:
|
||||
try:
|
||||
lib, cf, lf = pkg_config('libunwind')
|
||||
LIBS += lib
|
||||
CFLAGS += cf + ['-DHAS_LIBUNWIND']
|
||||
LFLAGS += lf
|
||||
bt = True
|
||||
print("Backtrace support via libunwind.")
|
||||
except:
|
||||
print("No backtrace support via libunwind.")
|
||||
if not bt:
|
||||
if check_c_compiles([CC, '-lbacktrace'], '''#include <backtrace.h>
|
||||
int main() {
|
||||
return 0;
|
||||
}'''):
|
||||
CFLAGS += ['-DHAS_BACKTRACE']
|
||||
LIBS += ['-lbacktrace']
|
||||
bt = True
|
||||
print("Backtrace support via libbacktrace.")
|
||||
else:
|
||||
print("No backtrace support via libbacktrace.")
|
||||
|
||||
# Add option-dependent flags
|
||||
if not args.debug:
|
||||
CFLAGS += ['-O2']
|
||||
|
||||
if args.asan:
|
||||
asan_flags = ['-fsanitize=address']
|
||||
CFLAGS += asan_flags
|
||||
LFLAGS += asan_flags
|
||||
|
||||
if args.tracing:
|
||||
CFLAGS += ['-finstrument-functions',
|
||||
'-finstrument-functions-exclude-file-list=tracing.c',
|
||||
'-finstrument-functions-exclude-function-list=get_time,gettime']
|
||||
|
||||
if args.asan or args.memory_tracing or args.tracing:
|
||||
trace_flags = ['-O0',
|
||||
'-fno-common',
|
||||
'-fno-omit-frame-pointer',
|
||||
'-rdynamic']
|
||||
CFLAGS += trace_flags
|
||||
LFLAGS += trace_flags + ['-fuse-ld=gold']
|
||||
|
||||
if args.memory_tracing:
|
||||
LIBS += ['-ldl']
|
||||
|
||||
# Define targets
|
||||
tint2 = Executable('tint2')
|
||||
tint2.cflags += CFLAGS
|
||||
tint2.lflags += LFLAGS
|
||||
tint2.libs += LIBS
|
||||
tint2.sources = ['src/config.c',
|
||||
'src/panel.c',
|
||||
'src/util/server.c',
|
||||
'src/main.c',
|
||||
'src/init.c',
|
||||
'src/util/signals.c',
|
||||
'src/util/tracing.c',
|
||||
'src/mouse_actions.c',
|
||||
'src/drag_and_drop.c',
|
||||
'src/default_icon.c',
|
||||
'src/clock/clock.c',
|
||||
'src/systray/systraybar.c',
|
||||
'src/launcher/launcher.c',
|
||||
'src/launcher/apps-common.c',
|
||||
'src/launcher/icon-theme-common.c',
|
||||
'src/launcher/xsettings-client.c',
|
||||
'src/launcher/xsettings-common.c',
|
||||
'src/taskbar/task.c',
|
||||
'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',
|
||||
'src/util/area.c',
|
||||
'src/util/bt.c',
|
||||
'src/util/common.c',
|
||||
'src/util/fps_distribution.c',
|
||||
'src/util/strnatcmp.c',
|
||||
'src/util/timer.c',
|
||||
'src/util/cache.c',
|
||||
'src/util/color.c',
|
||||
'src/util/strlcat.c',
|
||||
'src/util/print.c',
|
||||
'src/util/gradient.c',
|
||||
'src/util/test.c',
|
||||
'src/util/uevent.c',
|
||||
'src/util/window.c',
|
||||
'src/battery/battery.c']
|
||||
|
||||
# Battery implementation is platform-specific
|
||||
if sys.platform.startswith('linux'):
|
||||
tint2.sources += ['src/battery/linux.c']
|
||||
elif sys.platform.startswith('freebsd') or \
|
||||
sys.platform.startswith('dragonfly') or \
|
||||
sys.platform.startswith('gnukfreebsd'):
|
||||
tint2.sources += ['src/battery/freebsd.c']
|
||||
elif sys.platform.startswith('openbsd') or \
|
||||
sys.platform.startswith('netbsd'):
|
||||
tint2.sources += ['src/battery/openbsd.c']
|
||||
else:
|
||||
print("No battery support for platform:", sys.platform)
|
||||
tint2.sources += ['src/battery/dummy.c']
|
||||
|
||||
if args.memory_tracing:
|
||||
tint2.sources += ['src/util/mem.c']
|
||||
|
||||
tint2.install_exec = install(build_dir, 'tint2', bindir)
|
||||
tint2.install_data = (install(source_dir, 'tint2.svg', datarootdir, 'icons/hicolor/scalable/apps') +
|
||||
install(source_dir, 'tint2.desktop', datarootdir, 'applications') +
|
||||
install(source_dir, 'themes/tint2rc', sysconfdir, 'xdg/tint2') +
|
||||
install(source_dir, 'default_icon.png', datarootdir, 'tint2') +
|
||||
install(source_dir, 'AUTHORS', docdir) +
|
||||
install(source_dir, 'ChangeLog', docdir) +
|
||||
install(source_dir, 'README.md', docdir) +
|
||||
install(source_dir, 'doc/tint2.md', docdir) +
|
||||
install(source_dir, 'doc/manual.html', htmldir) +
|
||||
install(source_dir, 'doc/readme.html', htmldir) +
|
||||
install_dir(source_dir, 'doc/images', htmldir) +
|
||||
install(source_dir, 'doc/tint2.1', mandir, 'man1'))
|
||||
|
||||
tint2conf = Executable('tint2conf')
|
||||
tint2conf.cflags += CFLAGS
|
||||
tint2conf.lflags += LFLAGS
|
||||
tint2conf.libs += LIBS
|
||||
|
||||
for dep in ['gthread-2.0',
|
||||
'gtk+-x11-2.0']:
|
||||
lib, cf, lf = pkg_config(dep)
|
||||
tint2conf.libs += lib
|
||||
tint2conf.cflags += cf
|
||||
tint2conf.lflags += lf
|
||||
|
||||
tint2conf.cflags += ['-DTINT2CONF',
|
||||
'-DINSTALL_PREFIX=\\"{}\\"'.format(prefix),
|
||||
'-DLOCALEDIR=\\"{}\\"'.format(localedir),
|
||||
'-DGETTEXT_PACKAGE=\\"tint2conf\\"',
|
||||
'-DHAVE_VERSION_H',
|
||||
'-Wno-shadow']
|
||||
|
||||
tint2conf.sources = ['src/util/bt.c',
|
||||
'src/util/common.c',
|
||||
'src/util/strnatcmp.c',
|
||||
'src/util/cache.c',
|
||||
'src/util/timer.c',
|
||||
'src/util/test.c',
|
||||
'src/util/print.c',
|
||||
'src/util/signals.c',
|
||||
'src/config.c',
|
||||
'src/util/server.c',
|
||||
'src/util/strlcat.c',
|
||||
'src/launcher/apps-common.c',
|
||||
'src/launcher/icon-theme-common.c',
|
||||
'src/tint2conf/md4.c',
|
||||
'src/tint2conf/main.c',
|
||||
'src/tint2conf/properties.c',
|
||||
'src/tint2conf/properties_rw.c',
|
||||
'src/tint2conf/theme_view.c',
|
||||
'src/tint2conf/background_gui.c',
|
||||
'src/tint2conf/gradient_gui.c']
|
||||
tint2conf.pos = [os.path.join('src/tint2conf/po', f) for f in os.listdir('src/tint2conf/po') if f.endswith('.po')]
|
||||
tint2conf.install_exec = install(build_dir, 'tint2conf', bindir)
|
||||
tint2conf.install_data = (install(source_dir, 'src/tint2conf/tint2conf.svg', datarootdir, 'icons/hicolor/scalable/apps') +
|
||||
install(source_dir, 'src/tint2conf/tint2conf.desktop', datarootdir, 'applications') +
|
||||
install(source_dir, 'src/tint2conf/tint2conf.xml', datarootdir, 'mime/packages'))
|
||||
|
||||
makedirs(build_dir)
|
||||
assert 0 == os.system('cd {}; {}/get_version.sh'.format(build_dir, source_dir))
|
||||
generate_ninja([tint2, tint2conf], source_dir, build_dir)
|
||||
@@ -49,7 +49,7 @@ echo "echo \"#define VERSION_STRING \\\"$VERSION\\\"\" > version.h" > $DIR/get_v
|
||||
# Copy the debian files into the source directory
|
||||
cp -r debian $DIR/debian
|
||||
|
||||
for DISTRO in trusty xenial zesty artful bionic
|
||||
for DISTRO in trusty xenial artful bionic
|
||||
do
|
||||
# Cleanup from previous builds
|
||||
rm -rf tint2_$VERSION-*
|
||||
|
||||
@@ -15,7 +15,7 @@ git reset --hard
|
||||
git pull
|
||||
|
||||
|
||||
~/tint2/packaging/version_status.py > packaging.tmp.md
|
||||
timeout -k 10 600 ~/tint2/packaging/version_status.py > packaging.tmp.md
|
||||
cat packaging.tmp.md > packaging.md
|
||||
rm packaging.tmp.md
|
||||
|
||||
|
||||
@@ -289,7 +289,7 @@ def get_gentoo_versions():
|
||||
|
||||
def get_void_versions():
|
||||
print >> sys.stderr, "Void ..."
|
||||
template = http_download_txt("https://raw.githubusercontent.com/voidlinux/void-packages/master/srcpkgs/tint2/template")
|
||||
template = http_download_txt("https://raw.githubusercontent.com/void-linux/void-packages/master/srcpkgs/tint2/template")
|
||||
versions = []
|
||||
version = None
|
||||
maintainer = None
|
||||
|
||||
@@ -42,6 +42,7 @@ gboolean battery_enabled;
|
||||
gboolean battery_tooltip_enabled;
|
||||
int percentage_hide;
|
||||
static Timer battery_timer;
|
||||
static Timer battery_blink_timer;
|
||||
|
||||
#define BATTERY_BUF_SIZE 256
|
||||
static char buf_bat_line1[BATTERY_BUF_SIZE];
|
||||
@@ -60,6 +61,9 @@ char *battery_rclick_command;
|
||||
char *battery_uwheel_command;
|
||||
char *battery_dwheel_command;
|
||||
gboolean battery_found;
|
||||
gboolean battery_warn;
|
||||
gboolean battery_warn_red;
|
||||
Background *battery_warn_bg;
|
||||
|
||||
char *battery_sys_prefix = (char *)"";
|
||||
|
||||
@@ -77,6 +81,10 @@ void default_battery()
|
||||
battery_low_cmd_sent = FALSE;
|
||||
battery_full_cmd_sent = FALSE;
|
||||
INIT_TIMER(battery_timer);
|
||||
INIT_TIMER(battery_blink_timer);
|
||||
battery_warn = FALSE;
|
||||
battery_warn_red = FALSE;
|
||||
battery_warn_bg = NULL;
|
||||
bat1_has_font = FALSE;
|
||||
bat1_font_desc = NULL;
|
||||
bat1_format = NULL;
|
||||
@@ -128,7 +136,9 @@ void cleanup_battery()
|
||||
free(ac_disconnected_cmd);
|
||||
ac_disconnected_cmd = NULL;
|
||||
destroy_timer(&battery_timer);
|
||||
destroy_timer(&battery_blink_timer);
|
||||
battery_found = FALSE;
|
||||
free_and_null(battery_warn_bg);
|
||||
|
||||
battery_os_free();
|
||||
}
|
||||
@@ -225,7 +235,8 @@ void init_battery()
|
||||
|
||||
battery_found = battery_os_init();
|
||||
|
||||
change_timer(&battery_timer, true, 10, 30000, update_battery_tick, 0);
|
||||
if (!battery_timer.enabled_)
|
||||
change_timer(&battery_timer, true, 30000, 30000, update_battery_tick, 0);
|
||||
|
||||
update_battery();
|
||||
}
|
||||
@@ -272,6 +283,7 @@ void init_battery_panel(void *p)
|
||||
bat1_format = strdup("%p");
|
||||
bat2_format = strdup("%t");
|
||||
}
|
||||
update_battery_tick(NULL);
|
||||
}
|
||||
|
||||
void battery_init_fonts()
|
||||
@@ -308,6 +320,40 @@ void battery_default_font_changed()
|
||||
schedule_panel_redraw();
|
||||
}
|
||||
|
||||
void blink_battery(void *arg)
|
||||
{
|
||||
if (!battery_enabled)
|
||||
return;
|
||||
battery_warn_red = battery_warn ? !battery_warn_red : FALSE;
|
||||
if (battery_warn_red && !battery_warn_bg) {
|
||||
battery_warn_bg = calloc(1, sizeof(*battery_warn_bg));
|
||||
*battery_warn_bg = *panel_config.battery.area.bg;
|
||||
battery_warn_bg->fill_color.alpha = 1.0;
|
||||
battery_warn_bg->border.color.alpha = 1.0;
|
||||
}
|
||||
if (battery_warn_red) {
|
||||
battery_warn_bg->fill_color.rgb[0] = 0.6;
|
||||
battery_warn_bg->fill_color.rgb[1] = 0.1;
|
||||
battery_warn_bg->fill_color.rgb[2] = 0.1;
|
||||
battery_warn_bg->border.color.rgb[0] = 0.5;
|
||||
battery_warn_bg->border.color.rgb[1] = 0.0;
|
||||
battery_warn_bg->border.color.rgb[2] = 0.0;
|
||||
} else {
|
||||
battery_warn_bg->fill_color.rgb[0] = 0.9;
|
||||
battery_warn_bg->fill_color.rgb[1] = 0.7;
|
||||
battery_warn_bg->fill_color.rgb[2] = 0.1;
|
||||
battery_warn_bg->border.color.rgb[0] = 0.7;
|
||||
battery_warn_bg->border.color.rgb[1] = 0.5;
|
||||
battery_warn_bg->border.color.rgb[2] = 0.1;
|
||||
}
|
||||
for (int i = 0; i < num_panels; i++) {
|
||||
if (panels[i].battery.area.on_screen) {
|
||||
panels[i].battery.area.bg = battery_warn_bg;
|
||||
schedule_redraw(&panels[i].battery.area);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void update_battery_tick(void *arg)
|
||||
{
|
||||
if (!battery_enabled)
|
||||
@@ -318,6 +364,7 @@ void update_battery_tick(void *arg)
|
||||
gboolean old_ac_connected = battery_state.ac_connected;
|
||||
int16_t old_hours = battery_state.time.hours;
|
||||
int8_t old_minutes = battery_state.time.minutes;
|
||||
gboolean old_warn = battery_warn;
|
||||
|
||||
if (!battery_found) {
|
||||
init_battery();
|
||||
@@ -355,6 +402,20 @@ void update_battery_tick(void *arg)
|
||||
battery_full_cmd_sent = FALSE;
|
||||
}
|
||||
|
||||
if (!battery_blink_timer.enabled_) {
|
||||
if (battery_state.percentage < battery_low_status &&
|
||||
battery_state.state == BATTERY_DISCHARGING) {
|
||||
change_timer(&battery_blink_timer, true, 10, 1000, blink_battery, 0);
|
||||
battery_warn = TRUE;
|
||||
}
|
||||
} else {
|
||||
if (battery_state.percentage > battery_low_status ||
|
||||
battery_state.state != BATTERY_DISCHARGING) {
|
||||
stop_timer(&battery_blink_timer);
|
||||
battery_warn = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_panels; i++) {
|
||||
// Show/hide if needed
|
||||
if (!battery_found) {
|
||||
@@ -368,8 +429,11 @@ void update_battery_tick(void *arg)
|
||||
// Redraw if needed
|
||||
if (panels[i].battery.area.on_screen) {
|
||||
if (old_found != battery_found || old_percentage != battery_state.percentage ||
|
||||
old_hours != battery_state.time.hours || old_minutes != battery_state.time.minutes) {
|
||||
old_hours != battery_state.time.hours || old_minutes != battery_state.time.minutes ||
|
||||
old_warn != battery_warn) {
|
||||
panels[i].battery.area.resize_needed = TRUE;
|
||||
if (!battery_warn)
|
||||
panels[i].battery.area.bg = panel_config.battery.area.bg;
|
||||
schedule_panel_redraw();
|
||||
}
|
||||
}
|
||||
@@ -420,6 +484,7 @@ gboolean resize_battery(void *obj)
|
||||
void draw_battery(void *obj, cairo_t *c)
|
||||
{
|
||||
Battery *battery = (Battery *)obj;
|
||||
Panel *panel = (Panel *)battery->area.panel;
|
||||
draw_text_area(&battery->area,
|
||||
c,
|
||||
buf_bat_line1,
|
||||
@@ -428,7 +493,8 @@ void draw_battery(void *obj, cairo_t *c)
|
||||
bat2_font_desc,
|
||||
battery->bat1_posy,
|
||||
battery->bat2_posy,
|
||||
&battery->font_color);
|
||||
&battery->font_color,
|
||||
panel->scale);
|
||||
}
|
||||
|
||||
void battery_dump_geometry(void *obj, int indent)
|
||||
|
||||
@@ -269,9 +269,9 @@ 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 horiz_padding = (panel_horizontal ? button->area.paddingxlr : button->area.paddingy) * panel->scale;
|
||||
int vert_padding = (panel_horizontal ? button->area.paddingy : button->area.paddingxlr) * panel->scale;
|
||||
int interior_padding = button->area.paddingx * panel->scale;
|
||||
|
||||
int icon_w, icon_h;
|
||||
if (button->backend->icon_name) {
|
||||
@@ -280,18 +280,17 @@ int button_compute_desired_size(void *obj)
|
||||
else
|
||||
icon_h = icon_w = button->area.width - left_right_border_width(&button->area) - 2 * horiz_padding;
|
||||
if (button->backend->max_icon_size) {
|
||||
icon_w = MIN(icon_w, button->backend->max_icon_size);
|
||||
icon_h = MIN(icon_h, button->backend->max_icon_size);
|
||||
icon_w = MIN(icon_w, button->backend->max_icon_size * panel->scale);
|
||||
icon_h = MIN(icon_h, button->backend->max_icon_size * panel->scale);
|
||||
}
|
||||
} else {
|
||||
icon_h = icon_w = 0;
|
||||
}
|
||||
|
||||
int txt_height_ink, txt_height, txt_width;
|
||||
int 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,
|
||||
@@ -300,10 +299,11 @@ int button_compute_desired_size(void *obj)
|
||||
strlen(button->backend->text),
|
||||
PANGO_WRAP_WORD_CHAR,
|
||||
PANGO_ELLIPSIZE_NONE,
|
||||
FALSE);
|
||||
button->backend->centered ? PANGO_ALIGN_CENTER : PANGO_ALIGN_LEFT,
|
||||
FALSE,
|
||||
panel->scale);
|
||||
} else {
|
||||
get_text_size2(button->backend->font_desc,
|
||||
&txt_height_ink,
|
||||
&txt_height,
|
||||
&txt_width,
|
||||
panel->area.height,
|
||||
@@ -313,10 +313,12 @@ int button_compute_desired_size(void *obj)
|
||||
strlen(button->backend->text),
|
||||
PANGO_WRAP_WORD_CHAR,
|
||||
PANGO_ELLIPSIZE_NONE,
|
||||
FALSE);
|
||||
button->backend->centered ? PANGO_ALIGN_CENTER : PANGO_ALIGN_LEFT,
|
||||
FALSE,
|
||||
panel->scale);
|
||||
}
|
||||
} else {
|
||||
txt_height_ink = txt_height = txt_width = 0;
|
||||
txt_height = txt_width = 0;
|
||||
}
|
||||
|
||||
if (panel_horizontal) {
|
||||
@@ -336,9 +338,9 @@ gboolean resize_button(void *obj)
|
||||
Button *button = (Button *)obj;
|
||||
Panel *panel = (Panel *)button->area.panel;
|
||||
Area *area = &button->area;
|
||||
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 horiz_padding = (panel_horizontal ? button->area.paddingxlr : button->area.paddingy) * panel->scale;
|
||||
int vert_padding = (panel_horizontal ? button->area.paddingy : button->area.paddingxlr) * panel->scale;
|
||||
int interior_padding = button->area.paddingx * panel->scale;
|
||||
|
||||
int icon_w, icon_h;
|
||||
if (button->backend->icon_name) {
|
||||
@@ -347,8 +349,8 @@ gboolean resize_button(void *obj)
|
||||
else
|
||||
icon_h = icon_w = button->area.width - left_right_border_width(&button->area) - 2 * horiz_padding;
|
||||
if (button->backend->max_icon_size) {
|
||||
icon_w = MIN(icon_w, button->backend->max_icon_size);
|
||||
icon_h = MIN(icon_h, button->backend->max_icon_size);
|
||||
icon_w = MIN(icon_w, button->backend->max_icon_size * panel->scale);
|
||||
icon_h = MIN(icon_h, button->backend->max_icon_size * panel->scale);
|
||||
}
|
||||
} else {
|
||||
icon_h = icon_w = 0;
|
||||
@@ -369,10 +371,9 @@ gboolean resize_button(void *obj)
|
||||
available_h = panel->area.height;
|
||||
}
|
||||
|
||||
int txt_height_ink, txt_height, txt_width;
|
||||
int txt_height, txt_width;
|
||||
if (button->backend->text) {
|
||||
get_text_size2(button->backend->font_desc,
|
||||
&txt_height_ink,
|
||||
&txt_height,
|
||||
&txt_width,
|
||||
available_h,
|
||||
@@ -381,9 +382,11 @@ gboolean resize_button(void *obj)
|
||||
strlen(button->backend->text),
|
||||
PANGO_WRAP_WORD_CHAR,
|
||||
PANGO_ELLIPSIZE_NONE,
|
||||
FALSE);
|
||||
button->backend->centered ? PANGO_ALIGN_CENTER : PANGO_ALIGN_LEFT,
|
||||
FALSE,
|
||||
panel->scale);
|
||||
} else {
|
||||
txt_height_ink = txt_height = txt_width = 0;
|
||||
txt_height = txt_width = 0;
|
||||
}
|
||||
|
||||
gboolean result = FALSE;
|
||||
@@ -436,6 +439,7 @@ gboolean resize_button(void *obj)
|
||||
void draw_button(void *obj, cairo_t *c)
|
||||
{
|
||||
Button *button = obj;
|
||||
Panel *panel = (Panel *)button->area.panel;
|
||||
|
||||
if (button->frontend->icon) {
|
||||
// Render icon
|
||||
@@ -457,10 +461,12 @@ void draw_button(void *obj, cairo_t *c)
|
||||
|
||||
// Render text
|
||||
if (button->backend->text) {
|
||||
PangoLayout *layout = pango_cairo_create_layout(c);
|
||||
PangoContext *context = pango_cairo_create_context(c);
|
||||
pango_cairo_context_set_resolution(context, 96 * panel->scale);
|
||||
PangoLayout *layout = pango_layout_new(context);
|
||||
|
||||
pango_layout_set_font_description(layout, button->backend->font_desc);
|
||||
pango_layout_set_width(layout, (button->frontend->textw + 1) * PANGO_SCALE);
|
||||
pango_layout_set_width(layout, (button->frontend->textw + TINT2_PANGO_SLACK) * 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);
|
||||
@@ -472,9 +478,10 @@ void draw_button(void *obj, cairo_t *c)
|
||||
button->frontend->textx,
|
||||
button->frontend->texty,
|
||||
&button->backend->font_color,
|
||||
panel_config.font_shadow);
|
||||
panel_config.font_shadow ? layout : NULL);
|
||||
|
||||
g_object_unref(layout);
|
||||
g_object_unref(context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -173,7 +173,13 @@ gboolean time_format_needs_sec_ticks(char *time_format)
|
||||
{
|
||||
if (!time_format)
|
||||
return FALSE;
|
||||
if (strchr(time_format, 'S') || strchr(time_format, 'T') || strchr(time_format, 'r'))
|
||||
if (strchr(time_format, 'c') ||
|
||||
strchr(time_format, 'r') ||
|
||||
strchr(time_format, 's') ||
|
||||
strchr(time_format, 'S') ||
|
||||
strchr(time_format, 'T') ||
|
||||
strchr(time_format, 'X') ||
|
||||
strchr(time_format, '+'))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
@@ -261,10 +267,8 @@ void clock_default_font_changed()
|
||||
}
|
||||
|
||||
void clock_compute_text_geometry(Clock *clock,
|
||||
int *time_height_ink,
|
||||
int *time_height,
|
||||
int *time_width,
|
||||
int *date_height_ink,
|
||||
int *date_height,
|
||||
int *date_width)
|
||||
{
|
||||
@@ -273,10 +277,8 @@ void clock_compute_text_geometry(Clock *clock,
|
||||
time2_format ? buf_date : NULL,
|
||||
time1_font_desc,
|
||||
time2_font_desc,
|
||||
time_height_ink,
|
||||
time_height,
|
||||
time_width,
|
||||
date_height_ink,
|
||||
date_height,
|
||||
date_width);
|
||||
}
|
||||
@@ -306,6 +308,7 @@ gboolean resize_clock(void *obj)
|
||||
void draw_clock(void *obj, cairo_t *c)
|
||||
{
|
||||
Clock *clock = (Clock *)obj;
|
||||
Panel *panel = (Panel *)clock->area.panel;
|
||||
draw_text_area(&clock->area,
|
||||
c,
|
||||
buf_time,
|
||||
@@ -314,7 +317,8 @@ void draw_clock(void *obj, cairo_t *c)
|
||||
time2_font_desc,
|
||||
clock->time1_posy,
|
||||
clock->time2_posy,
|
||||
&clock->font);
|
||||
&clock->font,
|
||||
panel->scale);
|
||||
}
|
||||
|
||||
void clock_dump_geometry(void *obj, int indent)
|
||||
|
||||
@@ -244,7 +244,11 @@ void add_entry(char *key, char *value)
|
||||
char *value1 = 0, *value2 = 0, *value3 = 0;
|
||||
|
||||
/* Background and border */
|
||||
if (strcmp(key, "rounded") == 0) {
|
||||
if (strcmp(key, "scale_relative_to_dpi") == 0) {
|
||||
ui_scale_dpi_ref = atof(value);
|
||||
} else if (strcmp(key, "scale_relative_to_screen_height") == 0) {
|
||||
ui_scale_monitor_size_ref = atof(value);
|
||||
} else if (strcmp(key, "rounded") == 0) {
|
||||
// 'rounded' is the first parameter => alloc a new background
|
||||
if (backgrounds->len > 0) {
|
||||
Background *bg = &g_array_index(backgrounds, Background, backgrounds->len - 1);
|
||||
@@ -1012,6 +1016,8 @@ void add_entry(char *key, char *value)
|
||||
taskbar_sort_method = TASKBAR_SORT_CENTER;
|
||||
} else if (strcmp(value, "title") == 0) {
|
||||
taskbar_sort_method = TASKBAR_SORT_TITLE;
|
||||
} else if (strcmp(value, "application") == 0) {
|
||||
taskbar_sort_method = TASKBAR_SORT_APPLICATION;
|
||||
} else if (strcmp(value, "lru") == 0) {
|
||||
taskbar_sort_method = TASKBAR_SORT_LRU;
|
||||
} else if (strcmp(value, "mru") == 0) {
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
#define MAX_TOOLTIP_LEN 4096
|
||||
|
||||
bool debug_executors = false;
|
||||
|
||||
void execp_timer_callback(void *arg);
|
||||
char *execp_get_tooltip(void *obj);
|
||||
void execp_init_fonts();
|
||||
@@ -304,7 +306,6 @@ void execp_compute_icon_text_geometry(Execp *execp,
|
||||
int *icon_w,
|
||||
int *icon_h,
|
||||
gboolean *text_next_line,
|
||||
int *txt_height_ink,
|
||||
int *txt_height,
|
||||
int *txt_width,
|
||||
int *new_size,
|
||||
@@ -312,9 +313,9 @@ void execp_compute_icon_text_geometry(Execp *execp,
|
||||
{
|
||||
Panel *panel = (Panel *)execp->area.panel;
|
||||
Area *area = &execp->area;
|
||||
*horiz_padding = (panel_horizontal ? area->paddingxlr : area->paddingy);
|
||||
*vert_padding = (panel_horizontal ? area->paddingy : area->paddingxlr);
|
||||
*interior_padding = area->paddingx;
|
||||
*horiz_padding = (panel_horizontal ? area->paddingxlr : area->paddingy) * panel->scale;
|
||||
*vert_padding = (panel_horizontal ? area->paddingy : area->paddingxlr) * panel->scale;
|
||||
*interior_padding = area->paddingx * panel->scale;
|
||||
|
||||
if (reload_icon(execp)) {
|
||||
if (execp->backend->icon) {
|
||||
@@ -333,7 +334,7 @@ void execp_compute_icon_text_geometry(Execp *execp,
|
||||
int available_w, available_h;
|
||||
if (panel_horizontal) {
|
||||
available_w = panel->area.width;
|
||||
available_h = area->height - 2 * area->paddingy - left_right_border_width(area);
|
||||
available_h = area->height - 2 * *vert_padding - left_right_border_width(area);
|
||||
} else {
|
||||
available_w = !text_next_line
|
||||
? area->width - *icon_w - (*icon_w ? *interior_padding : 0) - 2 * *horiz_padding -
|
||||
@@ -342,7 +343,6 @@ void execp_compute_icon_text_geometry(Execp *execp,
|
||||
available_h = panel->area.height;
|
||||
}
|
||||
get_text_size2(execp->backend->font_desc,
|
||||
txt_height_ink,
|
||||
txt_height,
|
||||
txt_width,
|
||||
available_h,
|
||||
@@ -351,7 +351,9 @@ void execp_compute_icon_text_geometry(Execp *execp,
|
||||
strlen(execp->backend->text),
|
||||
PANGO_WRAP_WORD_CHAR,
|
||||
PANGO_ELLIPSIZE_NONE,
|
||||
execp->backend->has_markup);
|
||||
execp->backend->centered ? PANGO_ALIGN_CENTER : PANGO_ALIGN_LEFT,
|
||||
execp->backend->has_markup,
|
||||
panel->scale);
|
||||
|
||||
*resized = FALSE;
|
||||
if (panel_horizontal) {
|
||||
@@ -371,7 +373,11 @@ void execp_compute_icon_text_geometry(Execp *execp,
|
||||
*new_size = *txt_height + 2 * *vert_padding + top_bottom_border_width(area);
|
||||
*new_size = MAX(*new_size, *icon_h + 2 * *vert_padding + top_bottom_border_width(area));
|
||||
} else {
|
||||
*new_size = *icon_h + *interior_padding + *txt_height + 2 * *vert_padding + top_bottom_border_width(area);
|
||||
if (strlen(execp->backend->text)) {
|
||||
*new_size = *icon_h + *interior_padding + *txt_height + 2 * *vert_padding + top_bottom_border_width(area);
|
||||
} else {
|
||||
*new_size = *icon_h + 2 * *vert_padding + top_bottom_border_width(area);
|
||||
}
|
||||
}
|
||||
if (*new_size != area->height) {
|
||||
*resized = TRUE;
|
||||
@@ -385,7 +391,7 @@ int execp_compute_desired_size(void *obj)
|
||||
int horiz_padding, vert_padding, interior_padding;
|
||||
int icon_w, icon_h;
|
||||
gboolean text_next_line;
|
||||
int txt_height_ink, txt_height, txt_width;
|
||||
int txt_height, txt_width;
|
||||
int new_size;
|
||||
gboolean resized;
|
||||
execp_compute_icon_text_geometry(execp,
|
||||
@@ -395,7 +401,6 @@ int execp_compute_desired_size(void *obj)
|
||||
&icon_w,
|
||||
&icon_h,
|
||||
&text_next_line,
|
||||
&txt_height_ink,
|
||||
&txt_height,
|
||||
&txt_width,
|
||||
&new_size,
|
||||
@@ -410,7 +415,7 @@ gboolean resize_execp(void *obj)
|
||||
int horiz_padding, vert_padding, interior_padding;
|
||||
int icon_w, icon_h;
|
||||
gboolean text_next_line;
|
||||
int txt_height_ink, txt_height, txt_width;
|
||||
int txt_height, txt_width;
|
||||
int new_size;
|
||||
gboolean resized;
|
||||
execp_compute_icon_text_geometry(execp,
|
||||
@@ -420,7 +425,6 @@ gboolean resize_execp(void *obj)
|
||||
&icon_w,
|
||||
&icon_h,
|
||||
&text_next_line,
|
||||
&txt_height_ink,
|
||||
&txt_height,
|
||||
&txt_width,
|
||||
&new_size,
|
||||
@@ -441,10 +445,17 @@ gboolean resize_execp(void *obj)
|
||||
execp->frontend->texty = (execp->area.height - txt_height) / 2;
|
||||
execp->frontend->textx = execp->frontend->iconx + icon_w + interior_padding;
|
||||
} else {
|
||||
execp->frontend->icony = (execp->area.height - icon_h - interior_padding - txt_height) / 2;
|
||||
execp->frontend->iconx = (execp->area.width - icon_w) / 2;
|
||||
execp->frontend->texty = execp->frontend->icony + icon_h + interior_padding;
|
||||
execp->frontend->textx = (execp->area.width - txt_width) / 2;
|
||||
if (strlen(execp->backend->text)) {
|
||||
execp->frontend->icony = (execp->area.height - icon_h - interior_padding - txt_height) / 2;
|
||||
execp->frontend->iconx = (execp->area.width - icon_w) / 2;
|
||||
execp->frontend->texty = execp->frontend->icony + icon_h + interior_padding;
|
||||
execp->frontend->textx = (execp->area.width - txt_width) / 2;
|
||||
} else {
|
||||
execp->frontend->icony = (execp->area.height - icon_h) / 2;
|
||||
execp->frontend->iconx = (execp->area.width - icon_w) / 2;
|
||||
execp->frontend->texty = execp->frontend->icony + icon_h + interior_padding;
|
||||
execp->frontend->textx = (execp->area.width - txt_width) / 2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
execp->frontend->texty = (execp->area.height - txt_height) / 2;
|
||||
@@ -458,10 +469,17 @@ gboolean resize_execp(void *obj)
|
||||
execp->frontend->texty = (execp->area.height - txt_height) / 2;
|
||||
execp->frontend->textx = execp->frontend->iconx + icon_w + interior_padding;
|
||||
} else {
|
||||
execp->frontend->icony = (execp->area.height - icon_h - interior_padding - txt_height) / 2;
|
||||
execp->frontend->iconx = left_border_width(&execp->area) + horiz_padding;
|
||||
execp->frontend->texty = execp->frontend->icony + icon_h + interior_padding;
|
||||
execp->frontend->textx = execp->frontend->iconx;
|
||||
if (strlen(execp->backend->text)) {
|
||||
execp->frontend->icony = (execp->area.height - icon_h - interior_padding - txt_height) / 2;
|
||||
execp->frontend->iconx = left_border_width(&execp->area) + horiz_padding;
|
||||
execp->frontend->texty = execp->frontend->icony + icon_h + interior_padding;
|
||||
execp->frontend->textx = execp->frontend->iconx;
|
||||
} else {
|
||||
execp->frontend->icony = (execp->area.height - icon_h) / 2;
|
||||
execp->frontend->iconx = left_border_width(&execp->area) + horiz_padding;
|
||||
execp->frontend->texty = execp->frontend->icony + icon_h + interior_padding;
|
||||
execp->frontend->textx = execp->frontend->iconx;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
execp->frontend->texty = (execp->area.height - txt_height) / 2;
|
||||
@@ -473,10 +491,27 @@ gboolean resize_execp(void *obj)
|
||||
return resized;
|
||||
}
|
||||
|
||||
PangoLayout *create_execp_text_layout(Execp *execp, PangoContext *context)
|
||||
{
|
||||
PangoLayout *layout = pango_layout_new(context);
|
||||
pango_layout_set_font_description(layout, execp->backend->font_desc);
|
||||
pango_layout_set_width(layout, (execp->frontend->textw + TINT2_PANGO_SLACK) * PANGO_SCALE);
|
||||
pango_layout_set_height(layout, (execp->frontend->texth + TINT2_PANGO_SLACK) * PANGO_SCALE);
|
||||
pango_layout_set_alignment(layout, execp->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);
|
||||
return layout;
|
||||
}
|
||||
|
||||
void draw_execp(void *obj, cairo_t *c)
|
||||
{
|
||||
Execp *execp = (Execp *)obj;
|
||||
PangoLayout *layout = pango_cairo_create_layout(c);
|
||||
Panel *panel = (Panel *)execp->area.panel;
|
||||
|
||||
PangoContext *context = pango_cairo_create_context(c);
|
||||
pango_cairo_context_set_resolution(context, 96 * panel->scale);
|
||||
PangoLayout *layout = create_execp_text_layout(execp, context);
|
||||
PangoLayout *shadow_layout = NULL;
|
||||
|
||||
if (execp->backend->has_icon && execp->backend->icon) {
|
||||
imlib_context_set_image(execp->backend->icon);
|
||||
@@ -485,15 +520,18 @@ void draw_execp(void *obj, cairo_t *c)
|
||||
}
|
||||
|
||||
// draw layout
|
||||
pango_layout_set_font_description(layout, execp->backend->font_desc);
|
||||
pango_layout_set_width(layout, (execp->frontend->textw + 1) * PANGO_SCALE);
|
||||
pango_layout_set_alignment(layout, execp->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);
|
||||
if (!execp->backend->has_markup)
|
||||
if (!execp->backend->has_markup) {
|
||||
pango_layout_set_text(layout, execp->backend->text, strlen(execp->backend->text));
|
||||
else
|
||||
} else {
|
||||
pango_layout_set_markup(layout, execp->backend->text, strlen(execp->backend->text));
|
||||
if (panel_config.font_shadow) {
|
||||
shadow_layout = create_execp_text_layout(execp, context);
|
||||
if (!layout_set_markup_strip_colors(shadow_layout, execp->backend->text)) {
|
||||
g_object_unref(shadow_layout);
|
||||
shadow_layout = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pango_cairo_update_layout(c, layout);
|
||||
draw_text(layout,
|
||||
@@ -501,9 +539,10 @@ void draw_execp(void *obj, cairo_t *c)
|
||||
execp->frontend->textx,
|
||||
execp->frontend->texty,
|
||||
&execp->backend->font_color,
|
||||
panel_config.font_shadow);
|
||||
shadow_layout);
|
||||
|
||||
g_object_unref(layout);
|
||||
g_object_unref(context);
|
||||
}
|
||||
|
||||
void execp_dump_geometry(void *obj, int indent)
|
||||
@@ -525,12 +564,13 @@ void execp_dump_geometry(void *obj, int indent)
|
||||
imlib_context_set_image(tmp);
|
||||
}
|
||||
fprintf(stderr,
|
||||
"tint2: %*sText: x = %d, y = %d, w = %d, align = %s, text = %s\n",
|
||||
"tint2: %*sText: x = %d, y = %d, w = %d, h = %d, align = %s, text = %s\n",
|
||||
indent,
|
||||
"",
|
||||
execp->frontend->textx,
|
||||
execp->frontend->texty,
|
||||
execp->frontend->textw,
|
||||
execp->frontend->texth,
|
||||
execp->backend->centered ? "center" : "left",
|
||||
execp->backend->text);
|
||||
}
|
||||
@@ -631,7 +671,8 @@ void execp_timer_callback(void *arg)
|
||||
close(pipe_fd_stderr[0]);
|
||||
return;
|
||||
} else if (child == 0) {
|
||||
fprintf(stderr, "tint2: Executing: %s\n", execp->backend->command);
|
||||
if (debug_executors)
|
||||
fprintf(stderr, "tint2: Executing: %s\n", execp->backend->command);
|
||||
// We are in the child
|
||||
close(pipe_fd_stdout[0]);
|
||||
dup2(pipe_fd_stdout[1], 1); // 1 is stdout
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include "common.h"
|
||||
#include "timer.h"
|
||||
|
||||
extern bool debug_executors;
|
||||
|
||||
// Architecture:
|
||||
// Panel panel_config contains an array of Execp, each storing all config options and all the state variables.
|
||||
// Only these run commands.
|
||||
|
||||
@@ -65,14 +65,14 @@ void cleanup_freespace(Panel *panel)
|
||||
panel->freespace_list = NULL;
|
||||
}
|
||||
|
||||
int freespace_get_max_size(Panel *p)
|
||||
int freespace_get_max_size(Panel *panel)
|
||||
{
|
||||
if (panel_shrink)
|
||||
return 0;
|
||||
// Get space used by every element except the freespace
|
||||
int size = 0;
|
||||
int spacers = 0;
|
||||
for (GList *walk = p->area.children; walk; walk = g_list_next(walk)) {
|
||||
for (GList *walk = panel->area.children; walk; walk = g_list_next(walk)) {
|
||||
Area *a = (Area *)walk->data;
|
||||
|
||||
if (!a->on_screen)
|
||||
@@ -83,15 +83,15 @@ int freespace_get_max_size(Panel *p)
|
||||
}
|
||||
|
||||
if (panel_horizontal)
|
||||
size += a->width + p->area.paddingx;
|
||||
size += a->width + panel->area.paddingx * panel->scale;
|
||||
else
|
||||
size += a->height + p->area.paddingy;
|
||||
size += a->height + panel->area.paddingy * panel->scale;
|
||||
}
|
||||
|
||||
if (panel_horizontal)
|
||||
size = p->area.width - size - left_right_border_width(&p->area) - p->area.paddingxlr;
|
||||
size = panel->area.width - size - left_right_border_width(&panel->area) - panel->area.paddingxlr * panel->scale;
|
||||
else
|
||||
size = p->area.height - size - top_bottom_border_width(&p->area) - p->area.paddingxlr;
|
||||
size = panel->area.height - size - top_bottom_border_width(&panel->area) - panel->area.paddingxlr * panel->scale;
|
||||
|
||||
return size / spacers;
|
||||
}
|
||||
|
||||
@@ -106,6 +106,7 @@ void handle_env_vars()
|
||||
debug_dnd = getenv("DEBUG_DND") != NULL;
|
||||
debug_thumbnails = getenv("DEBUG_THUMBNAILS") != NULL;
|
||||
debug_timers = getenv("DEBUG_TIMERS") != NULL;
|
||||
debug_executors = getenv("DEBUG_EXECUTORS") != NULL;
|
||||
if (debug_fps) {
|
||||
init_fps_distribution();
|
||||
char *s = getenv("TRACING_FPS_THRESHOLD");
|
||||
@@ -208,8 +209,8 @@ void init_X11_pre_config()
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
server.x11_fd = ConnectionNumber(server.display);
|
||||
XSetErrorHandler((XErrorHandler)server_catch_error);
|
||||
XSetIOErrorHandler((XIOErrorHandler)x11_io_error);
|
||||
XSetErrorHandler(server_catch_error);
|
||||
XSetIOErrorHandler(x11_io_error);
|
||||
server_init_atoms();
|
||||
server.screen = DefaultScreen(server.display);
|
||||
server.root_win = RootWindow(server.display, server.screen);
|
||||
@@ -246,8 +247,9 @@ void init(int argc, char **argv)
|
||||
if (!config_read()) {
|
||||
fprintf(stderr, "tint2: Could not read config file.\n");
|
||||
print_usage();
|
||||
warnings_for_timers = false;
|
||||
cleanup();
|
||||
return;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
init_post_config();
|
||||
|
||||
@@ -112,7 +112,7 @@ void init_launcher_panel(void *p)
|
||||
return;
|
||||
|
||||
// This will be recomputed on resize, we just initialize to a non-zero value
|
||||
launcher->icon_size = launcher_max_icon_size > 0 ? launcher_max_icon_size : 24;
|
||||
launcher->icon_size = launcher_max_icon_size > 0 ? launcher_max_icon_size * panel->scale : 24;
|
||||
|
||||
launcher->area.on_screen = TRUE;
|
||||
schedule_panel_redraw();
|
||||
@@ -174,11 +174,12 @@ void cleanup_launcher_theme(Launcher *launcher)
|
||||
|
||||
int launcher_compute_icon_size(Launcher *launcher)
|
||||
{
|
||||
Panel *panel = launcher->area.panel;
|
||||
int icon_size = panel_horizontal ? launcher->area.height : launcher->area.width;
|
||||
icon_size = icon_size - MAX(left_right_border_width(&launcher->area), top_bottom_border_width(&launcher->area)) -
|
||||
(2 * launcher->area.paddingy);
|
||||
if (launcher_max_icon_size > 0 && icon_size > launcher_max_icon_size)
|
||||
icon_size = launcher_max_icon_size;
|
||||
(2 * launcher->area.paddingy * panel->scale);
|
||||
if (launcher_max_icon_size)
|
||||
icon_size = MIN(icon_size, launcher_max_icon_size * panel->scale);
|
||||
return icon_size;
|
||||
}
|
||||
|
||||
@@ -189,6 +190,7 @@ void launcher_compute_geometry(Launcher *launcher,
|
||||
int *icons_per_row,
|
||||
int *margin)
|
||||
{
|
||||
Panel *panel = (Panel*)launcher->area.panel;
|
||||
int count = 0;
|
||||
for (GSList *l = launcher->list_icons; l; l = l->next) {
|
||||
LauncherIcon *launcherIcon = (LauncherIcon *)l->data;
|
||||
@@ -204,25 +206,25 @@ void launcher_compute_geometry(Launcher *launcher,
|
||||
if (!count) {
|
||||
*size = 0;
|
||||
} else {
|
||||
int height = launcher->area.height - top_bottom_border_width(&launcher->area) - 2 * launcher->area.paddingy;
|
||||
int height = launcher->area.height - top_bottom_border_width(&launcher->area) - 2 * launcher->area.paddingy * panel->scale;
|
||||
// here icons_per_column always higher than 0
|
||||
*icons_per_column = (height + launcher->area.paddingx) / (*icon_size + launcher->area.paddingx);
|
||||
*margin = height - (*icons_per_column - 1) * (*icon_size + launcher->area.paddingx) - *icon_size;
|
||||
*icons_per_column = (height + launcher->area.paddingx * panel->scale) / (*icon_size + launcher->area.paddingx * panel->scale);
|
||||
*margin = height - (*icons_per_column - 1) * (*icon_size + launcher->area.paddingx * panel->scale) - *icon_size;
|
||||
*icons_per_row = count / *icons_per_column + (count % *icons_per_column != 0);
|
||||
*size = left_right_border_width(&launcher->area) + 2 * launcher->area.paddingxlr +
|
||||
(*icon_size * *icons_per_row) + ((*icons_per_row - 1) * launcher->area.paddingx);
|
||||
*size = left_right_border_width(&launcher->area) + 2 * launcher->area.paddingxlr * panel->scale +
|
||||
(*icon_size * *icons_per_row) + ((*icons_per_row - 1) * launcher->area.paddingx * panel->scale);
|
||||
}
|
||||
} else {
|
||||
if (!count) {
|
||||
*size = 0;
|
||||
} else {
|
||||
int width = launcher->area.width - top_bottom_border_width(&launcher->area) - 2 * launcher->area.paddingy;
|
||||
int width = launcher->area.width - top_bottom_border_width(&launcher->area) - 2 * launcher->area.paddingy * panel->scale;
|
||||
// here icons_per_row always higher than 0
|
||||
*icons_per_row = (width + launcher->area.paddingx) / (*icon_size + launcher->area.paddingx);
|
||||
*margin = width - (*icons_per_row - 1) * (*icon_size + launcher->area.paddingx) - *icon_size;
|
||||
*icons_per_row = (width + launcher->area.paddingx * panel->scale) / (*icon_size + launcher->area.paddingx * panel->scale);
|
||||
*margin = width - (*icons_per_row - 1) * (*icon_size + launcher->area.paddingx * panel->scale) - *icon_size;
|
||||
*icons_per_column = count / *icons_per_row + (count % *icons_per_row != 0);
|
||||
*size = top_bottom_border_width(&launcher->area) + 2 * launcher->area.paddingxlr +
|
||||
(*icon_size * *icons_per_column) + ((*icons_per_column - 1) * launcher->area.paddingx);
|
||||
*size = top_bottom_border_width(&launcher->area) + 2 * launcher->area.paddingxlr * panel->scale +
|
||||
(*icon_size * *icons_per_column) + ((*icons_per_column - 1) * launcher->area.paddingx * panel->scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -239,6 +241,7 @@ int launcher_compute_desired_size(void *obj)
|
||||
gboolean resize_launcher(void *obj)
|
||||
{
|
||||
Launcher *launcher = (Launcher *)obj;
|
||||
Panel *panel = (Panel*)launcher->area.panel;
|
||||
|
||||
int size, icons_per_column, icons_per_row, margin;
|
||||
launcher_compute_geometry(launcher, &size, &launcher->icon_size, &icons_per_column, &icons_per_row, &margin);
|
||||
@@ -281,11 +284,11 @@ gboolean resize_launcher(void *obj)
|
||||
int posx, posy;
|
||||
int start;
|
||||
if (panel_horizontal) {
|
||||
posy = start = top_border_width(&launcher->area) + launcher->area.paddingy + margin / 2;
|
||||
posx = left_border_width(&launcher->area) + launcher->area.paddingxlr;
|
||||
posy = start = top_border_width(&launcher->area) + launcher->area.paddingy * panel->scale + margin / 2;
|
||||
posx = left_border_width(&launcher->area) + launcher->area.paddingxlr * panel->scale;
|
||||
} else {
|
||||
posx = start = left_border_width(&launcher->area) + launcher->area.paddingy + margin / 2;
|
||||
posy = top_border_width(&launcher->area) + launcher->area.paddingxlr;
|
||||
posx = start = left_border_width(&launcher->area) + launcher->area.paddingy * panel->scale + margin / 2;
|
||||
posy = top_border_width(&launcher->area) + launcher->area.paddingxlr * panel->scale;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
@@ -300,17 +303,17 @@ gboolean resize_launcher(void *obj)
|
||||
// fprintf(stderr, "tint2: launcher %d : %d,%d\n", i, posx, posy);
|
||||
if (panel_horizontal) {
|
||||
if (i % icons_per_column) {
|
||||
posy += launcher->icon_size + launcher->area.paddingx;
|
||||
posy += launcher->icon_size + launcher->area.paddingx * panel->scale;
|
||||
} else {
|
||||
posy = start;
|
||||
posx += (launcher->icon_size + launcher->area.paddingx);
|
||||
posx += (launcher->icon_size + launcher->area.paddingx * panel->scale);
|
||||
}
|
||||
} else {
|
||||
if (i % icons_per_row) {
|
||||
posx += launcher->icon_size + launcher->area.paddingx;
|
||||
posx += launcher->icon_size + launcher->area.paddingx * panel->scale;
|
||||
} else {
|
||||
posx = start;
|
||||
posy += (launcher->icon_size + launcher->area.paddingx);
|
||||
posy += (launcher->icon_size + launcher->area.paddingx * panel->scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -396,7 +399,12 @@ void launcher_icon_dump_geometry(void *obj, int indent)
|
||||
Imlib_Image scale_icon(Imlib_Image original, int icon_size)
|
||||
{
|
||||
Imlib_Image icon_scaled;
|
||||
if (original) {
|
||||
if (!icon_size) {
|
||||
icon_scaled = imlib_create_image(1, 1);
|
||||
imlib_context_set_image(icon_scaled);
|
||||
imlib_context_set_color(255, 255, 255, 255);
|
||||
imlib_image_fill_rectangle(0, 0, icon_size, icon_size);
|
||||
} else if (original) {
|
||||
imlib_context_set_image(original);
|
||||
icon_scaled = imlib_create_cropped_scaled_image(0,
|
||||
0,
|
||||
|
||||
43
src/panel.c
43
src/panel.c
@@ -79,11 +79,16 @@ int num_panels;
|
||||
GArray *backgrounds;
|
||||
GArray *gradients;
|
||||
|
||||
double ui_scale_dpi_ref;
|
||||
double ui_scale_monitor_size_ref;
|
||||
|
||||
Imlib_Image default_icon;
|
||||
char *default_font = NULL;
|
||||
|
||||
void default_panel()
|
||||
{
|
||||
ui_scale_dpi_ref = 0;
|
||||
ui_scale_monitor_size_ref = 0;
|
||||
panels = NULL;
|
||||
num_panels = 0;
|
||||
default_icon = NULL;
|
||||
@@ -218,6 +223,17 @@ void init_panel()
|
||||
|
||||
if (panel_config.monitor < 0)
|
||||
p->monitor = i;
|
||||
if (ui_scale_dpi_ref > 0 && server.monitors[p->monitor].dpi > 0)
|
||||
p->scale = server.monitors[p->monitor].dpi / ui_scale_dpi_ref;
|
||||
else
|
||||
p->scale = 1;
|
||||
if (ui_scale_monitor_size_ref > 0)
|
||||
p->scale *= server.monitors[p->monitor].height / ui_scale_monitor_size_ref;
|
||||
if (p->scale > 8 || p->scale < 1./8) {
|
||||
fprintf(stderr, RED "tint2: panel %d having scale %g outside bounds, resetting to 1.0" RESET "\n", i + 1, p->scale);
|
||||
p->scale = 1;
|
||||
}
|
||||
fprintf(stderr, BLUE "tint2: panel %d uses scale %g " RESET "\n", i + 1, p->scale);
|
||||
if (!p->area.bg)
|
||||
p->area.bg = &g_array_index(backgrounds, Background, 0);
|
||||
p->area.parent = p;
|
||||
@@ -355,6 +371,19 @@ void panel_compute_size(Panel *panel)
|
||||
}
|
||||
}
|
||||
|
||||
if (!panel->fractional_width) {
|
||||
if (panel_horizontal)
|
||||
panel->area.width *= panel->scale;
|
||||
else
|
||||
panel->area.height *= panel->scale;
|
||||
}
|
||||
if (!panel->fractional_height) {
|
||||
if (panel_horizontal)
|
||||
panel->area.height *= panel->scale;
|
||||
else
|
||||
panel->area.width *= panel->scale;
|
||||
}
|
||||
|
||||
if (panel->area.width + panel->marginx > server.monitors[panel->monitor].width)
|
||||
panel->area.width = server.monitors[panel->monitor].width - panel->marginx;
|
||||
if (panel->area.height + panel->marginy > server.monitors[panel->monitor].height)
|
||||
@@ -449,9 +478,9 @@ gboolean resize_panel(void *obj)
|
||||
if (!taskbar->area.on_screen)
|
||||
continue;
|
||||
if (panel_horizontal)
|
||||
taskbar->area.width = 2 * taskbar->area.paddingxlr;
|
||||
taskbar->area.width = 2 * taskbar->area.paddingxlr * panel->scale;
|
||||
else
|
||||
taskbar->area.height = 2 * taskbar->area.paddingxlr;
|
||||
taskbar->area.height = 2 * taskbar->area.paddingxlr * panel->scale;
|
||||
if (taskbarname_enabled && taskbar->area.children) {
|
||||
Area *name = (Area *)taskbar->area.children->data;
|
||||
if (name->on_screen) {
|
||||
@@ -468,9 +497,9 @@ gboolean resize_panel(void *obj)
|
||||
continue;
|
||||
if (!first_child) {
|
||||
if (panel_horizontal)
|
||||
taskbar->area.width += taskbar->area.paddingx;
|
||||
taskbar->area.width += taskbar->area.paddingx * panel->scale;
|
||||
else
|
||||
taskbar->area.height += taskbar->area.paddingy;
|
||||
taskbar->area.height += taskbar->area.paddingy * panel->scale;
|
||||
}
|
||||
first_child = FALSE;
|
||||
}
|
||||
@@ -528,6 +557,8 @@ gboolean resize_panel(void *obj)
|
||||
}
|
||||
} else if (taskbar_alignment == ALIGN_CENTER) {
|
||||
slack /= 2;
|
||||
Taskbar *left_taskbar = NULL;
|
||||
Taskbar *right_taskbar = NULL;
|
||||
for (int i = 0; i < panel->num_desktops; i++) {
|
||||
Taskbar *taskbar = &panel->taskbar[i];
|
||||
if (!taskbar->area.on_screen)
|
||||
@@ -537,6 +568,7 @@ gboolean resize_panel(void *obj)
|
||||
else
|
||||
taskbar->area.height += slack;
|
||||
taskbar->area.alignment = ALIGN_RIGHT;
|
||||
left_taskbar = taskbar;
|
||||
break;
|
||||
}
|
||||
for (int i = panel->num_desktops - 1; i >= 0; i--) {
|
||||
@@ -548,8 +580,11 @@ gboolean resize_panel(void *obj)
|
||||
else
|
||||
taskbar->area.height += slack;
|
||||
taskbar->area.alignment = ALIGN_LEFT;
|
||||
right_taskbar = taskbar;
|
||||
break;
|
||||
}
|
||||
if (left_taskbar == right_taskbar)
|
||||
left_taskbar->area.alignment = ALIGN_CENTER;
|
||||
}
|
||||
} else {
|
||||
// No tasks => expand the first visible taskbar
|
||||
|
||||
@@ -95,6 +95,8 @@ extern gboolean debug_fps;
|
||||
extern double tracing_fps_threshold;
|
||||
extern gboolean debug_frames;
|
||||
extern gboolean debug_thumbnails;
|
||||
extern double ui_scale_dpi_ref;
|
||||
extern double ui_scale_monitor_size_ref;
|
||||
|
||||
typedef struct Panel {
|
||||
Area area;
|
||||
@@ -117,6 +119,7 @@ typedef struct Panel {
|
||||
int mouse_pressed_alpha;
|
||||
int mouse_pressed_saturation;
|
||||
int mouse_pressed_brightness;
|
||||
double scale;
|
||||
|
||||
// Per-panel parameters and states for Taskbar and Task
|
||||
GlobalTaskbar g_taskbar;
|
||||
|
||||
@@ -115,31 +115,33 @@ void cleanup_separator()
|
||||
int separator_compute_desired_size(void *obj)
|
||||
{
|
||||
Separator *separator = (Separator *)obj;
|
||||
Panel *panel = (Panel*)separator->area.panel;
|
||||
if (!separator->area.on_screen)
|
||||
return 0;
|
||||
|
||||
if (panel_horizontal)
|
||||
return separator->thickness + 2 * separator->area.paddingxlr + left_right_border_width(&separator->area);
|
||||
return separator->thickness + 2 * separator->area.paddingxlr * panel->scale + left_right_border_width(&separator->area);
|
||||
else
|
||||
return separator->thickness + 2 * separator->area.paddingxlr + top_bottom_border_width(&separator->area);
|
||||
return separator->thickness + 2 * separator->area.paddingxlr * panel->scale + top_bottom_border_width(&separator->area);
|
||||
}
|
||||
|
||||
gboolean resize_separator(void *obj)
|
||||
{
|
||||
Separator *separator = (Separator *)obj;
|
||||
Panel *panel = (Panel*)separator->area.panel;
|
||||
if (!separator->area.on_screen)
|
||||
return FALSE;
|
||||
|
||||
if (panel_horizontal) {
|
||||
separator->area.width =
|
||||
separator->thickness + 2 * separator->area.paddingxlr + left_right_border_width(&separator->area);
|
||||
separator->thickness + 2 * separator->area.paddingxlr * panel->scale + left_right_border_width(&separator->area);
|
||||
separator->length =
|
||||
separator->area.height - 2 * separator->area.paddingy - top_bottom_border_width(&separator->area);
|
||||
separator->area.height - 2 * separator->area.paddingy * panel->scale - top_bottom_border_width(&separator->area);
|
||||
} else {
|
||||
separator->area.height =
|
||||
separator->thickness + 2 * separator->area.paddingxlr + top_bottom_border_width(&separator->area);
|
||||
separator->thickness + 2 * separator->area.paddingxlr * panel->scale + top_bottom_border_width(&separator->area);
|
||||
separator->length =
|
||||
separator->area.width - 2 * separator->area.paddingy - left_right_border_width(&separator->area);
|
||||
separator->area.width - 2 * separator->area.paddingy * panel->scale - left_right_border_width(&separator->area);
|
||||
}
|
||||
|
||||
schedule_redraw(&separator->area);
|
||||
|
||||
@@ -141,11 +141,12 @@ void init_systray_panel(void *p)
|
||||
|
||||
void systray_compute_geometry(int *size)
|
||||
{
|
||||
Panel *panel = (Panel*)systray.area.panel;
|
||||
systray.icon_size = panel_horizontal ? systray.area.height : systray.area.width;
|
||||
systray.icon_size -=
|
||||
MAX(left_right_border_width(&systray.area), top_bottom_border_width(&systray.area)) + 2 * systray.area.paddingy;
|
||||
MAX(left_right_border_width(&systray.area), top_bottom_border_width(&systray.area)) + 2 * systray.area.paddingy * panel->scale;
|
||||
if (systray_max_icon_size > 0)
|
||||
systray.icon_size = MIN(systray.icon_size, systray_max_icon_size);
|
||||
systray.icon_size = MIN(systray.icon_size, systray_max_icon_size * panel->scale);
|
||||
|
||||
int count = 0;
|
||||
for (GSList *l = systray.list_icons; l; l = l->next) {
|
||||
@@ -153,24 +154,24 @@ void systray_compute_geometry(int *size)
|
||||
}
|
||||
|
||||
if (panel_horizontal) {
|
||||
int height = systray.area.height - top_bottom_border_width(&systray.area) - 2 * systray.area.paddingy;
|
||||
int height = systray.area.height - top_bottom_border_width(&systray.area) - 2 * systray.area.paddingy * panel->scale;
|
||||
// here icons_per_column always higher than 0
|
||||
systray.icons_per_column = (height + systray.area.paddingx) / (systray.icon_size + systray.area.paddingx);
|
||||
systray.icons_per_column = (height + systray.area.paddingx * panel->scale) / (systray.icon_size + systray.area.paddingx * panel->scale);
|
||||
systray.margin =
|
||||
height - (systray.icons_per_column - 1) * (systray.icon_size + systray.area.paddingx) - systray.icon_size;
|
||||
height - (systray.icons_per_column - 1) * (systray.icon_size + systray.area.paddingx * panel->scale) - systray.icon_size;
|
||||
systray.icons_per_row = count / systray.icons_per_column + (count % systray.icons_per_column != 0);
|
||||
*size = left_right_border_width(&systray.area) + 2 * systray.area.paddingxlr +
|
||||
(systray.icon_size * systray.icons_per_row) + ((systray.icons_per_row - 1) * systray.area.paddingx);
|
||||
*size = left_right_border_width(&systray.area) + 2 * systray.area.paddingxlr * panel->scale +
|
||||
(systray.icon_size * systray.icons_per_row) + ((systray.icons_per_row - 1) * systray.area.paddingx * panel->scale);
|
||||
} else {
|
||||
int width = systray.area.width - left_right_border_width(&systray.area) - 2 * systray.area.paddingy;
|
||||
int width = systray.area.width - left_right_border_width(&systray.area) - 2 * systray.area.paddingy * panel->scale;
|
||||
// here icons_per_row always higher than 0
|
||||
systray.icons_per_row = (width + systray.area.paddingx) / (systray.icon_size + systray.area.paddingx);
|
||||
systray.icons_per_row = (width + systray.area.paddingx * panel->scale) / (systray.icon_size + systray.area.paddingx * panel->scale);
|
||||
systray.margin =
|
||||
width - (systray.icons_per_row - 1) * (systray.icon_size + systray.area.paddingx) - systray.icon_size;
|
||||
width - (systray.icons_per_row - 1) * (systray.icon_size + systray.area.paddingx * panel->scale) - systray.icon_size;
|
||||
systray.icons_per_column = count / systray.icons_per_row + (count % systray.icons_per_row != 0);
|
||||
*size = top_bottom_border_width(&systray.area) + (2 * systray.area.paddingxlr) +
|
||||
*size = top_bottom_border_width(&systray.area) + (2 * systray.area.paddingxlr * panel->scale) +
|
||||
(systray.icon_size * systray.icons_per_column) +
|
||||
((systray.icons_per_column - 1) * systray.area.paddingx);
|
||||
((systray.icons_per_column - 1) * systray.area.paddingx * panel->scale);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,13 +282,13 @@ void on_change_systray(void *obj)
|
||||
int posx, posy;
|
||||
int start;
|
||||
if (panel_horizontal) {
|
||||
posy = start = top_border_width(&panel->area) + panel->area.paddingy + top_border_width(&systray.area) +
|
||||
systray.area.paddingy + systray.margin / 2;
|
||||
posx = systray.area.posx + left_border_width(&systray.area) + systray.area.paddingxlr;
|
||||
posy = start = top_border_width(&panel->area) + panel->area.paddingy * panel->scale + top_border_width(&systray.area) +
|
||||
systray.area.paddingy * panel->scale + systray.margin / 2;
|
||||
posx = systray.area.posx + left_border_width(&systray.area) + systray.area.paddingxlr * panel->scale;
|
||||
} else {
|
||||
posx = start = left_border_width(&panel->area) + panel->area.paddingy + left_border_width(&systray.area) +
|
||||
systray.area.paddingy + systray.margin / 2;
|
||||
posy = systray.area.posy + top_border_width(&systray.area) + systray.area.paddingxlr;
|
||||
posx = start = left_border_width(&panel->area) + panel->area.paddingy * panel->scale + left_border_width(&systray.area) +
|
||||
systray.area.paddingy * panel->scale + systray.margin / 2;
|
||||
posy = systray.area.posy + top_border_width(&systray.area) + systray.area.paddingxlr * panel->scale;
|
||||
}
|
||||
|
||||
TrayWindow *traywin;
|
||||
@@ -312,17 +313,17 @@ void on_change_systray(void *obj)
|
||||
traywin->height = systray.icon_size;
|
||||
if (panel_horizontal) {
|
||||
if (i % systray.icons_per_column) {
|
||||
posy += systray.icon_size + systray.area.paddingx;
|
||||
posy += systray.icon_size + systray.area.paddingx * panel->scale;
|
||||
} else {
|
||||
posy = start;
|
||||
posx += (systray.icon_size + systray.area.paddingx);
|
||||
posx += (systray.icon_size + systray.area.paddingx * panel->scale);
|
||||
}
|
||||
} else {
|
||||
if (i % systray.icons_per_row) {
|
||||
posx += systray.icon_size + systray.area.paddingx;
|
||||
posx += systray.icon_size + systray.area.paddingx * panel->scale;
|
||||
} else {
|
||||
posx = start;
|
||||
posy += (systray.icon_size + systray.area.paddingx);
|
||||
posy += (systray.icon_size + systray.area.paddingx * panel->scale);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -107,6 +107,21 @@ Task *add_task(Window win)
|
||||
(int)win,
|
||||
task_template.title ? task_template.title : "null");
|
||||
|
||||
// get application name
|
||||
// use res_class property of WM_CLASS as res_name is easily overridable by user
|
||||
XClassHint *classhint = XAllocClassHint();
|
||||
if (classhint && XGetClassHint(server.display, win, classhint))
|
||||
task_template.application = strdup(classhint->res_class);
|
||||
else
|
||||
task_template.application = strdup("Untitled");
|
||||
if (classhint) {
|
||||
if (classhint->res_name)
|
||||
XFree(classhint->res_name);
|
||||
if (classhint->res_class)
|
||||
XFree(classhint->res_class);
|
||||
XFree(classhint);
|
||||
}
|
||||
|
||||
GPtrArray *task_buttons = g_ptr_array_new();
|
||||
for (int j = 0; j < panels[monitor].num_desktops; j++) {
|
||||
if (task_template.desktop != ALL_DESKTOPS && task_template.desktop != j)
|
||||
@@ -132,6 +147,7 @@ Task *add_task(Window win)
|
||||
task_instance->area.on_screen = always_show_all_desktop_tasks;
|
||||
}
|
||||
task_instance->title = task_template.title;
|
||||
task_instance->application = task_template.application;
|
||||
if (panels[monitor].g_task.tooltip_enabled) {
|
||||
task_instance->area._get_tooltip_text = task_get_tooltip;
|
||||
task_instance->area._get_tooltip_image = task_get_thumbnail;
|
||||
@@ -208,12 +224,14 @@ void remove_task(Task *task)
|
||||
|
||||
Window win = task->win;
|
||||
|
||||
// free title and icon just for the first task
|
||||
// free title, icon and application name just for the first task
|
||||
// even with task_on_all_desktop and with task_on_all_panel
|
||||
if (task->title)
|
||||
free(task->title);
|
||||
if (task->thumbnail)
|
||||
cairo_surface_destroy(task->thumbnail);
|
||||
if (task->application)
|
||||
free(task->application);
|
||||
task_remove_icon(task);
|
||||
|
||||
GPtrArray *task_buttons = g_hash_table_lookup(win_to_task, &win);
|
||||
@@ -381,7 +399,7 @@ void task_update_icon(Task *task)
|
||||
task->icon[k] = adjust_icon(orig_image,
|
||||
panel->g_task.alpha[k],
|
||||
panel->g_task.saturation[k],
|
||||
panel->g_task.brightness[k] != 0);
|
||||
panel->g_task.brightness[k]);
|
||||
if (panel_config.mouse_effects) {
|
||||
task->icon_hover[k] = adjust_icon(task->icon[k],
|
||||
panel_config.mouse_over_alpha,
|
||||
@@ -429,7 +447,7 @@ void draw_task_icon(Task *task, int text_width)
|
||||
else
|
||||
task->_icon_x = (task->area.width - panel->g_task.icon_size1) / 2;
|
||||
} else {
|
||||
task->_icon_x = left_border_width(&task->area) + task->area.paddingxlr;
|
||||
task->_icon_x = left_border_width(&task->area) + task->area.paddingxlr * panel->scale;
|
||||
}
|
||||
|
||||
// Render
|
||||
@@ -459,11 +477,13 @@ void draw_task(void *obj, cairo_t *c)
|
||||
|
||||
task->_text_width = 0;
|
||||
if (panel->g_task.has_text) {
|
||||
PangoLayout *layout = pango_cairo_create_layout(c);
|
||||
PangoContext *context = pango_cairo_create_context(c);
|
||||
pango_cairo_context_set_resolution(context, 96 * panel->scale);
|
||||
PangoLayout *layout = pango_layout_new(context);
|
||||
pango_layout_set_font_description(layout, panel->g_task.font_desc);
|
||||
pango_layout_set_text(layout, task->title, -1);
|
||||
|
||||
pango_layout_set_width(layout, (((Taskbar *)task->area.parent)->text_width + 1) * PANGO_SCALE);
|
||||
pango_layout_set_width(layout, (((Taskbar *)task->area.parent)->text_width + TINT2_PANGO_SLACK) * PANGO_SCALE);
|
||||
pango_layout_set_height(layout, panel->g_task.text_height * PANGO_SCALE);
|
||||
pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
|
||||
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
|
||||
@@ -477,9 +497,10 @@ void draw_task(void *obj, cairo_t *c)
|
||||
task->_text_posy = (panel->g_task.area.height - task->_text_height) / 2.0;
|
||||
|
||||
Color *config_text = &panel->g_task.font[task->current_state];
|
||||
draw_text(layout, c, panel->g_task.text_posx, task->_text_posy, config_text, panel->font_shadow);
|
||||
draw_text(layout, c, panel->g_task.text_posx, task->_text_posy, config_text, panel->font_shadow ? layout : NULL);
|
||||
|
||||
g_object_unref(layout);
|
||||
g_object_unref(context);
|
||||
}
|
||||
|
||||
if (panel->g_task.has_icon)
|
||||
@@ -532,7 +553,7 @@ int task_compute_desired_size(void *obj)
|
||||
{
|
||||
Task *task = (Task *)obj;
|
||||
Panel *panel = (Panel *)task->area.panel;
|
||||
int size = panel_horizontal ? panel->g_task.maximum_width : panel->g_task.maximum_height;
|
||||
int size = (panel_horizontal ? panel->g_task.maximum_width : panel->g_task.maximum_height) * panel->scale;
|
||||
return size;
|
||||
}
|
||||
|
||||
@@ -652,12 +673,13 @@ void task_refresh_thumbnail(Task *task)
|
||||
return;
|
||||
if (task->current_state == TASK_ICONIFIED)
|
||||
return;
|
||||
Panel *panel = (Panel*)task->area.panel;
|
||||
double now = get_time();
|
||||
if (now - task->thumbnail_last_update < 0.1)
|
||||
return;
|
||||
if (debug_thumbnails)
|
||||
fprintf(stderr, "tint2: thumbnail for window: %s" RESET "\n", task->title ? task->title : "");
|
||||
cairo_surface_t *thumbnail = get_window_thumbnail(task->win, panel_config.g_task.thumbnail_width);
|
||||
cairo_surface_t *thumbnail = get_window_thumbnail(task->win, panel_config.g_task.thumbnail_width * panel->scale);
|
||||
if (!thumbnail)
|
||||
return;
|
||||
if (task->thumbnail)
|
||||
@@ -754,8 +776,8 @@ void blink_urgent(void *arg)
|
||||
GSList *urgent_task = urgent_list;
|
||||
while (urgent_task) {
|
||||
Task *t = urgent_task->data;
|
||||
if (t->urgent_tick < max_tick_urgent) {
|
||||
if (t->urgent_tick++ % 2)
|
||||
if (t->urgent_tick <= max_tick_urgent) {
|
||||
if (++t->urgent_tick % 2)
|
||||
set_task_state(t, TASK_URGENT);
|
||||
else
|
||||
set_task_state(t, window_is_iconified(t->win) ? TASK_ICONIFIED : TASK_NORMAL);
|
||||
|
||||
@@ -68,6 +68,7 @@ typedef struct Task {
|
||||
Color icon_color_hover;
|
||||
Color icon_color_press;
|
||||
char *title;
|
||||
char *application;
|
||||
int urgent_tick;
|
||||
// These may not be up-to-date
|
||||
int win_x;
|
||||
|
||||
@@ -238,15 +238,15 @@ void init_taskbar_panel(void *p)
|
||||
panel->g_taskbar.area.resize_needed = 1;
|
||||
panel->g_taskbar.area.on_screen = TRUE;
|
||||
if (panel_horizontal) {
|
||||
panel->g_taskbar.area.posy = top_border_width(&panel->area) + panel->area.paddingy;
|
||||
panel->g_taskbar.area.posy = top_border_width(&panel->area) + panel->area.paddingy * panel->scale;
|
||||
panel->g_taskbar.area.height =
|
||||
panel->area.height - top_bottom_border_width(&panel->area) - 2 * panel->area.paddingy;
|
||||
panel->area.height - top_bottom_border_width(&panel->area) - 2 * panel->area.paddingy * panel->scale;
|
||||
panel->g_taskbar.area_name.posy = panel->g_taskbar.area.posy;
|
||||
panel->g_taskbar.area_name.height = panel->g_taskbar.area.height;
|
||||
} else {
|
||||
panel->g_taskbar.area.posx = left_border_width(&panel->area) + panel->area.paddingy;
|
||||
panel->g_taskbar.area.posx = left_border_width(&panel->area) + panel->area.paddingy * panel->scale;
|
||||
panel->g_taskbar.area.width =
|
||||
panel->area.width - left_right_border_width(&panel->area) - 2 * panel->area.paddingy;
|
||||
panel->area.width - left_right_border_width(&panel->area) - 2 * panel->area.paddingy * panel->scale;
|
||||
panel->g_taskbar.area_name.posx = panel->g_taskbar.area.posx;
|
||||
panel->g_taskbar.area_name.width = panel->g_taskbar.area.width;
|
||||
}
|
||||
@@ -304,19 +304,19 @@ void init_taskbar_panel(void *p)
|
||||
if (panel_horizontal) {
|
||||
panel->g_task.area.posy = panel->g_taskbar.area.posy +
|
||||
top_bg_border_width(panel->g_taskbar.background[TASKBAR_NORMAL]) +
|
||||
panel->g_taskbar.area.paddingy;
|
||||
panel->g_taskbar.area.paddingy * panel->scale;
|
||||
panel->g_task.area.width = panel->g_task.maximum_width;
|
||||
panel->g_task.area.height = panel->g_taskbar.area.height -
|
||||
top_bottom_bg_border_width(panel->g_taskbar.background[TASKBAR_NORMAL]) -
|
||||
2 * panel->g_taskbar.area.paddingy;
|
||||
2 * panel->g_taskbar.area.paddingy * panel->scale;
|
||||
} else {
|
||||
panel->g_task.area.posx = panel->g_taskbar.area.posx +
|
||||
left_bg_border_width(panel->g_taskbar.background[TASKBAR_NORMAL]) +
|
||||
panel->g_taskbar.area.paddingy;
|
||||
panel->g_taskbar.area.paddingy * panel->scale;
|
||||
panel->g_task.area.width = panel->g_taskbar.area.width -
|
||||
left_right_bg_border_width(panel->g_taskbar.background[TASKBAR_NORMAL]) -
|
||||
2 * panel->g_taskbar.area.paddingy;
|
||||
panel->g_task.area.height = panel->g_task.maximum_height;
|
||||
2 * panel->g_taskbar.area.paddingy * panel->scale;
|
||||
panel->g_task.area.height = panel->g_task.maximum_height * panel->scale;
|
||||
}
|
||||
|
||||
for (int j = 0; j < TASK_STATE_COUNT; ++j) {
|
||||
@@ -333,9 +333,8 @@ void init_taskbar_panel(void *p)
|
||||
}
|
||||
|
||||
// compute vertical position : text and icon
|
||||
int height_ink, height, width;
|
||||
int height, width;
|
||||
get_text_size2(panel->g_task.font_desc,
|
||||
&height_ink,
|
||||
&height,
|
||||
&width,
|
||||
panel->area.height,
|
||||
@@ -344,17 +343,19 @@ void init_taskbar_panel(void *p)
|
||||
5,
|
||||
PANGO_WRAP_WORD_CHAR,
|
||||
PANGO_ELLIPSIZE_END,
|
||||
FALSE);
|
||||
panel->g_task.centered ? PANGO_ALIGN_CENTER : PANGO_ALIGN_LEFT,
|
||||
FALSE,
|
||||
panel->scale);
|
||||
|
||||
panel->g_task.text_posx = left_bg_border_width(panel->g_task.background[0]) + panel->g_task.area.paddingxlr;
|
||||
panel->g_task.text_posx = left_bg_border_width(panel->g_task.background[0]) + panel->g_task.area.paddingxlr * panel->scale;
|
||||
panel->g_task.text_height =
|
||||
panel->g_task.area.height - (2 * panel->g_task.area.paddingy) - top_bottom_border_width(&panel->g_task.area);
|
||||
panel->g_task.area.height - (2 * panel->g_task.area.paddingy * panel->scale) - top_bottom_border_width(&panel->g_task.area);
|
||||
if (panel->g_task.has_icon) {
|
||||
panel->g_task.icon_size1 = MIN(MIN(panel->g_task.maximum_width, panel->g_task.maximum_height),
|
||||
panel->g_task.icon_size1 = MIN(MIN(panel->g_task.maximum_width * panel->scale, panel->g_task.maximum_height * panel->scale),
|
||||
MIN(panel->g_task.area.width, panel->g_task.area.height)) -
|
||||
2 * panel->g_task.area.paddingy - MAX(left_right_border_width(&panel->g_task.area),
|
||||
2 * panel->g_task.area.paddingy * panel->scale - MAX(left_right_border_width(&panel->g_task.area),
|
||||
top_bottom_border_width(&panel->g_task.area));
|
||||
panel->g_task.text_posx += panel->g_task.icon_size1 + panel->g_task.area.paddingx;
|
||||
panel->g_task.text_posx += panel->g_task.icon_size1 + panel->g_task.area.paddingx * panel->scale;
|
||||
panel->g_task.icon_posy = (panel->g_task.area.height - panel->g_task.icon_size1) / 2;
|
||||
}
|
||||
|
||||
@@ -573,12 +574,12 @@ gboolean resize_taskbar(void *obj)
|
||||
}
|
||||
}
|
||||
taskbar->text_width = text_width - panel->g_task.text_posx - right_border_width(&panel->g_task.area) -
|
||||
panel->g_task.area.paddingxlr;
|
||||
panel->g_task.area.paddingxlr * panel->scale;
|
||||
} else {
|
||||
relayout_with_constraint(&taskbar->area, panel->g_task.maximum_height);
|
||||
relayout_with_constraint(&taskbar->area, panel->g_task.maximum_height * panel->scale);
|
||||
|
||||
taskbar->text_width = taskbar->area.width - (2 * panel->g_taskbar.area.paddingy) - panel->g_task.text_posx -
|
||||
right_border_width(&panel->g_task.area) - panel->g_task.area.paddingxlr;
|
||||
taskbar->text_width = taskbar->area.width - (2 * panel->g_taskbar.area.paddingy * panel->scale) - panel->g_task.text_posx -
|
||||
right_border_width(&panel->g_task.area) - panel->g_task.area.paddingxlr * panel->scale;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
@@ -734,6 +735,14 @@ gint compare_task_titles(Task *a, Task *b, Taskbar *taskbar)
|
||||
return strnatcasecmp(a->title ? a->title : "", b->title ? b->title : "");
|
||||
}
|
||||
|
||||
gint compare_task_applications(Task *a, Task *b, Taskbar *taskbar)
|
||||
{
|
||||
int trivial = compare_tasks_trivial(a, b, taskbar);
|
||||
if (trivial != NONTRIVIAL)
|
||||
return trivial;
|
||||
return strnatcasecmp(a->application ? a->application : "", b->application ? b->application : "");
|
||||
}
|
||||
|
||||
gint compare_tasks(Task *a, Task *b, Taskbar *taskbar)
|
||||
{
|
||||
int trivial = compare_tasks_trivial(a, b, taskbar);
|
||||
@@ -745,6 +754,8 @@ gint compare_tasks(Task *a, Task *b, Taskbar *taskbar)
|
||||
return compare_task_centers(a, b, taskbar);
|
||||
} else if (taskbar_sort_method == TASKBAR_SORT_TITLE) {
|
||||
return compare_task_titles(a, b, taskbar);
|
||||
} else if (taskbar_sort_method == TASKBAR_SORT_APPLICATION) {
|
||||
return compare_task_applications(a, b, taskbar);
|
||||
} else if (taskbar_sort_method == TASKBAR_SORT_LRU) {
|
||||
return compare_timespecs(&a->last_activation_time, &b->last_activation_time);
|
||||
} else if (taskbar_sort_method == TASKBAR_SORT_MRU) {
|
||||
@@ -834,7 +845,8 @@ void taskbar_update_thumbnails(void *arg)
|
||||
c;
|
||||
c = c->next) {
|
||||
Task *t = (Task *)c->data;
|
||||
if ((mode == THUMB_MODE_ALL && t->current_state == TASK_ACTIVE && !g_list_find(taskbar_thumbnail_jobs_done, t)) || (mode == THUMB_MODE_ACTIVE_WINDOW && t->current_state == TASK_ACTIVE) ||
|
||||
if ((mode == THUMB_MODE_ALL && t->current_state == TASK_ACTIVE && !g_list_find(taskbar_thumbnail_jobs_done, t)) ||
|
||||
(mode == THUMB_MODE_ACTIVE_WINDOW && t->current_state == TASK_ACTIVE) ||
|
||||
(mode == THUMB_MODE_TOOLTIP_WINDOW && g_tooltip.mapped && g_tooltip.area == &t->area)) {
|
||||
task_refresh_thumbnail(t);
|
||||
if (mode == THUMB_MODE_ALL)
|
||||
|
||||
@@ -21,6 +21,7 @@ typedef enum TaskbarSortMethod {
|
||||
TASKBAR_NOSORT = 0,
|
||||
TASKBAR_SORT_CENTER,
|
||||
TASKBAR_SORT_TITLE,
|
||||
TASKBAR_SORT_APPLICATION,
|
||||
TASKBAR_SORT_LRU,
|
||||
TASKBAR_SORT_MRU,
|
||||
} TaskbarSortMethod;
|
||||
|
||||
@@ -134,9 +134,8 @@ int taskbarname_compute_desired_size(void *obj)
|
||||
{
|
||||
TaskbarName *taskbar_name = (TaskbarName *)obj;
|
||||
Panel *panel = (Panel *)taskbar_name->area.panel;
|
||||
int name_height, name_width, name_height_ink;
|
||||
int name_height, name_width;
|
||||
get_text_size2(panel_config.taskbarname_font_desc,
|
||||
&name_height_ink,
|
||||
&name_height,
|
||||
&name_width,
|
||||
panel->area.height,
|
||||
@@ -145,12 +144,14 @@ int taskbarname_compute_desired_size(void *obj)
|
||||
strlen(taskbar_name->name),
|
||||
PANGO_WRAP_WORD_CHAR,
|
||||
PANGO_ELLIPSIZE_NONE,
|
||||
FALSE);
|
||||
PANGO_ALIGN_CENTER,
|
||||
FALSE,
|
||||
panel->scale);
|
||||
|
||||
if (panel_horizontal) {
|
||||
return name_width + 2 * taskbar_name->area.paddingxlr + left_right_border_width(&taskbar_name->area);
|
||||
return name_width + 2 * taskbar_name->area.paddingxlr * panel->scale + left_right_border_width(&taskbar_name->area);
|
||||
} else {
|
||||
return name_height + 2 * taskbar_name->area.paddingxlr + top_bottom_border_width(&taskbar_name->area);
|
||||
return name_height + 2 * taskbar_name->area.paddingxlr * panel->scale + top_bottom_border_width(&taskbar_name->area);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,9 +162,8 @@ gboolean resize_taskbarname(void *obj)
|
||||
|
||||
schedule_redraw(&taskbar_name->area);
|
||||
|
||||
int name_height, name_width, name_height_ink;
|
||||
int name_height, name_width;
|
||||
get_text_size2(panel_config.taskbarname_font_desc,
|
||||
&name_height_ink,
|
||||
&name_height,
|
||||
&name_width,
|
||||
panel->area.height,
|
||||
@@ -172,7 +172,9 @@ gboolean resize_taskbarname(void *obj)
|
||||
strlen(taskbar_name->name),
|
||||
PANGO_WRAP_WORD_CHAR,
|
||||
PANGO_ELLIPSIZE_NONE,
|
||||
FALSE);
|
||||
PANGO_ALIGN_CENTER,
|
||||
FALSE,
|
||||
panel->scale);
|
||||
|
||||
gboolean result = FALSE;
|
||||
int new_size = taskbarname_compute_desired_size(obj);
|
||||
@@ -195,11 +197,14 @@ gboolean resize_taskbarname(void *obj)
|
||||
void draw_taskbarname(void *obj, cairo_t *c)
|
||||
{
|
||||
TaskbarName *taskbar_name = obj;
|
||||
Panel *panel = (Panel *)taskbar_name->area.panel;
|
||||
Taskbar *taskbar = taskbar_name->area.parent;
|
||||
Color *config_text = (taskbar->desktop == server.desktop) ? &taskbarname_active_font : &taskbarname_font;
|
||||
|
||||
// draw content
|
||||
PangoLayout *layout = pango_cairo_create_layout(c);
|
||||
PangoContext *context = pango_cairo_create_context(c);
|
||||
pango_cairo_context_set_resolution(context, 96 * panel->scale);
|
||||
PangoLayout *layout = pango_layout_new(context);
|
||||
pango_layout_set_font_description(layout, panel_config.taskbarname_font_desc);
|
||||
pango_layout_set_width(layout, taskbar_name->area.width * PANGO_SCALE);
|
||||
pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
|
||||
@@ -210,9 +215,10 @@ void draw_taskbarname(void *obj, cairo_t *c)
|
||||
cairo_set_source_rgba(c, config_text->rgb[0], config_text->rgb[1], config_text->rgb[2], config_text->alpha);
|
||||
|
||||
pango_cairo_update_layout(c, layout);
|
||||
draw_text(layout, c, 0, taskbar_name->posy, config_text, ((Panel *)taskbar_name->area.panel)->font_shadow);
|
||||
draw_text(layout, c, 0, taskbar_name->posy, config_text, ((Panel *)taskbar_name->area.panel)->font_shadow ? layout : NULL);
|
||||
|
||||
g_object_unref(layout);
|
||||
g_object_unref(context);
|
||||
}
|
||||
|
||||
void update_desktop_names()
|
||||
|
||||
@@ -20,6 +20,7 @@ include_directories( ../util
|
||||
${RSVG_INCLUDE_DIRS} )
|
||||
|
||||
set(SOURCES ../util/common.c
|
||||
../util/bt.c
|
||||
../util/strnatcmp.c
|
||||
../util/cache.c
|
||||
../util/timer.c
|
||||
|
||||
@@ -383,6 +383,11 @@ static void menuAbout()
|
||||
|
||||
// ====== Theme import/copy/delete ======
|
||||
|
||||
static void free_data(gpointer data, gpointer userdata)
|
||||
{
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
// Shows open dialog and copies the selected files to ~ without overwrite.
|
||||
static void menuImportFile()
|
||||
{
|
||||
@@ -407,7 +412,7 @@ static void menuImportFile()
|
||||
gchar *newpath = import_no_overwrite(l->data);
|
||||
g_free(newpath);
|
||||
}
|
||||
g_slist_foreach(list, (GFunc)g_free, NULL);
|
||||
g_slist_foreach(list, free_data, NULL);
|
||||
g_slist_free(list);
|
||||
gtk_widget_destroy(dialog);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -22,6 +22,7 @@
|
||||
#include "gradient_gui.h"
|
||||
#include "strlcat.h"
|
||||
|
||||
GtkWidget *scale_relative_to_dpi, *scale_relative_to_screen_height;
|
||||
GtkWidget *panel_width, *panel_height, *panel_margin_x, *panel_margin_y, *panel_padding_x, *panel_padding_y,
|
||||
*panel_spacing;
|
||||
GtkWidget *panel_wm_menu, *panel_dock, *panel_autohide, *panel_autohide_show_time, *panel_autohide_hide_time,
|
||||
@@ -600,6 +601,32 @@ void create_panel(GtkWidget *parent)
|
||||
"for centered panels, it is evenly distributed on both sides of the panel."),
|
||||
NULL);
|
||||
|
||||
row++;
|
||||
col = 2;
|
||||
label = gtk_label_new(_("Scale relative to DPI"));
|
||||
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
|
||||
gtk_widget_show(label);
|
||||
gtk_table_attach(GTK_TABLE(table), label, col, col + 1, row, row + 1, GTK_FILL, 0, 0, 0);
|
||||
col++;
|
||||
|
||||
scale_relative_to_dpi = gtk_spin_button_new_with_range(0, 9000, 1);
|
||||
gtk_widget_show(scale_relative_to_dpi);
|
||||
gtk_table_attach(GTK_TABLE(table), scale_relative_to_dpi, col, col + 1, row, row + 1, GTK_FILL, 0, 0, 0);
|
||||
col++;
|
||||
|
||||
row++;
|
||||
col = 2;
|
||||
label = gtk_label_new(_("Scale relative to screen height"));
|
||||
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
|
||||
gtk_widget_show(label);
|
||||
gtk_table_attach(GTK_TABLE(table), label, col, col + 1, row, row + 1, GTK_FILL, 0, 0, 0);
|
||||
col++;
|
||||
|
||||
scale_relative_to_screen_height = gtk_spin_button_new_with_range(0, 9000, 1);
|
||||
gtk_widget_show(scale_relative_to_screen_height);
|
||||
gtk_table_attach(GTK_TABLE(table), scale_relative_to_screen_height, col, col + 1, row, row + 1, GTK_FILL, 0, 0, 0);
|
||||
col++;
|
||||
|
||||
change_paragraph(parent);
|
||||
|
||||
label = gtk_label_new(_("<b>Appearance</b>"));
|
||||
@@ -2691,6 +2718,7 @@ void create_taskbar(GtkWidget *parent)
|
||||
col++;
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(taskbar_sort_order), _("None"));
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(taskbar_sort_order), _("By title"));
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(taskbar_sort_order), _("By application"));
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(taskbar_sort_order), _("By center"));
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(taskbar_sort_order), _("Most recently used first"));
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(taskbar_sort_order), _("Most recently used last"));
|
||||
@@ -2701,6 +2729,7 @@ void create_taskbar(GtkWidget *parent)
|
||||
"'None' means that new tasks are added to the end, and the user can also reorder task "
|
||||
"buttons by mouse dragging. \n"
|
||||
"'By title' means that tasks are sorted by their window titles. \n"
|
||||
"'By application' means that tasks are sorted by their application names. \n"
|
||||
"'By center' means that tasks are sorted geometrically by their window centers."),
|
||||
NULL);
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "../launcher/icon-theme-common.h"
|
||||
|
||||
// panel
|
||||
extern GtkWidget *scale_relative_to_dpi, *scale_relative_to_screen_height;
|
||||
extern GtkWidget *panel_width, *panel_height, *panel_margin_x, *panel_margin_y, *panel_padding_x, *panel_padding_y,
|
||||
*panel_spacing;
|
||||
extern GtkWidget *panel_wm_menu, *panel_dock, *panel_autohide, *panel_autohide_show_time, *panel_autohide_hide_time,
|
||||
|
||||
@@ -378,6 +378,13 @@ void config_write_panel(FILE *fp)
|
||||
(int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(mouse_pressed_icon_saturation)),
|
||||
(int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(mouse_pressed_icon_brightness)));
|
||||
|
||||
fprintf(fp,
|
||||
"scale_relative_to_dpi = %d\n",
|
||||
(int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(scale_relative_to_dpi)));
|
||||
fprintf(fp,
|
||||
"scale_relative_to_screen_height = %d\n",
|
||||
(int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(scale_relative_to_screen_height)));
|
||||
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
|
||||
@@ -450,10 +457,12 @@ void config_write_taskbar(FILE *fp)
|
||||
} else if (gtk_combo_box_get_active(GTK_COMBO_BOX(taskbar_sort_order)) == 1) {
|
||||
fprintf(fp, "title");
|
||||
} else if (gtk_combo_box_get_active(GTK_COMBO_BOX(taskbar_sort_order)) == 2) {
|
||||
fprintf(fp, "center");
|
||||
fprintf(fp, "application");
|
||||
} else if (gtk_combo_box_get_active(GTK_COMBO_BOX(taskbar_sort_order)) == 3) {
|
||||
fprintf(fp, "mru");
|
||||
fprintf(fp, "center");
|
||||
} else if (gtk_combo_box_get_active(GTK_COMBO_BOX(taskbar_sort_order)) == 4) {
|
||||
fprintf(fp, "mru");
|
||||
} else if (gtk_combo_box_get_active(GTK_COMBO_BOX(taskbar_sort_order)) == 5) {
|
||||
fprintf(fp, "lru");
|
||||
} else {
|
||||
fprintf(fp, "none");
|
||||
@@ -1108,7 +1117,13 @@ void add_entry(char *key, char *value)
|
||||
char *value1 = 0, *value2 = 0, *value3 = 0;
|
||||
|
||||
/* Gradients */
|
||||
if (strcmp(key, "gradient") == 0) {
|
||||
if (strcmp(key, "scale_relative_to_dpi") == 0) {
|
||||
extract_values(value, &value1, &value2, &value3);
|
||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(scale_relative_to_dpi), atoi(value1));
|
||||
} else if (strcmp(key, "scale_relative_to_screen_height") == 0) {
|
||||
extract_values(value, &value1, &value2, &value3);
|
||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(scale_relative_to_screen_height), atoi(value1));
|
||||
} else if (strcmp(key, "gradient") == 0) {
|
||||
finalize_gradient();
|
||||
GradientConfigType t;
|
||||
if (g_str_equal(value, "horizontal"))
|
||||
@@ -1546,12 +1561,14 @@ void add_entry(char *key, char *value)
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(taskbar_sort_order), 0);
|
||||
else if (strcmp(value, "title") == 0)
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(taskbar_sort_order), 1);
|
||||
else if (strcmp(value, "center") == 0)
|
||||
else if (strcmp(value, "application") == 0)
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(taskbar_sort_order), 2);
|
||||
else if (strcmp(value, "mru") == 0)
|
||||
else if (strcmp(value, "center") == 0)
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(taskbar_sort_order), 3);
|
||||
else if (strcmp(value, "lru") == 0)
|
||||
else if (strcmp(value, "mru") == 0)
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(taskbar_sort_order), 4);
|
||||
else if (strcmp(value, "lru") == 0)
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(taskbar_sort_order), 5);
|
||||
else
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(taskbar_sort_order), 0);
|
||||
} else if (strcmp(key, "task_align") == 0) {
|
||||
|
||||
@@ -153,7 +153,9 @@ void tooltip_update_geometry()
|
||||
|
||||
cairo_surface_t *cs = cairo_xlib_surface_create(server.display, g_tooltip.window, server.visual, width, height);
|
||||
cairo_t *c = cairo_create(cs);
|
||||
PangoLayout *layout = pango_cairo_create_layout(c);
|
||||
PangoContext *context = pango_cairo_create_context(c);
|
||||
pango_cairo_context_set_resolution(context, 96 * panel->scale);
|
||||
PangoLayout *layout = pango_layout_new(context);
|
||||
|
||||
pango_layout_set_font_description(layout, g_tooltip.font_desc);
|
||||
PangoRectangle r1, r2;
|
||||
@@ -161,7 +163,7 @@ void tooltip_update_geometry()
|
||||
pango_layout_get_pixel_extents(layout, &r1, &r2);
|
||||
int max_width = MIN(r2.width * 5, screen_width * 2 / 3);
|
||||
if (g_tooltip.image && cairo_image_surface_get_width(g_tooltip.image) > 0) {
|
||||
max_width = left_right_bg_border_width(g_tooltip.bg) + 2 * g_tooltip.paddingx +
|
||||
max_width = left_right_bg_border_width(g_tooltip.bg) + 2 * g_tooltip.paddingx * panel->scale +
|
||||
cairo_image_surface_get_width(g_tooltip.image);
|
||||
}
|
||||
pango_layout_set_width(layout, max_width * PANGO_SCALE);
|
||||
@@ -169,12 +171,12 @@ void tooltip_update_geometry()
|
||||
pango_layout_set_text(layout, g_tooltip.tooltip_text ? g_tooltip.tooltip_text : "1234567890abcdef", -1);
|
||||
pango_layout_set_wrap(layout, PANGO_WRAP_WORD);
|
||||
pango_layout_get_pixel_extents(layout, &r1, &r2);
|
||||
width = left_right_bg_border_width(g_tooltip.bg) + 2 * g_tooltip.paddingx + r2.width;
|
||||
height = top_bottom_bg_border_width(g_tooltip.bg) + 2 * g_tooltip.paddingy + r2.height;
|
||||
width = left_right_bg_border_width(g_tooltip.bg) + 2 * g_tooltip.paddingx * panel->scale + r2.width;
|
||||
height = top_bottom_bg_border_width(g_tooltip.bg) + 2 * g_tooltip.paddingy * panel->scale + r2.height;
|
||||
if (g_tooltip.image && cairo_image_surface_get_width(g_tooltip.image) > 0) {
|
||||
width = left_right_bg_border_width(g_tooltip.bg) + 2 * g_tooltip.paddingx +
|
||||
width = left_right_bg_border_width(g_tooltip.bg) + 2 * g_tooltip.paddingx * panel->scale +
|
||||
cairo_image_surface_get_width(g_tooltip.image);
|
||||
height += g_tooltip.paddingy + cairo_image_surface_get_height(g_tooltip.image);
|
||||
height += g_tooltip.paddingy * panel->scale + cairo_image_surface_get_height(g_tooltip.image);
|
||||
}
|
||||
|
||||
if (panel_horizontal && panel_position & BOTTOM)
|
||||
@@ -187,6 +189,7 @@ void tooltip_update_geometry()
|
||||
x = panel->posx - width;
|
||||
|
||||
g_object_unref(layout);
|
||||
g_object_unref(context);
|
||||
cairo_destroy(c);
|
||||
cairo_surface_destroy(cs);
|
||||
}
|
||||
@@ -243,6 +246,7 @@ void tooltip_update()
|
||||
tooltip_hide(0);
|
||||
return;
|
||||
}
|
||||
Panel *panel = g_tooltip.panel;
|
||||
|
||||
tooltip_update_geometry();
|
||||
if (just_shown) {
|
||||
@@ -277,7 +281,9 @@ void tooltip_update()
|
||||
|
||||
Color fc = g_tooltip.font_color;
|
||||
cairo_set_source_rgba(c, fc.rgb[0], fc.rgb[1], fc.rgb[2], fc.alpha);
|
||||
PangoLayout *layout = pango_cairo_create_layout(c);
|
||||
PangoContext *context = pango_cairo_create_context(c);
|
||||
pango_cairo_context_set_resolution(context, 96 * panel->scale);
|
||||
PangoLayout *layout = pango_layout_new(context);
|
||||
pango_layout_set_font_description(layout, g_tooltip.font_desc);
|
||||
pango_layout_set_wrap(layout, PANGO_WRAP_WORD);
|
||||
pango_layout_set_text(layout, g_tooltip.tooltip_text, -1);
|
||||
@@ -289,15 +295,16 @@ void tooltip_update()
|
||||
// I do not know why this is the right way, but with the below cairo_move_to it seems to be centered (horiz. and
|
||||
// vert.)
|
||||
cairo_move_to(c,
|
||||
-r1.x / 2 + left_bg_border_width(g_tooltip.bg) + g_tooltip.paddingx,
|
||||
-r1.y / 2 + 1 + top_bg_border_width(g_tooltip.bg) + g_tooltip.paddingy);
|
||||
-r1.x / 2 + left_bg_border_width(g_tooltip.bg) + g_tooltip.paddingx * panel->scale,
|
||||
-r1.y / 2 + 1 + top_bg_border_width(g_tooltip.bg) + g_tooltip.paddingy * panel->scale);
|
||||
pango_cairo_show_layout(c, layout);
|
||||
g_object_unref(layout);
|
||||
g_object_unref(context);
|
||||
|
||||
if (g_tooltip.image) {
|
||||
cairo_translate(c,
|
||||
left_bg_border_width(g_tooltip.bg) + g_tooltip.paddingx,
|
||||
height - bottom_bg_border_width(g_tooltip.bg) - g_tooltip.paddingy - cairo_image_surface_get_height(g_tooltip.image));
|
||||
left_bg_border_width(g_tooltip.bg) + g_tooltip.paddingx * panel->scale,
|
||||
height - bottom_bg_border_width(g_tooltip.bg) - g_tooltip.paddingy * panel->scale - cairo_image_surface_get_height(g_tooltip.image));
|
||||
cairo_set_source_surface(c, g_tooltip.image, 0, 0);
|
||||
cairo_paint(c);
|
||||
}
|
||||
|
||||
@@ -478,14 +478,14 @@ void draw(Area *a)
|
||||
a->_clear(a);
|
||||
}
|
||||
|
||||
cairo_surface_t *cs = cairo_xlib_surface_create(server.display, a->pix, server.visual, a->width, a->height);
|
||||
cairo_surface_t *cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, a->width, a->height);
|
||||
cairo_t *c = cairo_create(cs);
|
||||
|
||||
draw_background(a, c);
|
||||
|
||||
if (a->_draw_foreground)
|
||||
a->_draw_foreground(a, c);
|
||||
|
||||
draw_cairo_surface_to_xpixmap(cs, a->pix);
|
||||
cairo_destroy(c);
|
||||
cairo_surface_destroy(cs);
|
||||
}
|
||||
@@ -929,10 +929,8 @@ void area_compute_text_geometry(Area *area,
|
||||
const char *line2,
|
||||
PangoFontDescription *line1_font_desc,
|
||||
PangoFontDescription *line2_font_desc,
|
||||
int *line1_height_ink,
|
||||
int *line1_height,
|
||||
int *line1_width,
|
||||
int *line2_height_ink,
|
||||
int *line2_height,
|
||||
int *line2_width)
|
||||
{
|
||||
@@ -941,7 +939,6 @@ void area_compute_text_geometry(Area *area,
|
||||
|
||||
if (line1 && line1[0])
|
||||
get_text_size2(line1_font_desc,
|
||||
line1_height_ink,
|
||||
line1_height,
|
||||
line1_width,
|
||||
available_h,
|
||||
@@ -950,13 +947,14 @@ void area_compute_text_geometry(Area *area,
|
||||
strlen(line1),
|
||||
PANGO_WRAP_WORD_CHAR,
|
||||
PANGO_ELLIPSIZE_NONE,
|
||||
FALSE);
|
||||
PANGO_ALIGN_CENTER,
|
||||
FALSE,
|
||||
((Panel*)area->panel)->scale);
|
||||
else
|
||||
*line1_width = *line1_height_ink = *line1_height = 0;
|
||||
*line1_width = *line1_height = 0;
|
||||
|
||||
if (line2 && line2[0])
|
||||
get_text_size2(line2_font_desc,
|
||||
line2_height_ink,
|
||||
line2_height,
|
||||
line2_width,
|
||||
available_h,
|
||||
@@ -965,9 +963,11 @@ void area_compute_text_geometry(Area *area,
|
||||
strlen(line2),
|
||||
PANGO_WRAP_WORD_CHAR,
|
||||
PANGO_ELLIPSIZE_NONE,
|
||||
FALSE);
|
||||
PANGO_ALIGN_CENTER,
|
||||
FALSE,
|
||||
((Panel*)area->panel)->scale);
|
||||
else
|
||||
*line2_width = *line2_height_ink = *line2_height = 0;
|
||||
*line2_width = *line2_height = 0;
|
||||
}
|
||||
|
||||
int text_area_compute_desired_size(Area *area,
|
||||
@@ -976,16 +976,14 @@ int text_area_compute_desired_size(Area *area,
|
||||
PangoFontDescription *line1_font_desc,
|
||||
PangoFontDescription *line2_font_desc)
|
||||
{
|
||||
int line1_height_ink, line1_height, line1_width, line2_height_ink, line2_height, line2_width;
|
||||
int line1_height, line1_width, line2_height, line2_width;
|
||||
area_compute_text_geometry(area,
|
||||
line1,
|
||||
line2,
|
||||
line1_font_desc,
|
||||
line2_font_desc,
|
||||
&line1_height_ink,
|
||||
&line1_height,
|
||||
&line1_width,
|
||||
&line2_height_ink,
|
||||
&line2_height,
|
||||
&line2_width);
|
||||
|
||||
@@ -1010,17 +1008,15 @@ gboolean resize_text_area(Area *area,
|
||||
|
||||
schedule_redraw(area);
|
||||
|
||||
int line1_height_ink, line1_height, line1_width;
|
||||
int line2_height_ink, line2_height, line2_width;
|
||||
int line1_height, line1_width;
|
||||
int line2_height, line2_width;
|
||||
area_compute_text_geometry(area,
|
||||
line1,
|
||||
line2,
|
||||
line1_font_desc,
|
||||
line2_font_desc,
|
||||
&line1_height_ink,
|
||||
&line1_height,
|
||||
&line1_width,
|
||||
&line2_height_ink,
|
||||
&line2_height,
|
||||
&line2_width);
|
||||
|
||||
@@ -1067,12 +1063,16 @@ void draw_text_area(Area *area,
|
||||
PangoFontDescription *line2_font_desc,
|
||||
int line1_posy,
|
||||
int line2_posy,
|
||||
Color *color)
|
||||
Color *color,
|
||||
double scale)
|
||||
{
|
||||
int inner_w, inner_h;
|
||||
area_compute_inner_size(area, &inner_w, &inner_h);
|
||||
|
||||
PangoLayout *layout = pango_cairo_create_layout(c);
|
||||
PangoContext *context = pango_cairo_create_context(c);
|
||||
pango_cairo_context_set_resolution(context, 96 * scale);
|
||||
PangoLayout *layout = pango_layout_new(context);
|
||||
|
||||
pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
|
||||
pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
|
||||
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
|
||||
@@ -1084,7 +1084,7 @@ void draw_text_area(Area *area,
|
||||
pango_layout_set_font_description(layout, line1_font_desc);
|
||||
pango_layout_set_text(layout, line1, strlen(line1));
|
||||
pango_cairo_update_layout(c, layout);
|
||||
draw_text(layout, c, (area->width - inner_w) / 2, line1_posy, color, ((Panel *)area->panel)->font_shadow);
|
||||
draw_text(layout, c, (area->width - inner_w) / 2, line1_posy, color, ((Panel *)area->panel)->font_shadow ? layout : NULL);
|
||||
}
|
||||
|
||||
if (line2 && line2[0]) {
|
||||
@@ -1092,10 +1092,11 @@ void draw_text_area(Area *area,
|
||||
pango_layout_set_indent(layout, 0);
|
||||
pango_layout_set_text(layout, line2, strlen(line2));
|
||||
pango_cairo_update_layout(c, layout);
|
||||
draw_text(layout, c, (area->width - inner_w) / 2, line2_posy, color, ((Panel *)area->panel)->font_shadow);
|
||||
draw_text(layout, c, (area->width - inner_w) / 2, line2_posy, color, ((Panel *)area->panel)->font_shadow ? layout : NULL);
|
||||
}
|
||||
|
||||
g_object_unref(layout);
|
||||
g_object_unref(context);
|
||||
}
|
||||
|
||||
Area *compute_element_area(Area *area, Element element)
|
||||
|
||||
@@ -273,10 +273,8 @@ void area_compute_text_geometry(Area *area,
|
||||
const char *line2,
|
||||
PangoFontDescription *line1_font_desc,
|
||||
PangoFontDescription *line2_font_desc,
|
||||
int *line1_height_ink,
|
||||
int *line1_height,
|
||||
int *line1_width,
|
||||
int *line2_height_ink,
|
||||
int *line2_height,
|
||||
int *line2_width);
|
||||
int text_area_compute_desired_size(Area *area,
|
||||
@@ -299,7 +297,8 @@ void draw_text_area(Area *area,
|
||||
PangoFontDescription *line2_font_desc,
|
||||
int line1_posy,
|
||||
int line2_posy,
|
||||
Color *color);
|
||||
Color *color,
|
||||
double scale);
|
||||
|
||||
int left_border_width(Area *a);
|
||||
int right_border_width(Area *a);
|
||||
|
||||
268
src/util/bt.c
Normal file
268
src/util/bt.c
Normal file
@@ -0,0 +1,268 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Tint2 : backtrace
|
||||
*
|
||||
* Copyright (C) 2007 Pål Staurland (staura@gmail.com)
|
||||
* Modified (C) 2008 thierry lorthiois (lorthiois@bbsoft.fr) from Omega distribution
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "bt.h"
|
||||
#include "bool.h"
|
||||
|
||||
#if defined(HAS_BACKTRACE) || defined(HAS_LIBUNWIND) || defined(HAS_EXECINFO)
|
||||
|
||||
static void bt_add_frame(struct backtrace *bt, const char *fname)
|
||||
{
|
||||
if (bt->frame_count >= BT_MAX_FRAMES)
|
||||
return;
|
||||
struct backtrace_frame *frame = &bt->frames[bt->frame_count];
|
||||
if (fname && *fname) {
|
||||
strncpy(frame->name, fname, BT_FRAME_SIZE);
|
||||
} else {
|
||||
strncpy(frame->name, "??", BT_FRAME_SIZE);
|
||||
}
|
||||
bt->frame_count++;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAS_BACKTRACE
|
||||
|
||||
#include <backtrace.h>
|
||||
|
||||
static const char *get_exe()
|
||||
{
|
||||
static char buf[256] = {0};
|
||||
ssize_t ret = readlink("/proc/self/exe", buf, sizeof(buf)-1);
|
||||
if (ret > 0)
|
||||
return buf;
|
||||
ret = readlink("/proc/curproc/file", buf, sizeof(buf)-1);
|
||||
if (ret > 0)
|
||||
return buf;
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void bt_error_callback(void *data, const char *msg, int errnum)
|
||||
{
|
||||
}
|
||||
|
||||
static int bt_full_callback(void *data, uintptr_t pc,
|
||||
const char *filename, int lineno,
|
||||
const char *function)
|
||||
{
|
||||
struct backtrace *bt = (struct backtrace *)data;
|
||||
bt_add_frame(bt, function);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void get_backtrace(struct backtrace *bt, int skip)
|
||||
{
|
||||
static struct backtrace_state *state = NULL;
|
||||
|
||||
if (!state) {
|
||||
const char *exe = get_exe();
|
||||
if (exe)
|
||||
state = backtrace_create_state(exe, 1, bt_error_callback, NULL);
|
||||
}
|
||||
bzero(bt, sizeof(*bt));
|
||||
if (state) {
|
||||
backtrace_full(state, skip + 1, bt_full_callback, bt_error_callback, bt);
|
||||
}
|
||||
}
|
||||
|
||||
#elif HAS_LIBUNWIND
|
||||
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include <libunwind.h>
|
||||
|
||||
struct bt_mapping {
|
||||
unw_word_t ip;
|
||||
char fname[BT_FRAME_SIZE];
|
||||
};
|
||||
|
||||
#define BT_BUCKET_SIZE 3
|
||||
struct bt_bucket {
|
||||
struct bt_mapping mappings[BT_BUCKET_SIZE];
|
||||
};
|
||||
|
||||
struct bt_cache {
|
||||
struct bt_bucket *buckets;
|
||||
size_t count;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
static unsigned oat_hash(void *key, int len)
|
||||
{
|
||||
unsigned char *p = key;
|
||||
unsigned h = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
h += p[i];
|
||||
h += (h << 10);
|
||||
h ^= (h >> 6);
|
||||
}
|
||||
|
||||
h += (h << 3);
|
||||
h ^= (h >> 11);
|
||||
h += (h << 15);
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
static struct bt_bucket *cached_proc_name_bucket(struct bt_cache *cache, unw_word_t ip)
|
||||
{
|
||||
if (!cache->size)
|
||||
return NULL;
|
||||
unsigned h = oat_hash(&ip, sizeof(ip));
|
||||
return &cache->buckets[h % cache->size];
|
||||
}
|
||||
|
||||
static void bt_cache_init(struct bt_cache *cache)
|
||||
{
|
||||
if (!cache->size) {
|
||||
cache->size = 119;
|
||||
cache->buckets = calloc(cache->size, sizeof(*cache->buckets));
|
||||
if (!cache->buckets)
|
||||
cache->size = 0;
|
||||
cache->count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void cached_proc_name_store(struct bt_cache *cache, unw_word_t ip, const char *fname);
|
||||
|
||||
static void bt_cache_rebalance(struct bt_cache *cache)
|
||||
{
|
||||
struct bt_cache bigger = {};
|
||||
bigger.size = cache->size * 2 + 1337;
|
||||
bigger.buckets = calloc(bigger.size, sizeof(*bigger.buckets));
|
||||
bigger.count = 0;
|
||||
for (size_t b = 0; b < cache->size; b++) {
|
||||
for (size_t i = 0; i < BT_BUCKET_SIZE; i++) {
|
||||
struct bt_mapping *map = &cache->buckets[b].mappings[i];
|
||||
if (map->ip) {
|
||||
cached_proc_name_store(&bigger, map->ip, map->fname);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(cache->buckets);
|
||||
*cache = bigger;
|
||||
}
|
||||
|
||||
static void cached_proc_name_store(struct bt_cache *cache, unw_word_t ip, const char *fname)
|
||||
{
|
||||
bt_cache_init(cache);
|
||||
if (!cache->size)
|
||||
return;
|
||||
struct bt_bucket *bucket = cached_proc_name_bucket(cache, ip);
|
||||
bool stored = false;
|
||||
for (size_t i = 0; i < BT_BUCKET_SIZE; i++) {
|
||||
if (bucket->mappings[i].ip == ip)
|
||||
return;
|
||||
if (bucket->mappings[i].ip != 0)
|
||||
continue;
|
||||
bucket->mappings[i].ip = ip;
|
||||
strncpy(bucket->mappings[i].fname, fname, sizeof(bucket->mappings[i].fname));
|
||||
cache->count++;
|
||||
stored = true;
|
||||
break;
|
||||
}
|
||||
if (cache->count > cache->size / 4 || !stored) {
|
||||
bt_cache_rebalance(cache);
|
||||
fprintf(stderr, "tint2: proc_name cache: ratio %f, count %lu, size %lu, (%lu bytes)\n",
|
||||
cache->count / (double)cache->size,
|
||||
cache->count, (size_t)cache->size, cache->size * sizeof(*cache->buckets));
|
||||
}
|
||||
}
|
||||
|
||||
const char *cached_proc_name_get(struct bt_cache *cache, unw_word_t ip)
|
||||
{
|
||||
struct bt_bucket *bucket = cached_proc_name_bucket(cache, ip);
|
||||
if (!bucket)
|
||||
return NULL;
|
||||
for (size_t i = 0; i < BT_BUCKET_SIZE; i++) {
|
||||
if (bucket->mappings[i].ip != ip)
|
||||
continue;
|
||||
return bucket->mappings[i].fname;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void get_backtrace(struct backtrace *bt, int skip)
|
||||
{
|
||||
static struct bt_cache bt_cache = {};
|
||||
bzero(bt, sizeof(*bt));
|
||||
|
||||
unw_cursor_t cursor;
|
||||
unw_context_t context;
|
||||
unw_getcontext(&context);
|
||||
unw_init_local(&cursor, &context);
|
||||
|
||||
while (unw_step(&cursor) > 0) {
|
||||
if (skip > 0) {
|
||||
skip--;
|
||||
continue;
|
||||
}
|
||||
unw_word_t offset;
|
||||
char fname[BT_FRAME_SIZE] = {0};
|
||||
unw_word_t ip;
|
||||
unw_get_reg(&cursor, UNW_REG_IP, &ip);
|
||||
const char *fname_cached = cached_proc_name_get(&bt_cache, ip);
|
||||
if (fname_cached) {
|
||||
bt_add_frame(bt, fname_cached);
|
||||
} else {
|
||||
unw_get_proc_name(&cursor, fname, sizeof(fname), &offset);
|
||||
cached_proc_name_store(&bt_cache, ip, fname);
|
||||
bt_add_frame(bt, fname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#elif HAS_EXECINFO
|
||||
|
||||
#include <execinfo.h>
|
||||
|
||||
void get_backtrace(struct backtrace *bt, int skip)
|
||||
{
|
||||
bzero(bt, sizeof(*bt));
|
||||
|
||||
void *array[BT_MAX_FRAMES];
|
||||
int size = backtrace(array, BT_MAX_FRAMES);
|
||||
char **strings = backtrace_symbols(array, size);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
bt_add_frame(bt, strings[i]);
|
||||
}
|
||||
|
||||
free(strings);
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
void get_backtrace(struct backtrace *bt, int skip)
|
||||
{
|
||||
bzero(bt, sizeof(*bt));
|
||||
}
|
||||
|
||||
#endif
|
||||
20
src/util/bt.h
Normal file
20
src/util/bt.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef BT_H
|
||||
#define BT_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#define BT_FRAME_SIZE 64
|
||||
#define BT_MAX_FRAMES 64
|
||||
|
||||
struct backtrace_frame {
|
||||
char name[BT_FRAME_SIZE];
|
||||
};
|
||||
|
||||
struct backtrace {
|
||||
struct backtrace_frame frames[BT_MAX_FRAMES];
|
||||
size_t frame_count;
|
||||
};
|
||||
|
||||
void get_backtrace(struct backtrace *bt, int skip);
|
||||
|
||||
#endif // BT_H
|
||||
@@ -48,18 +48,10 @@
|
||||
#include <librsvg/rsvg.h>
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_LIBUNWIND
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include <libunwind.h>
|
||||
#else
|
||||
#ifdef ENABLE_EXECINFO
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "../panel.h"
|
||||
#include "timer.h"
|
||||
#include "signals.h"
|
||||
#include "bt.h"
|
||||
|
||||
void write_string(int fd, const char *s)
|
||||
{
|
||||
@@ -83,39 +75,13 @@ void log_string(int fd, const char *s)
|
||||
|
||||
void dump_backtrace(int log_fd)
|
||||
{
|
||||
#ifndef DISABLE_BACKTRACE
|
||||
struct backtrace bt;
|
||||
get_backtrace(&bt, 1);
|
||||
log_string(log_fd, "\n" YELLOW "Backtrace:" RESET "\n");
|
||||
|
||||
#ifdef ENABLE_LIBUNWIND
|
||||
unw_cursor_t cursor;
|
||||
unw_context_t context;
|
||||
unw_getcontext(&context);
|
||||
unw_init_local(&cursor, &context);
|
||||
|
||||
while (unw_step(&cursor) > 0) {
|
||||
unw_word_t offset;
|
||||
char fname[128];
|
||||
fname[0] = '\0';
|
||||
(void)unw_get_proc_name(&cursor, fname, sizeof(fname), &offset);
|
||||
log_string(log_fd, fname);
|
||||
for (size_t i = 0; i < bt.frame_count; i++) {
|
||||
log_string(log_fd, bt.frames[i].name);
|
||||
log_string(log_fd, "\n");
|
||||
}
|
||||
#else
|
||||
#ifdef ENABLE_EXECINFO
|
||||
#define MAX_TRACE_SIZE 128
|
||||
void *array[MAX_TRACE_SIZE];
|
||||
size_t size = backtrace(array, MAX_TRACE_SIZE);
|
||||
char **strings = backtrace_symbols(array, size);
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
log_string(log_fd, strings[i]);
|
||||
log_string(log_fd, "\n");
|
||||
}
|
||||
|
||||
free(strings);
|
||||
#endif // ENABLE_EXECINFO
|
||||
#endif // ENABLE_LIBUNWIND
|
||||
#endif // DISABLE_BACKTRACE
|
||||
}
|
||||
|
||||
// sleep() returns early when signals arrive. This function does not.
|
||||
@@ -396,8 +362,12 @@ pid_t tint_exec(const char *command,
|
||||
// Allow children to exist after parent destruction
|
||||
setsid();
|
||||
// Run the command
|
||||
if (dir)
|
||||
chdir(dir);
|
||||
if (dir) {
|
||||
int ret = chdir(dir);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "tint2: failed to chdir to %s\n", dir);
|
||||
}
|
||||
}
|
||||
close_all_fds();
|
||||
reset_signals();
|
||||
if (terminal) {
|
||||
@@ -758,27 +728,60 @@ void render_image(Drawable d, int x, int y)
|
||||
XFreePixmap(server.display, pixmap);
|
||||
}
|
||||
|
||||
void draw_text(PangoLayout *layout, cairo_t *c, int posx, int posy, Color *color, int font_shadow)
|
||||
gboolean is_color_attribute(PangoAttribute *attr, gpointer user_data)
|
||||
{
|
||||
if (font_shadow) {
|
||||
const int shadow_size = 3;
|
||||
const double shadow_edge_alpha = 0.0;
|
||||
int i, j;
|
||||
for (i = -shadow_size; i <= shadow_size; i++) {
|
||||
for (j = -shadow_size; j <= shadow_size; j++) {
|
||||
cairo_set_source_rgba(c,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0 -
|
||||
(1.0 - shadow_edge_alpha) *
|
||||
sqrt((i * i + j * j) / (double)(shadow_size * shadow_size)));
|
||||
pango_cairo_update_layout(c, layout);
|
||||
cairo_move_to(c, posx + i, posy + j);
|
||||
pango_cairo_show_layout(c, layout);
|
||||
}
|
||||
return attr->klass->type == PANGO_ATTR_FOREGROUND ||
|
||||
attr->klass->type == PANGO_ATTR_BACKGROUND ||
|
||||
attr->klass->type == PANGO_ATTR_UNDERLINE_COLOR ||
|
||||
attr->klass->type == PANGO_ATTR_STRIKETHROUGH_COLOR ||
|
||||
attr->klass->type == PANGO_ATTR_FOREGROUND_ALPHA ||
|
||||
attr->klass->type == PANGO_ATTR_BACKGROUND_ALPHA;
|
||||
}
|
||||
|
||||
gboolean layout_set_markup_strip_colors(PangoLayout *layout, const char *markup)
|
||||
{
|
||||
PangoAttrList *attrs = NULL;
|
||||
char *text = NULL;
|
||||
GError *error = NULL;
|
||||
if (!pango_parse_markup(markup, -1, 0, &attrs, &text, NULL, &error)) {
|
||||
g_error_free(error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pango_layout_set_text(layout, text, -1);
|
||||
g_free(text);
|
||||
|
||||
pango_attr_list_filter(attrs, is_color_attribute, NULL);
|
||||
pango_layout_set_attributes(layout, attrs);
|
||||
pango_attr_list_unref(attrs);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void draw_shadow(cairo_t *c, int posx, int posy, PangoLayout *shadow_layout)
|
||||
{
|
||||
const int shadow_size = 3;
|
||||
const double shadow_edge_alpha = 0.0;
|
||||
int i, j;
|
||||
for (i = -shadow_size; i <= shadow_size; i++) {
|
||||
for (j = -shadow_size; j <= shadow_size; j++) {
|
||||
cairo_set_source_rgba(c,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0 -
|
||||
(1.0 - shadow_edge_alpha) *
|
||||
sqrt((i * i + j * j) / (double)(shadow_size * shadow_size)));
|
||||
pango_cairo_update_layout(c, shadow_layout);
|
||||
cairo_move_to(c, posx + i, posy + j);
|
||||
pango_cairo_show_layout(c, shadow_layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void draw_text(PangoLayout *layout, cairo_t *c, int posx, int posy, Color *color, PangoLayout *shadow_layout)
|
||||
{
|
||||
if (shadow_layout)
|
||||
draw_shadow(c, posx, posy, shadow_layout);
|
||||
cairo_set_source_rgba(c, color->rgb[0], color->rgb[1], color->rgb[2], color->alpha);
|
||||
pango_cairo_update_layout(c, layout);
|
||||
cairo_move_to(c, posx, posy);
|
||||
@@ -788,15 +791,15 @@ void draw_text(PangoLayout *layout, cairo_t *c, int posx, int posy, Color *color
|
||||
Imlib_Image load_image(const char *path, int cached)
|
||||
{
|
||||
Imlib_Image image;
|
||||
static unsigned long counter = 0;
|
||||
if (debug_icons)
|
||||
fprintf(stderr, "tint2: loading icon %s\n", path);
|
||||
#ifdef HAVE_RSVG
|
||||
if (cached) {
|
||||
image = imlib_load_image_immediately(path);
|
||||
} else {
|
||||
image = imlib_load_image_immediately_without_cache(path);
|
||||
}
|
||||
image = imlib_load_image(path);
|
||||
if (!image && g_str_has_suffix(path, ".svg")) {
|
||||
char tmp_filename[128];
|
||||
snprintf(tmp_filename, sizeof(tmp_filename), "/tmp/tint2-%d.png", (int)getpid());
|
||||
snprintf(tmp_filename, sizeof(tmp_filename), "/tmp/tint2-%d-%lu.png", (int)getpid(), counter);
|
||||
counter++;
|
||||
int fd = open(tmp_filename, O_CREAT | O_EXCL, 0600);
|
||||
if (fd >= 0) {
|
||||
// We fork here because librsvg allocates memory like crazy
|
||||
@@ -818,19 +821,17 @@ Imlib_Image load_image(const char *path, int cached)
|
||||
// Parent
|
||||
close(fd);
|
||||
waitpid(pid, 0, 0);
|
||||
image = imlib_load_image_immediately_without_cache(tmp_filename);
|
||||
image = imlib_load_image_immediately(tmp_filename);
|
||||
unlink(tmp_filename);
|
||||
}
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (cached) {
|
||||
image = imlib_load_image_immediately(path);
|
||||
} else {
|
||||
image = imlib_load_image_immediately_without_cache(path);
|
||||
}
|
||||
image = imlib_load_image(path);
|
||||
}
|
||||
imlib_context_set_image(image);
|
||||
imlib_image_set_changes_on_disk();
|
||||
return image;
|
||||
}
|
||||
|
||||
@@ -924,30 +925,35 @@ void clear_pixmap(Pixmap p, int x, int y, int w, int h)
|
||||
XRenderFreePicture(server.display, pict);
|
||||
}
|
||||
|
||||
void get_text_size2(const PangoFontDescription *font,
|
||||
int *height_ink,
|
||||
int *height,
|
||||
int *width,
|
||||
int available_height,
|
||||
int available_width,
|
||||
const char *text,
|
||||
int text_len,
|
||||
PangoWrapMode wrap,
|
||||
PangoEllipsizeMode ellipsis,
|
||||
gboolean markup)
|
||||
void get_text_size(const PangoFontDescription *font,
|
||||
int *height,
|
||||
int *width,
|
||||
int available_height,
|
||||
int available_width,
|
||||
const char *text,
|
||||
int text_len,
|
||||
PangoWrapMode wrap,
|
||||
PangoEllipsizeMode ellipsis,
|
||||
PangoAlignment alignment,
|
||||
gboolean markup,
|
||||
double scale)
|
||||
{
|
||||
PangoRectangle rect_ink, rect;
|
||||
|
||||
available_width = MAX(0, available_width);
|
||||
available_height = MAX(0, available_height);
|
||||
|
||||
Pixmap pmap = XCreatePixmap(server.display, server.root_win, available_height, available_width, server.depth);
|
||||
cairo_surface_t *cs =
|
||||
cairo_image_surface_create(CAIRO_FORMAT_ARGB32, available_height, available_width);
|
||||
cairo_xlib_surface_create(server.display, pmap, server.visual, available_height, available_width);
|
||||
cairo_t *c = cairo_create(cs);
|
||||
|
||||
PangoLayout *layout = pango_cairo_create_layout(c);
|
||||
PangoContext *context = pango_cairo_create_context(c);
|
||||
pango_cairo_context_set_resolution(context, 96 * scale);
|
||||
PangoLayout *layout = pango_layout_new(context);
|
||||
pango_layout_set_width(layout, available_width * PANGO_SCALE);
|
||||
pango_layout_set_height(layout, available_height * PANGO_SCALE);
|
||||
pango_layout_set_alignment(layout, alignment);
|
||||
pango_layout_set_wrap(layout, wrap);
|
||||
pango_layout_set_ellipsize(layout, ellipsis);
|
||||
pango_layout_set_font_description(layout, font);
|
||||
@@ -958,14 +964,63 @@ void get_text_size2(const PangoFontDescription *font,
|
||||
pango_layout_set_markup(layout, text, text_len);
|
||||
|
||||
pango_layout_get_pixel_extents(layout, &rect_ink, &rect);
|
||||
*height_ink = rect_ink.height;
|
||||
*height = rect.height;
|
||||
*width = rect.width;
|
||||
|
||||
// fprintf(stderr, "tint2: dimension : %d - %d\n", rect_ink.height, rect.height);
|
||||
|
||||
g_object_unref(layout);
|
||||
g_object_unref(context);
|
||||
cairo_destroy(c);
|
||||
cairo_surface_destroy(cs);
|
||||
XFreePixmap(server.display, pmap);
|
||||
}
|
||||
|
||||
void get_text_size2(const PangoFontDescription *font,
|
||||
int *height,
|
||||
int *width,
|
||||
int available_height,
|
||||
int available_width,
|
||||
const char *text,
|
||||
int text_len,
|
||||
PangoWrapMode wrap,
|
||||
PangoEllipsizeMode ellipsis,
|
||||
PangoAlignment alignment,
|
||||
gboolean markup,
|
||||
double scale)
|
||||
{
|
||||
get_text_size(font, height, width, available_height, available_width, text, text_len, wrap, ellipsis, alignment, markup, scale);
|
||||
|
||||
// We do multiple passes, because pango sucks
|
||||
int actual_height, actual_width, overflow = 0;
|
||||
while (true) {
|
||||
get_text_size(font, &actual_height, &actual_width, *height, *width, text, text_len, wrap, ellipsis, alignment, markup, scale);
|
||||
if (actual_height <= *height)
|
||||
break;
|
||||
if (*width >= available_width)
|
||||
break;
|
||||
overflow = 1;
|
||||
fprintf(stderr, "tint2: text overflows, recomputing: available %dx%d, computed %dx%d, actual %dx%d: %s\n",
|
||||
available_width,
|
||||
available_height,
|
||||
*width,
|
||||
*height,
|
||||
actual_width,
|
||||
actual_height,
|
||||
text);
|
||||
(*width)++;
|
||||
}
|
||||
if (overflow) {
|
||||
*height = actual_height;
|
||||
fprintf(stderr, "tint2: text final size computed as: available %dx%d, computed %dx%d, actual %dx%d: %s\n",
|
||||
available_width,
|
||||
available_height,
|
||||
*width,
|
||||
*height,
|
||||
actual_width,
|
||||
actual_height,
|
||||
text);
|
||||
}
|
||||
}
|
||||
|
||||
#if !GLIB_CHECK_VERSION(2, 34, 0)
|
||||
@@ -1174,3 +1229,19 @@ void dump_image_data(const char *file_name, const char *name)
|
||||
|
||||
imlib_free_image();
|
||||
}
|
||||
|
||||
void draw_cairo_surface_to_xpixmap(cairo_surface_t *cs, Pixmap pix)
|
||||
{
|
||||
int w = cairo_image_surface_get_width(cs);
|
||||
int h = cairo_image_surface_get_height(cs);
|
||||
cairo_surface_t *cs_xlib = cairo_xlib_surface_create(server.display, pix, server.visual, w, h);
|
||||
cairo_xlib_surface_set_size(cs_xlib, w, h);
|
||||
cairo_t *c_xlib = cairo_create(cs_xlib);
|
||||
|
||||
cairo_set_source_surface(c_xlib, cs, 0, 0);
|
||||
cairo_paint(c_xlib);
|
||||
cairo_surface_flush(cs_xlib);
|
||||
|
||||
cairo_destroy(c_xlib);
|
||||
cairo_surface_destroy(cs_xlib);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#define COMMON_H
|
||||
|
||||
#define WM_CLASS_TINT "panel"
|
||||
#define TINT2_PANGO_SLACK 0
|
||||
|
||||
#include <glib.h>
|
||||
#include <Imlib2.h>
|
||||
@@ -113,7 +114,6 @@ void create_heuristic_mask(DATA32 *data, int w, int h);
|
||||
void render_image(Drawable d, int x, int y);
|
||||
|
||||
void get_text_size2(const PangoFontDescription *font,
|
||||
int *height_ink,
|
||||
int *height,
|
||||
int *width,
|
||||
int available_height,
|
||||
@@ -122,9 +122,12 @@ void get_text_size2(const PangoFontDescription *font,
|
||||
int text_len,
|
||||
PangoWrapMode wrap,
|
||||
PangoEllipsizeMode ellipsis,
|
||||
gboolean markup);
|
||||
PangoAlignment alignment,
|
||||
gboolean markup,
|
||||
double scale);
|
||||
|
||||
void draw_text(PangoLayout *layout, cairo_t *c, int posx, int posy, Color *color, int font_shadow);
|
||||
gboolean layout_set_markup_strip_colors(PangoLayout *layout, const char *markup);
|
||||
void draw_text(PangoLayout *layout, cairo_t *c, int posx, int posy, Color *color, PangoLayout *shadow_layout);
|
||||
|
||||
// Draws a rounded rectangle
|
||||
void draw_rect(cairo_t *c, double x, double y, double w, double h, double r);
|
||||
@@ -151,6 +154,8 @@ void get_image_mean_color(const Imlib_Image image, Color *mean_color);
|
||||
|
||||
void dump_image_data(const char *file_name, const char *name);
|
||||
|
||||
void draw_cairo_surface_to_xpixmap(cairo_surface_t *cs, Pixmap pix);
|
||||
|
||||
#define free_and_null(p) \
|
||||
{ \
|
||||
free(p); \
|
||||
|
||||
331
src/util/mem.c
Normal file
331
src/util/mem.c
Normal file
@@ -0,0 +1,331 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <dlfcn.h>
|
||||
#include <endian.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <limits.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "bt.h"
|
||||
#include "bool.h"
|
||||
|
||||
#define UNUSED(x) ((void)x)
|
||||
|
||||
void ERR(const char *s)
|
||||
{
|
||||
if (!s) {
|
||||
ERR("(null)");
|
||||
return;
|
||||
}
|
||||
ssize_t ret = write(STDERR_FILENO, s, strlen(s));
|
||||
UNUSED(ret);
|
||||
ret = fsync(STDERR_FILENO);
|
||||
UNUSED(ret);
|
||||
}
|
||||
|
||||
void utoa(unsigned long n, char *s)
|
||||
{
|
||||
if (n == 0) {
|
||||
*s++ = '0';
|
||||
*s = 0;
|
||||
return;
|
||||
}
|
||||
char buffer[128] = {0};
|
||||
char *digit;
|
||||
for (digit = buffer; n; digit++, n/=10) {
|
||||
*digit = '0' + (n % 10);
|
||||
}
|
||||
digit--;
|
||||
while (digit >= buffer) {
|
||||
*s++ = *digit--;
|
||||
}
|
||||
*s = 0;
|
||||
}
|
||||
|
||||
unsigned long uabs(long n)
|
||||
{
|
||||
if (n == LONG_MIN)
|
||||
return ((unsigned long)LONG_MAX) + 1;
|
||||
return (unsigned long)labs(n);
|
||||
}
|
||||
|
||||
void itoa(long n, char *s)
|
||||
{
|
||||
if (n < 0) {
|
||||
*s++ = '-';
|
||||
}
|
||||
utoa(uabs(n), s);
|
||||
}
|
||||
|
||||
__attribute__((noreturn))
|
||||
static void crash(char *file, int line, char *msg)
|
||||
{
|
||||
ERR(file);
|
||||
ERR(":");
|
||||
char buf[256];
|
||||
itoa(line, buf);
|
||||
ERR(buf);
|
||||
ERR(" ");
|
||||
ERR(msg);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
#define ASSERT_OK(call) if (0 != (call)) crash(__FILE__, __LINE__, #call)
|
||||
#define ASSERT_FD(fd) if ((fd) == -1) crash(__FILE__, __LINE__, "bad file descriptor")
|
||||
#define ASSERT_PID(pid) if ((pid) == -1) crash(__FILE__, __LINE__, "bad PID")
|
||||
#define ASSERT(b) if (!(b)) crash(__FILE__, __LINE__, "assert failed")
|
||||
|
||||
void *return_null(void *x, void *y)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void load_func_or_crash(void **result, const char *name)
|
||||
{
|
||||
static int inside_loader = 0;
|
||||
if (inside_loader) {
|
||||
*result = (void*)return_null;
|
||||
return;
|
||||
} else if (*result == (void*)return_null) {
|
||||
*result = 0;
|
||||
}
|
||||
if (*result)
|
||||
return;
|
||||
dlerror();
|
||||
inside_loader++;
|
||||
*result = dlsym(RTLD_NEXT, name);
|
||||
inside_loader--;
|
||||
char *err = dlerror();
|
||||
if (err) {
|
||||
ERR("Failed to load ");
|
||||
ERR(name);
|
||||
ERR(" error: ");
|
||||
ERR(err);
|
||||
ERR("\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static int fd = -1;
|
||||
static u_int64_t tstart = 0;
|
||||
static bool stop_alloc_log = false;
|
||||
|
||||
static void write_char(char c)
|
||||
{
|
||||
static char buffer[4096] = {0};
|
||||
static size_t count = 0;
|
||||
if (c) {
|
||||
buffer[count++] = c;
|
||||
}
|
||||
if (!count)
|
||||
return;
|
||||
if (c == '\n' || c == 0 || count >= sizeof(buffer)) {
|
||||
ssize_t ret = write(fd, buffer, count);
|
||||
ASSERT(ret > 0);
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void write_string(const char *s)
|
||||
{
|
||||
for (; *s; s++)
|
||||
write_char(*s);
|
||||
}
|
||||
|
||||
static void write_word(const char *s)
|
||||
{
|
||||
write_string(s);
|
||||
write_string(" ");
|
||||
}
|
||||
|
||||
static char hex(u_int8_t value)
|
||||
{
|
||||
if (value < 10)
|
||||
return '0' + (char)value;
|
||||
return 'a' + (char)(value - 10);
|
||||
}
|
||||
|
||||
static void write_hex(u_int64_t v)
|
||||
{
|
||||
write_string("0x");
|
||||
if (!v) {
|
||||
write_string("0 ");
|
||||
return;
|
||||
}
|
||||
v = htobe64(v);
|
||||
int leading_zero = 1;
|
||||
while (v) {
|
||||
u_int8_t byte = v & 0xff;
|
||||
if (byte)
|
||||
leading_zero = 0;
|
||||
if (!leading_zero) {
|
||||
write_char(hex(byte >> 4));
|
||||
write_char(hex(byte & 0xf));
|
||||
}
|
||||
v = v >> 8;
|
||||
}
|
||||
write_string(" ");
|
||||
}
|
||||
|
||||
static void write_backtrace(int skip)
|
||||
{
|
||||
struct backtrace bt;
|
||||
get_backtrace(&bt, skip + 1);
|
||||
for (size_t i = 0; i < bt.frame_count; i++) {
|
||||
write_word(bt.frames[i].name);
|
||||
}
|
||||
}
|
||||
|
||||
static void log_alloc_finish(void);
|
||||
|
||||
static u_int64_t current_time_ms()
|
||||
{
|
||||
struct timespec t = {0, 0};
|
||||
clock_gettime(CLOCK_MONOTONIC, &t);
|
||||
u_int64_t result = t.tv_sec * 1000 + t.tv_nsec / 1000 / 1000;
|
||||
return result;
|
||||
}
|
||||
|
||||
static void log_alloc_init(u_int64_t t)
|
||||
{
|
||||
if (stop_alloc_log)
|
||||
return;
|
||||
if (fd == -1) {
|
||||
int pfd[2] = {-1, -1};
|
||||
ASSERT_OK(pipe(pfd));
|
||||
pid_t child = fork();
|
||||
ASSERT_PID(child);
|
||||
if (child == 0) {
|
||||
// child
|
||||
close(pfd[1]);
|
||||
ASSERT_FD(dup2(pfd[0], STDIN_FILENO));
|
||||
ASSERT_OK(close(pfd[0]));
|
||||
int out = open("mem.log.gz", O_APPEND | O_CLOEXEC | O_CREAT | O_WRONLY | O_TRUNC, 0600);
|
||||
ASSERT_FD(out);
|
||||
ASSERT_FD(dup2(out, STDOUT_FILENO));
|
||||
sigset_t mask;
|
||||
sigfillset(&mask);
|
||||
sigprocmask(SIG_SETMASK, &mask, NULL);
|
||||
ASSERT_OK(execlp("gzip", "gzip", "-c", NULL));
|
||||
_exit(1);
|
||||
} else {
|
||||
// parent
|
||||
close(pfd[0]);
|
||||
fd = pfd[1];
|
||||
}
|
||||
atexit(log_alloc_finish);
|
||||
tstart = t;
|
||||
write_string("# function time_ms result ptr size count backtrace\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void log_alloc_locked(const char *func_name, void *result, void *ptr, size_t size, size_t count)
|
||||
{
|
||||
if (stop_alloc_log)
|
||||
return;
|
||||
u_int64_t t = current_time_ms();
|
||||
if (fd == -1)
|
||||
log_alloc_init(t);
|
||||
if (fd == -1)
|
||||
return;
|
||||
if (func_name) {
|
||||
write_word(func_name);
|
||||
write_hex((u_int64_t)(t - tstart));
|
||||
write_hex((u_int64_t)result);
|
||||
write_hex((u_int64_t)ptr);
|
||||
write_hex((u_int64_t)size);
|
||||
write_hex((u_int64_t)count);
|
||||
write_backtrace(2);
|
||||
write_string("\n");
|
||||
} else {
|
||||
write_string("# done\n");
|
||||
close(fd);
|
||||
fd = -1;
|
||||
stop_alloc_log = true;
|
||||
}
|
||||
}
|
||||
|
||||
static int pid = -1;
|
||||
static void log_alloc(const char *func_name, void *result, void *ptr, size_t size, size_t count)
|
||||
{
|
||||
static pthread_mutex_t mutex_global = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_mutex_t mutex_recursive;
|
||||
static pthread_mutex_t mutex_nonrecursive = PTHREAD_MUTEX_INITIALIZER;
|
||||
static bool mutexes_initialized = false;
|
||||
|
||||
pthread_mutex_lock(&mutex_global);
|
||||
{
|
||||
if (!mutexes_initialized) {
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
pthread_mutex_init(&mutex_recursive, &attr);
|
||||
mutexes_initialized = true;
|
||||
pid = getpid();
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&mutex_global);
|
||||
|
||||
// Do not log from forked processes.
|
||||
if (pid != getpid())
|
||||
return;
|
||||
|
||||
pthread_mutex_lock(&mutex_recursive);
|
||||
int ret = pthread_mutex_trylock(&mutex_nonrecursive);
|
||||
if (ret == 0) {
|
||||
log_alloc_locked(func_name, result, ptr, size, count);
|
||||
pthread_mutex_unlock(&mutex_nonrecursive);
|
||||
}
|
||||
pthread_mutex_unlock(&mutex_recursive);
|
||||
}
|
||||
|
||||
static void log_alloc_finish()
|
||||
{
|
||||
log_alloc(0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void *malloc(size_t size)
|
||||
{
|
||||
static void *(*original)(size_t size) = 0;
|
||||
load_func_or_crash((void *)&original, __FUNCTION__);
|
||||
void *result = original(size);
|
||||
log_alloc(__FUNCTION__, result, 0, size, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
void *realloc(void *ptr, size_t size)
|
||||
{
|
||||
static void *(*original)(void *p, size_t size) = 0;
|
||||
load_func_or_crash((void *)&original, __FUNCTION__);
|
||||
void *result = original(ptr, size);
|
||||
log_alloc(__FUNCTION__, result, ptr, size, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
void *calloc(size_t nmemb, size_t size)
|
||||
{
|
||||
static void *(*original)(size_t nmemb, size_t size) = 0;
|
||||
load_func_or_crash((void *)&original, __FUNCTION__);
|
||||
void *result = original(nmemb, size);
|
||||
log_alloc(__FUNCTION__, result, 0, size, nmemb);
|
||||
return result;
|
||||
}
|
||||
|
||||
void free(void *ptr)
|
||||
{
|
||||
static void *(*original)(void *p) = 0;
|
||||
load_func_or_crash((void *)&original, __FUNCTION__);
|
||||
if (!original) {
|
||||
return;
|
||||
}
|
||||
original(ptr);
|
||||
log_alloc(__FUNCTION__, 0, ptr, 0, 0);
|
||||
}
|
||||
@@ -19,11 +19,11 @@
|
||||
**************************************************************************/
|
||||
|
||||
#include <X11/extensions/Xdamage.h>
|
||||
#include <X11/extensions/Xrender.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#include <X11/extensions/Xrender.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
@@ -36,8 +36,9 @@
|
||||
|
||||
Server server;
|
||||
|
||||
void server_catch_error(Display *d, XErrorEvent *ev)
|
||||
int server_catch_error(Display *d, XErrorEvent *ev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void server_init_atoms()
|
||||
@@ -311,6 +312,21 @@ void sort_monitors()
|
||||
qsort(server.monitors, server.num_monitors, sizeof(Monitor), compare_monitor_pos);
|
||||
}
|
||||
|
||||
int compute_dpi(XRRCrtcInfo *crtc, XRROutputInfo *output)
|
||||
{
|
||||
double width = output->mm_width;
|
||||
double height = output->mm_height;
|
||||
double x_res = crtc->width;
|
||||
double y_res = crtc->height;
|
||||
|
||||
if (width > 0 && height > 0) {
|
||||
int dpi_x = x_res / width * 25.4;
|
||||
int dpi_y = y_res / height * 25.4;
|
||||
return MAX(dpi_x, dpi_y);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void get_monitors()
|
||||
{
|
||||
if (XineramaIsActive(server.display)) {
|
||||
@@ -339,12 +355,22 @@ void get_monitors()
|
||||
server.monitors[i_monitor].width = crtc_info->width;
|
||||
server.monitors[i_monitor].height = crtc_info->height;
|
||||
server.monitors[i_monitor].names = calloc((crtc_info->noutput + 1), sizeof(gchar *));
|
||||
server.monitors[i_monitor].dpi = 96;
|
||||
for (int j = 0; j < crtc_info->noutput; ++j) {
|
||||
XRROutputInfo *output_info = XRRGetOutputInfo(server.display, res, crtc_info->outputs[j]);
|
||||
fprintf(stderr, "tint2: xRandr: Linking output %s with crtc %d\n", output_info->name, i);
|
||||
server.monitors[i_monitor].names[j] = g_strdup(output_info->name);
|
||||
XRRFreeOutputInfo(output_info);
|
||||
server.monitors[i_monitor].primary = crtc_info->outputs[j] == primary_output;
|
||||
int dpi = compute_dpi(crtc_info, output_info);
|
||||
if (dpi)
|
||||
server.monitors[i_monitor].dpi = dpi;
|
||||
fprintf(stderr,
|
||||
BLUE "tint2: xRandr: Linking output %s with crtc %d, resolution %dx%d, DPI %d" RESET "\n",
|
||||
output_info->name,
|
||||
i,
|
||||
server.monitors[i_monitor].width,
|
||||
server.monitors[i_monitor].height,
|
||||
server.monitors[i_monitor].dpi);
|
||||
XRRFreeOutputInfo(output_info);
|
||||
}
|
||||
server.monitors[i_monitor].names[crtc_info->noutput] = NULL;
|
||||
XRRFreeCrtcInfo(crtc_info);
|
||||
@@ -357,6 +383,7 @@ void get_monitors()
|
||||
server.monitors[i].width = info[i].width;
|
||||
server.monitors[i].height = info[i].height;
|
||||
server.monitors[i].names = NULL;
|
||||
server.monitors[i].dpi = 96;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,6 +420,7 @@ void get_monitors()
|
||||
server.monitors[0].width = DisplayWidth(server.display, server.screen);
|
||||
server.monitors[0].height = DisplayHeight(server.display, server.screen);
|
||||
server.monitors[0].names = 0;
|
||||
server.monitors[0].dpi = 96;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,7 +551,8 @@ int get_current_desktop()
|
||||
// fprintf(stderr, "tint2: \n");
|
||||
// fprintf(stderr, "tint2: Work area size: %d x %d\n", work_area_width, work_area_height);
|
||||
// fprintf(stderr, "tint2: Viewport pos: %d x %d\n", viewport_x, viewport_y);
|
||||
// fprintf(stderr, "tint2: Viewport i: %d\n", (viewport_y / work_area_height) * ncols + viewport_x / work_area_width);
|
||||
// fprintf(stderr, "tint2: Viewport i: %d\n", (viewport_y / work_area_height) * ncols + viewport_x /
|
||||
//work_area_width);
|
||||
|
||||
int result = (viewport_y / work_area_height) * ncols + viewport_x / work_area_width;
|
||||
return MAX(0, MIN(server.num_desktops - 1, result));
|
||||
@@ -648,9 +677,10 @@ void handle_crash(const char *reason)
|
||||
#endif
|
||||
}
|
||||
|
||||
void x11_io_error(Display *display)
|
||||
int x11_io_error(Display *display)
|
||||
{
|
||||
handle_crash("X11 I/O error");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SN
|
||||
|
||||
@@ -107,6 +107,7 @@ typedef struct Monitor {
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
int dpi;
|
||||
gboolean primary;
|
||||
gchar **names;
|
||||
} Monitor;
|
||||
@@ -163,12 +164,12 @@ void send_event32(Window win, Atom at, long data1, long data2, long data3);
|
||||
int get_property32(Window win, Atom at, Atom type);
|
||||
void *server_get_property(Window win, Atom at, Atom type, int *num_results);
|
||||
Atom server_get_atom(char *atom_name);
|
||||
void server_catch_error(Display *d, XErrorEvent *ev);
|
||||
int server_catch_error(Display *d, XErrorEvent *ev);
|
||||
void server_init_atoms();
|
||||
void server_init_visual();
|
||||
void server_init_xdamage();
|
||||
|
||||
void x11_io_error(Display *display);
|
||||
int x11_io_error(Display *display);
|
||||
void handle_crash(const char *reason);
|
||||
|
||||
// detect root background
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "timer.h"
|
||||
#include "test.h"
|
||||
|
||||
bool warnings_for_timers = true;
|
||||
bool debug_timers = false;
|
||||
#define MOCK_ORIGIN 1000000
|
||||
|
||||
@@ -59,7 +60,7 @@ void init_timer(Timer *timer, const char *name)
|
||||
|
||||
void destroy_timer(Timer *timer)
|
||||
{
|
||||
if (!g_list_find(timers, timer)) {
|
||||
if (warnings_for_timers && !g_list_find(timers, timer)) {
|
||||
fprintf(stderr, RED "tint2: Attempt to destroy nonexisting timer: %s" RESET "\n", timer->name_);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <sys/time.h>
|
||||
#include "bool.h"
|
||||
|
||||
extern bool warnings_for_timers;
|
||||
extern bool debug_timers;
|
||||
|
||||
typedef void TimerCallback(void *arg);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/extensions/Xrender.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -383,28 +384,42 @@ void smooth_thumbnail(cairo_surface_t *image_surface)
|
||||
}
|
||||
}
|
||||
|
||||
// This is measured to be slightly faster.
|
||||
#define GetPixel(ximg, x, y) ((u_int32_t *)&(ximg->data[y * ximg->bytes_per_line]))[x]
|
||||
//#define GetPixel XGetPixel
|
||||
// This is measured to be slightly faster than XGetPixel.
|
||||
static u_int32_t GetPixel(XImage *ximg, unsigned x, unsigned y)
|
||||
{
|
||||
if (x >= ximg->width || y >= ximg->height) {
|
||||
fprintf(stderr, RED "GetPixel read overflow: %u %u %d %d\n",
|
||||
x, y, ximg->width, ximg->height);
|
||||
return 0;
|
||||
}
|
||||
return ((u_int32_t *)&(ximg->data[y * ximg->bytes_per_line]))[x];
|
||||
}
|
||||
|
||||
// TODO: the xrender method only works well if there is a compositor running
|
||||
cairo_surface_t *get_window_thumbnail_ximage(Window win, size_t size, gboolean use_shm)
|
||||
{
|
||||
fprintf(stderr, GREEN "tint2: win=%u: getting thumbnail of size %u" RESET "\n", win, size);
|
||||
cairo_surface_t *result = NULL;
|
||||
XWindowAttributes wa;
|
||||
if (!XGetWindowAttributes(server.display, win, &wa) || wa.width <= 0 || wa.height <= 0 ||
|
||||
wa.map_state != IsViewable)
|
||||
wa.map_state != IsViewable) {
|
||||
fprintf(stderr, YELLOW "tint2: win=%u: no win attributes" RESET "\n", win);
|
||||
goto err0;
|
||||
}
|
||||
|
||||
if (window_is_iconified(win))
|
||||
if (window_is_iconified(win)) {
|
||||
fprintf(stderr, YELLOW "tint2: win=%u: no thumbnail for minimized window" RESET "\n", win);
|
||||
goto err0;
|
||||
}
|
||||
|
||||
size_t w, h;
|
||||
w = (size_t)wa.width;
|
||||
h = (size_t)wa.height;
|
||||
w = (size_t)wa.width + wa.x;
|
||||
h = (size_t)wa.height + wa.y;
|
||||
size_t tw, th, fw;
|
||||
size_t ox, oy;
|
||||
tw = size;
|
||||
th = h * tw / w;
|
||||
double scale = th / (double)h;
|
||||
if (th > tw * 0.618) {
|
||||
th = (size_t)(tw * 0.618);
|
||||
fw = w * th / h;
|
||||
@@ -414,20 +429,69 @@ cairo_surface_t *get_window_thumbnail_ximage(Window win, size_t size, gboolean u
|
||||
fw = tw;
|
||||
ox = oy = 0;
|
||||
}
|
||||
if (!w || !h || !tw || !th || !fw) {
|
||||
fprintf(stderr, YELLOW "tint2: win=%u: no thumbnail for size 0x0" RESET "\n", win);
|
||||
goto err0;
|
||||
}
|
||||
|
||||
XShmSegmentInfo shminfo;
|
||||
XImage *ximg;
|
||||
if (use_shm)
|
||||
ximg = XShmCreateImage(server.display,
|
||||
wa.visual,
|
||||
(unsigned)wa.depth,
|
||||
ZPixmap,
|
||||
NULL,
|
||||
&shminfo,
|
||||
(unsigned)w,
|
||||
(unsigned)h);
|
||||
else
|
||||
ximg = XGetImage(server.display, win, 0, 0, (unsigned)w, (unsigned)h, AllPlanes, ZPixmap);
|
||||
XImage *ximg = NULL;
|
||||
|
||||
XGetWindowAttributes(server.display, win, &wa);
|
||||
if (wa.map_state != IsViewable) {
|
||||
fprintf(stderr, YELLOW "tint2: win=%u: no thumbnail for non-viewable window" RESET "\n", win);
|
||||
goto err4;
|
||||
}
|
||||
|
||||
Pixmap pix = XCreatePixmap(server.display, win, tw, th, wa.depth);
|
||||
if (!pix) {
|
||||
fprintf(stderr, YELLOW "tint2: win=%u: no pixmap" RESET "\n", win);
|
||||
goto err4;
|
||||
}
|
||||
XRenderPictureAttributes attrs = {
|
||||
.repeat = RepeatNone
|
||||
};
|
||||
XRenderPictFormat *fmt = XRenderFindVisualFormat(server.display, wa.visual);
|
||||
if (!fmt) {
|
||||
fprintf(stderr, YELLOW "tint2: win=%u: no XRender format" RESET "\n", win);
|
||||
goto err4;
|
||||
}
|
||||
Picture src_pic = XRenderCreatePicture(server.display, win, fmt, CPRepeat, &attrs);
|
||||
if (!src_pic) {
|
||||
fprintf(stderr, YELLOW "tint2: win=%u: no src picture" RESET "\n", win);
|
||||
goto err4;
|
||||
}
|
||||
Picture dst_pic = XRenderCreatePicture(server.display, pix, fmt, CPRepeat, &attrs);
|
||||
if (!dst_pic) {
|
||||
fprintf(stderr, YELLOW "tint2: win=%u: no src picture" RESET "\n", win);
|
||||
goto err4;
|
||||
}
|
||||
fprintf(stderr, GREEN "tint2: win=%u: transformation %u %u %f xy %d %d" RESET "\n", win, ox, oy, scale,
|
||||
wa.x, wa.y);
|
||||
XTransform transform = {
|
||||
{
|
||||
{
|
||||
XDoubleToFixed(1./scale),
|
||||
XDoubleToFixed(0),
|
||||
XDoubleToFixed(ox-wa.x/scale)
|
||||
},
|
||||
{
|
||||
XDoubleToFixed(0),
|
||||
XDoubleToFixed(1./scale),
|
||||
XDoubleToFixed(oy-wa.y/scale)
|
||||
},
|
||||
{
|
||||
XDoubleToFixed(0),
|
||||
XDoubleToFixed(0),
|
||||
XDoubleToFixed(1)
|
||||
}
|
||||
}
|
||||
};
|
||||
XRenderSetPictureTransform(server.display, src_pic, &transform);
|
||||
XRenderSetPictureFilter(server.display, src_pic, FilterBilinear, NULL, 0);
|
||||
XRenderComposite(server.display, PictOpSrc, src_pic, None, dst_pic, 0, 0, 0, 0, 0, 0, w, h);
|
||||
XSync(server.display, False);
|
||||
|
||||
ximg = XGetImage(server.display, pix, 0, 0, (unsigned)tw, (unsigned)th, AllPlanes, ZPixmap);
|
||||
if (!ximg) {
|
||||
fprintf(stderr, RED "tint2: !ximg" RESET "\n");
|
||||
goto err0;
|
||||
@@ -436,87 +500,32 @@ cairo_surface_t *get_window_thumbnail_ximage(Window win, size_t size, gboolean u
|
||||
fprintf(stderr, RED "tint2: unusual bits_per_pixel" RESET "\n");
|
||||
goto err1;
|
||||
}
|
||||
if (use_shm) {
|
||||
shminfo.shmid = shmget(IPC_PRIVATE, (size_t)(ximg->bytes_per_line * ximg->height), IPC_CREAT | 0777);
|
||||
if (shminfo.shmid < 0) {
|
||||
fprintf(stderr, RED "tint2: !shmget" RESET "\n");
|
||||
goto err1;
|
||||
}
|
||||
shminfo.shmaddr = ximg->data = (char *)shmat(shminfo.shmid, 0, 0);
|
||||
if (!shminfo.shmaddr) {
|
||||
fprintf(stderr, RED "tint2: !shmat" RESET "\n");
|
||||
goto err2;
|
||||
}
|
||||
shminfo.readOnly = False;
|
||||
if (!XShmAttach(server.display, &shminfo)) {
|
||||
fprintf(stderr, RED "tint2: !xshmattach" RESET "\n");
|
||||
goto err3;
|
||||
}
|
||||
if (!XShmGetImage(server.display, win, ximg, 0, 0, AllPlanes)) {
|
||||
fprintf(stderr, RED "tint2: !xshmgetimage" RESET "\n");
|
||||
goto err4;
|
||||
}
|
||||
}
|
||||
|
||||
XGetWindowAttributes(server.display, win, &wa);
|
||||
if (wa.map_state != IsViewable)
|
||||
goto err4;
|
||||
|
||||
fprintf(stderr, GREEN "tint2: creating image surface %ux%u" RESET "\n", tw, th);
|
||||
result = cairo_image_surface_create(CAIRO_FORMAT_RGB24, (int)tw, (int)th);
|
||||
u_int32_t *data = (u_int32_t *)cairo_image_surface_get_data(result);
|
||||
memset(data, 0, tw * th);
|
||||
|
||||
// Fixed-point precision
|
||||
const size_t prec = 1 << 16;
|
||||
const size_t xstep = w * prec / fw;
|
||||
const size_t ystep = h * prec / th;
|
||||
|
||||
const size_t offset_y1 = 0 * ystep / 8;
|
||||
const size_t offset_x1 = 3 * xstep / 8;
|
||||
|
||||
const size_t offset_y2 = 1 * ystep / 8;
|
||||
const size_t offset_x2 = 6 * xstep / 8;
|
||||
|
||||
const size_t offset_y3 = 4 * ystep / 8;
|
||||
const size_t offset_x3 = 2 * xstep / 8;
|
||||
|
||||
const size_t offset_y4 = 4 * ystep / 8;
|
||||
const size_t offset_x4 = 4 * xstep / 8;
|
||||
|
||||
const size_t offset_y5 = 4 * ystep / 8;
|
||||
const size_t offset_x5 = 7 * xstep / 8;
|
||||
|
||||
const size_t offset_y6 = 6 * ystep / 8;
|
||||
const size_t offset_x6 = 1 * xstep / 8;
|
||||
|
||||
const size_t offset_y7 = 7 * ystep / 8;
|
||||
const size_t offset_x7 = 6 * xstep / 8;
|
||||
|
||||
const u_int32_t rmask = (u_int32_t)ximg->red_mask;
|
||||
const u_int32_t gmask = (u_int32_t)ximg->green_mask;
|
||||
const u_int32_t bmask = (u_int32_t)ximg->blue_mask;
|
||||
for (size_t yt = 0, y = 0; yt < th; yt++, y += ystep) {
|
||||
for (size_t xt = 0, x = 0; xt < fw; xt++, x += xstep) {
|
||||
size_t j = yt * tw + ox + xt;
|
||||
u_int32_t c1 = (u_int32_t)GetPixel(ximg, (int)((x + offset_x1) / prec), (int)((y + offset_y1) / prec));
|
||||
u_int32_t c2 = (u_int32_t)GetPixel(ximg, (int)((x + offset_x2) / prec), (int)((y + offset_y2) / prec));
|
||||
u_int32_t c3 = (u_int32_t)GetPixel(ximg, (int)((x + offset_x3) / prec), (int)((y + offset_y3) / prec));
|
||||
u_int32_t c4 = (u_int32_t)GetPixel(ximg, (int)((x + offset_x4) / prec), (int)((y + offset_y4) / prec));
|
||||
u_int32_t c5 = (u_int32_t)GetPixel(ximg, (int)((x + offset_x5) / prec), (int)((y + offset_y5) / prec));
|
||||
u_int32_t c6 = (u_int32_t)GetPixel(ximg, (int)((x + offset_x6) / prec), (int)((y + offset_y6) / prec));
|
||||
u_int32_t c7 = (u_int32_t)GetPixel(ximg, (int)((x + offset_x7) / prec), (int)((y + offset_y7) / prec));
|
||||
u_int32_t b = ((c1 & bmask) + (c2 & bmask) + (c3 & bmask) + (c4 & bmask) + (c5 & bmask) * 2 + (c6 & bmask) +
|
||||
(c7 & bmask)) /
|
||||
8;
|
||||
u_int32_t g = ((c1 & gmask) + (c2 & gmask) + (c3 & gmask) + (c4 & gmask) + (c5 & gmask) * 2 + (c6 & gmask) +
|
||||
(c7 & gmask)) /
|
||||
8;
|
||||
u_int32_t r = ((c1 & rmask) + (c2 & rmask) + (c3 & rmask) + (c4 & rmask) + (c5 & rmask) * 2 + (c6 & rmask) +
|
||||
(c7 & rmask)) /
|
||||
8;
|
||||
data[j] = (r & rmask) | (g & gmask) | (b & bmask);
|
||||
for (size_t y = 0; y < th; y++) {
|
||||
for (size_t x = 0; x < tw; x++) {
|
||||
u_int32_t c = (u_int32_t)XGetPixel(ximg, x, y);
|
||||
data[y * tw + x] = c;
|
||||
}
|
||||
}
|
||||
|
||||
imlib_context_set_drawable(pix);
|
||||
Imlib_Image img = imlib_create_image_from_drawable(0, 0, 0, tw, th, 1);
|
||||
//Imlib_Image img = imlib_create_image_using_data(tw, th, data);
|
||||
imlib_context_set_image(img);
|
||||
char path[256];
|
||||
static unsigned count = 0;
|
||||
sprintf(path, "thumb-%u-%u.png", win, count++);
|
||||
imlib_save_image(path);
|
||||
imlib_free_image();
|
||||
|
||||
// Convert to argb32
|
||||
if (rmask & 0xff0000) {
|
||||
// argb32 or rgb24 => Nothing to do
|
||||
@@ -539,24 +548,23 @@ cairo_surface_t *get_window_thumbnail_ximage(Window win, size_t size, gboolean u
|
||||
}
|
||||
|
||||
// 2nd pass
|
||||
smooth_thumbnail(result);
|
||||
//smooth_thumbnail(result);
|
||||
cairo_surface_flush(result);
|
||||
|
||||
if (ximg) {
|
||||
XDestroyImage(ximg);
|
||||
ximg = NULL;
|
||||
}
|
||||
err4:
|
||||
if (use_shm)
|
||||
XShmDetach(server.display, &shminfo);
|
||||
err3:
|
||||
if (use_shm)
|
||||
shmdt(shminfo.shmaddr);
|
||||
err2:
|
||||
if (use_shm)
|
||||
shmctl(shminfo.shmid, IPC_RMID, NULL);
|
||||
err1:
|
||||
err4:
|
||||
if (ximg)
|
||||
XDestroyImage(ximg);
|
||||
if (src_pic)
|
||||
XRenderFreePicture(server.display, src_pic);
|
||||
if (dst_pic)
|
||||
XRenderFreePicture(server.display, dst_pic);
|
||||
if (pix)
|
||||
XFreePixmap(server.display, pix);
|
||||
err0:
|
||||
return result;
|
||||
}
|
||||
@@ -576,24 +584,11 @@ gboolean cairo_surface_is_blank(cairo_surface_t *image_surface)
|
||||
cairo_surface_t *get_window_thumbnail(Window win, int size)
|
||||
{
|
||||
cairo_surface_t *image_surface = NULL;
|
||||
const gboolean shm_allowed = FALSE;
|
||||
if (shm_allowed && server.has_shm && server.composite_manager) {
|
||||
image_surface = get_window_thumbnail_ximage(win, (size_t)size, TRUE);
|
||||
if (image_surface && cairo_surface_is_blank(image_surface)) {
|
||||
cairo_surface_destroy(image_surface);
|
||||
image_surface = NULL;
|
||||
}
|
||||
if (debug_thumbnails) {
|
||||
if (!image_surface)
|
||||
fprintf(stderr, YELLOW "tint2: XShmGetImage failed, trying slower method" RESET "\n");
|
||||
else
|
||||
fprintf(stderr, "tint2: captured window using XShmGetImage\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!image_surface) {
|
||||
image_surface = get_window_thumbnail_ximage(win, (size_t)size, FALSE);
|
||||
if (image_surface && cairo_surface_is_blank(image_surface)) {
|
||||
fprintf(stderr, RED "tint2: captured blank thumbnail" RESET "\n");
|
||||
cairo_surface_destroy(image_surface);
|
||||
image_surface = NULL;
|
||||
}
|
||||
|
||||
@@ -201,7 +201,7 @@ clock_dwheel_command =
|
||||
# Battery
|
||||
battery_tooltip = 1
|
||||
battery_low_status = 10
|
||||
battery_low_cmd = notify-send "battery low"
|
||||
battery_low_cmd = xmessage 'tint2: Battery low!'
|
||||
battery_full_cmd =
|
||||
bat1_font = sans 8
|
||||
bat2_font = sans 6
|
||||
|
||||
@@ -201,7 +201,7 @@ clock_dwheel_command =
|
||||
# Battery
|
||||
battery_tooltip = 1
|
||||
battery_low_status = 10
|
||||
battery_low_cmd = notify-send "battery low"
|
||||
battery_low_cmd = xmessage 'tint2: Battery low!'
|
||||
battery_full_cmd =
|
||||
bat1_font = sans 8
|
||||
bat2_font = sans 6
|
||||
|
||||
@@ -212,7 +212,7 @@ clock_dwheel_command =
|
||||
# Battery
|
||||
battery_tooltip = 1
|
||||
battery_low_status = 10
|
||||
battery_low_cmd = notify-send "battery low"
|
||||
battery_low_cmd = xmessage 'tint2: Battery low!'
|
||||
battery_full_cmd =
|
||||
bat1_font = sans 8
|
||||
bat2_font = sans 6
|
||||
|
||||
@@ -201,7 +201,7 @@ clock_dwheel_command =
|
||||
# Battery
|
||||
battery_tooltip = 1
|
||||
battery_low_status = 10
|
||||
battery_low_cmd = notify-send "battery low"
|
||||
battery_low_cmd = xmessage 'tint2: Battery low!'
|
||||
battery_full_cmd =
|
||||
bat1_font = sans 8
|
||||
bat2_font = sans 6
|
||||
|
||||
@@ -175,7 +175,7 @@ clock_dwheel_command =
|
||||
# Battery
|
||||
battery_tooltip = 1
|
||||
battery_low_status = 10
|
||||
battery_low_cmd = notify-send "battery low"
|
||||
battery_low_cmd = xmessage 'tint2: Battery low!'
|
||||
battery_full_cmd =
|
||||
battery_font_color = #ffffff 100
|
||||
bat1_format =
|
||||
|
||||
@@ -201,7 +201,7 @@ clock_dwheel_command =
|
||||
# Battery
|
||||
battery_tooltip = 1
|
||||
battery_low_status = 10
|
||||
battery_low_cmd = notify-send "battery low"
|
||||
battery_low_cmd = xmessage 'tint2: Battery low!'
|
||||
battery_full_cmd =
|
||||
bat1_font = sans 8
|
||||
bat2_font = sans 6
|
||||
|
||||
@@ -201,7 +201,7 @@ clock_dwheel_command =
|
||||
# Battery
|
||||
battery_tooltip = 1
|
||||
battery_low_status = 10
|
||||
battery_low_cmd = notify-send "battery low"
|
||||
battery_low_cmd = xmessage 'tint2: Battery low!'
|
||||
battery_full_cmd =
|
||||
bat1_font = sans 8
|
||||
bat2_font = sans 6
|
||||
|
||||
@@ -212,7 +212,7 @@ clock_dwheel_command =
|
||||
# Battery
|
||||
battery_tooltip = 1
|
||||
battery_low_status = 10
|
||||
battery_low_cmd = notify-send "battery low"
|
||||
battery_low_cmd = xmessage 'tint2: Battery low!'
|
||||
battery_full_cmd =
|
||||
bat1_font = sans 8
|
||||
bat2_font = sans 6
|
||||
|
||||
@@ -201,7 +201,7 @@ clock_dwheel_command =
|
||||
# Battery
|
||||
battery_tooltip = 1
|
||||
battery_low_status = 10
|
||||
battery_low_cmd = notify-send "battery low"
|
||||
battery_low_cmd = xmessage 'tint2: Battery low!'
|
||||
battery_full_cmd =
|
||||
bat1_font = sans 8
|
||||
bat2_font = sans 6
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
configure
|
||||
doc/tint2.1
|
||||
sample/icon_and_text_1.tint2rc
|
||||
sample/icon_and_text_2.tint2rc
|
||||
@@ -59,8 +60,12 @@ src/util/area.c
|
||||
src/util/area.h
|
||||
src/util/blur.c
|
||||
src/util/blur.h
|
||||
src/util/bt.c
|
||||
src/util/bt.h
|
||||
src/util/common.c
|
||||
src/util/common.h
|
||||
src/util/server.c
|
||||
src/util/server.h
|
||||
src/util/strlcat.c
|
||||
src/util/strlcat.h
|
||||
src/util/timer.c
|
||||
|
||||
Reference in New Issue
Block a user