Compare commits
43
Commits
| 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 |
@@ -6,6 +6,7 @@ tint2 is developped by :
|
|||||||
- Ovidiu M <mrovi9000 at gmail.com> : launcher, bug fixes
|
- Ovidiu M <mrovi9000 at gmail.com> : launcher, bug fixes
|
||||||
- Mishael A Sibiryakov (death@junki.org) : freespace
|
- Mishael A Sibiryakov (death@junki.org) : freespace
|
||||||
- Sebastian Reichel <sre@ring0.de> : battery, various fixes, debian package maintainer
|
- 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/)
|
tint2 is based on the ttm source code (http://code.google.com/p/ttm/)
|
||||||
- 2007-2008 Pål Staurland <staura@gmail.com>
|
- 2007-2008 Pål Staurland <staura@gmail.com>
|
||||||
@@ -32,6 +33,7 @@ Contributors:
|
|||||||
Ryan Gray, Jeff Blake (https://gitlab.com/berkley4) : battery format
|
Ryan Gray, Jeff Blake (https://gitlab.com/berkley4) : battery format
|
||||||
aaaz (https://gitlab.com/aaaz) : clock fixes
|
aaaz (https://gitlab.com/aaaz) : clock fixes
|
||||||
heisenbug (https://gitlab.com/heisenbugh) : taskbar button tinting with icon color
|
heisenbug (https://gitlab.com/heisenbugh) : taskbar button tinting with icon color
|
||||||
|
Fabian Carlström : taskbar sort order by app name
|
||||||
|
|
||||||
Translations:
|
Translations:
|
||||||
Bosnian:
|
Bosnian:
|
||||||
|
|||||||
@@ -152,6 +152,7 @@ set( SOURCES src/config.c
|
|||||||
src/separator/separator.c
|
src/separator/separator.c
|
||||||
src/tint2rc.c
|
src/tint2rc.c
|
||||||
src/util/area.c
|
src/util/area.c
|
||||||
|
src/util/bt.c
|
||||||
src/util/common.c
|
src/util/common.c
|
||||||
src/util/fps_distribution.c
|
src/util/fps_distribution.c
|
||||||
src/util/strnatcmp.c
|
src/util/strnatcmp.c
|
||||||
|
|||||||
@@ -1,3 +1,31 @@
|
|||||||
|
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
|
2018-01-21 16.2
|
||||||
- Fixes:
|
- Fixes:
|
||||||
- Proper fix for issue #688
|
- Proper fix for issue #688
|
||||||
@@ -993,3 +1021,7 @@ released tint-0.2
|
|||||||
.
|
.
|
||||||
.
|
.
|
||||||
.
|
.
|
||||||
|
.
|
||||||
|
.
|
||||||
|
.
|
||||||
|
.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Latest stable release: 16.2
|
# Latest stable release: 16.6.1
|
||||||
Changes: https://gitlab.com/o9000/tint2/blob/16.2/ChangeLog
|
Changes: https://gitlab.com/o9000/tint2/blob/16.6.1/ChangeLog
|
||||||
|
|
||||||
Documentation: [doc/tint2.md](doc/tint2.md)
|
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
|
git clone https://gitlab.com/o9000/tint2.git
|
||||||
cd tint2
|
cd tint2
|
||||||
git checkout 16.2
|
git checkout 16.6.1
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake ..
|
cmake ..
|
||||||
@@ -97,4 +97,3 @@ tint2 is a simple panel/taskbar made for modern X window managers. It was specif
|
|||||||
## More
|
## More
|
||||||
|
|
||||||
* [Tint2 wiki](https://gitlab.com/o9000/tint2/wikis/Home)
|
* [Tint2 wiki](https://gitlab.com/o9000/tint2/wikis/Home)
|
||||||
Home)
|
|
||||||
|
|||||||
+2
-1
@@ -466,6 +466,7 @@ panel_size = 94% 30
|
|||||||
<ul>
|
<ul>
|
||||||
<li><code>none</code> : No sorting. New tasks are simply appended at the end of the taskbar when they appear.</li>
|
<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>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>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>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>
|
<li><code>lru</code> : Shows the most recently used tasks last. <em>(since 0.12.4)</em></li>
|
||||||
@@ -572,7 +573,7 @@ panel_size = 94% 30
|
|||||||
<ul>
|
<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_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_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>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>bat1_font = [FAMILY-LIST] [STYLE-OPTIONS] [SIZE]</code></p></li>
|
||||||
<li><p><code>bat2_font = [FAMILY-LIST] [STYLE-OPTIONS] [SIZE]</code></p></li>
|
<li><p><code>bat2_font = [FAMILY-LIST] [STYLE-OPTIONS] [SIZE]</code></p></li>
|
||||||
|
|||||||
+3
-4
@@ -199,9 +199,9 @@ pre {
|
|||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1 id="latest-stable-release-16-2"><span class="md2man-title">Latest</span> <span class="md2man-section">stable</span> <span class="md2man-date">release:</span> <span class="md2man-source">16.2</span><a name="latest-stable-release-16-2" href="#latest-stable-release-16-2" class="md2man-permalink" title="permalink"></a></h1><p>Changes: <a href="https://gitlab.com/o9000/tint2/blob/16.2/ChangeLog">https://gitlab.com/o9000/tint2/blob/16.2/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
|
cd tint2
|
||||||
git checkout 16.2
|
git checkout 16.6.1
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake ..
|
cmake ..
|
||||||
@@ -269,8 +269,7 @@ update-mime-database /usr/local/share/mime
|
|||||||
</ul>
|
</ul>
|
||||||
<h2 id="more">More<a name="more" href="#more" class="md2man-permalink" title="permalink"></a></h2>
|
<h2 id="more">More<a name="more" href="#more" class="md2man-permalink" title="permalink"></a></h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="https://gitlab.com/o9000/tint2/wikis/Home">Tint2 wiki</a>
|
<li><a href="https://gitlab.com/o9000/tint2/wikis/Home">Tint2 wiki</a></li>
|
||||||
Home)</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
+4
-2
@@ -1,4 +1,4 @@
|
|||||||
.TH TINT2 1 "2018\-01\-21" 16.2
|
.TH TINT2 1 "2018\-08\-05" 16.6.1
|
||||||
.SH NAME
|
.SH NAME
|
||||||
.PP
|
.PP
|
||||||
tint2 \- lightweight panel/taskbar
|
tint2 \- lightweight panel/taskbar
|
||||||
@@ -480,6 +480,8 @@ You can switch between virtual desktops.
|
|||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\fB\fCtitle\fR : Sorts the tasks by title.
|
\fB\fCtitle\fR : Sorts the tasks by title.
|
||||||
.IP \(bu 2
|
.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.
|
\fB\fCcenter\fR : Sorts the tasks by their window centers.
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\fB\fCmru\fR : Shows the most recently used tasks first. \fI(since 0.12.4)\fP
|
\fB\fCmru\fR : Shows the most recently used tasks first. \fI(since 0.12.4)\fP
|
||||||
@@ -663,7 +665,7 @@ To hide the clock, comment \fB\fCtime1_format\fR and \fB\fCtime2_format\fR\&.
|
|||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\fB\fCbattery_low_status = integer\fR: At what battery percentage the low command is executed.
|
\fB\fCbattery_low_status = integer\fR: At what battery percentage the low command is executed.
|
||||||
.IP \(bu 2
|
.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
|
.IP \(bu 2
|
||||||
\fB\fCbattery_full_cmd = notify\-send "battery full"\fR : Command to execute when the battery is full.
|
\fB\fCbattery_full_cmd = notify\-send "battery full"\fR : Command to execute when the battery is full.
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
|
|||||||
+3
-2
@@ -1,4 +1,4 @@
|
|||||||
# TINT2 1 "2018-01-21" 16.2
|
# TINT2 1 "2018-08-05" 16.6.1
|
||||||
|
|
||||||
## NAME
|
## NAME
|
||||||
tint2 - lightweight panel/taskbar
|
tint2 - lightweight panel/taskbar
|
||||||
@@ -385,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)*
|
* `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.
|
* `none` : No sorting. New tasks are simply appended at the end of the taskbar when they appear.
|
||||||
* `title` : Sorts the tasks by title.
|
* `title` : Sorts the tasks by title.
|
||||||
|
* `application` : Sorts the tasks by application name. *(since 16.3)*
|
||||||
* `center` : Sorts the tasks by their window centers.
|
* `center` : Sorts the tasks by their window centers.
|
||||||
* `mru` : Shows the most recently used tasks first. *(since 0.12.4)*
|
* `mru` : Shows the most recently used tasks first. *(since 0.12.4)*
|
||||||
* `lru` : Shows the most recently used tasks last. *(since 0.12.4)*
|
* `lru` : Shows the most recently used tasks last. *(since 0.12.4)*
|
||||||
@@ -546,7 +547,7 @@ The action semantics:
|
|||||||
|
|
||||||
* `battery_low_status = integer`: At what battery percentage the low command is executed.
|
* `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.
|
* `battery_full_cmd = notify-send "battery full"` : Command to execute when the battery is full.
|
||||||
|
|
||||||
|
|||||||
+16
-15
@@ -76,19 +76,23 @@ def get_last_version():
|
|||||||
return tags[-1]
|
return tags[-1]
|
||||||
|
|
||||||
|
|
||||||
def inc_version(v, feature=False):
|
def inc_version(v, feature=False, tiny=False):
|
||||||
if v.startswith("v0."):
|
if v.startswith("v0."):
|
||||||
assert v == "v0.14.6"
|
assert v == "v0.14.6"
|
||||||
return "v15.0"
|
return "v15.0"
|
||||||
# v4.11 -> v4.12 or v5.0
|
# v4.11 -> v4.12 or v5.0 or v4.11.1
|
||||||
parts = v.split(".")
|
parts = v.split(".")
|
||||||
while len(parts) < 2:
|
while len(parts) < 3:
|
||||||
parts.append("0")
|
parts.append("0")
|
||||||
assert len(parts) == 2
|
assert len(parts) == 3
|
||||||
if feature:
|
if feature:
|
||||||
|
del parts[-1]
|
||||||
parts[-2] = "v" + str(int(parts[-2].replace("v", "")) + 1)
|
parts[-2] = "v" + str(int(parts[-2].replace("v", "")) + 1)
|
||||||
parts[-1] = "0"
|
parts[-1] = "0"
|
||||||
|
elif tiny:
|
||||||
|
parts[-1] = str(int(parts[-1]) + 1)
|
||||||
else:
|
else:
|
||||||
|
del parts[-1]
|
||||||
parts[-1] = str(int(parts[-1]) + 1)
|
parts[-1] = str(int(parts[-1]) + 1)
|
||||||
return ".".join([s for s in parts if s])
|
return ".".join([s for s in parts if s])
|
||||||
|
|
||||||
@@ -153,23 +157,14 @@ def update_log(path, version, date):
|
|||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument("--feature", action="store_true")
|
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()
|
args = parser.parse_args()
|
||||||
logging.basicConfig(format=ansi_lblue + "%(asctime)s %(pathname)s %(levelname)s" + ansi_reset + " %(message)s", level=logging.DEBUG)
|
logging.basicConfig(format=ansi_lblue + "%(asctime)s %(pathname)s %(levelname)s" + ansi_reset + " %(message)s", level=logging.DEBUG)
|
||||||
test_inc_version()
|
test_inc_version()
|
||||||
# Read version from last tag and increment
|
# Read version from last tag and increment
|
||||||
old_version = get_last_version()
|
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)
|
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", "")
|
readable_version = version.replace("v", "")
|
||||||
date = datetime.datetime.now().strftime("%Y-%m-%d")
|
date = datetime.datetime.now().strftime("%Y-%m-%d")
|
||||||
info("New version:", readable_version, version, date)
|
info("New version:", readable_version, version, date)
|
||||||
@@ -194,3 +189,9 @@ if __name__ == '__main__':
|
|||||||
choice = raw_input().lower()
|
choice = raw_input().lower()
|
||||||
if choice != "y":
|
if choice != "y":
|
||||||
run("git reset --hard HEAD~ ; git tag -d %s ; git tag -d %s" % (version, readable_version))
|
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
@@ -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)
|
||||||
@@ -289,7 +289,7 @@ def get_gentoo_versions():
|
|||||||
|
|
||||||
def get_void_versions():
|
def get_void_versions():
|
||||||
print >> sys.stderr, "Void ..."
|
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 = []
|
versions = []
|
||||||
version = None
|
version = None
|
||||||
maintainer = None
|
maintainer = None
|
||||||
|
|||||||
+63
-1
@@ -42,6 +42,7 @@ gboolean battery_enabled;
|
|||||||
gboolean battery_tooltip_enabled;
|
gboolean battery_tooltip_enabled;
|
||||||
int percentage_hide;
|
int percentage_hide;
|
||||||
static Timer battery_timer;
|
static Timer battery_timer;
|
||||||
|
static Timer battery_blink_timer;
|
||||||
|
|
||||||
#define BATTERY_BUF_SIZE 256
|
#define BATTERY_BUF_SIZE 256
|
||||||
static char buf_bat_line1[BATTERY_BUF_SIZE];
|
static char buf_bat_line1[BATTERY_BUF_SIZE];
|
||||||
@@ -60,6 +61,9 @@ char *battery_rclick_command;
|
|||||||
char *battery_uwheel_command;
|
char *battery_uwheel_command;
|
||||||
char *battery_dwheel_command;
|
char *battery_dwheel_command;
|
||||||
gboolean battery_found;
|
gboolean battery_found;
|
||||||
|
gboolean battery_warn;
|
||||||
|
gboolean battery_warn_red;
|
||||||
|
Background *battery_warn_bg;
|
||||||
|
|
||||||
char *battery_sys_prefix = (char *)"";
|
char *battery_sys_prefix = (char *)"";
|
||||||
|
|
||||||
@@ -77,6 +81,10 @@ void default_battery()
|
|||||||
battery_low_cmd_sent = FALSE;
|
battery_low_cmd_sent = FALSE;
|
||||||
battery_full_cmd_sent = FALSE;
|
battery_full_cmd_sent = FALSE;
|
||||||
INIT_TIMER(battery_timer);
|
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_has_font = FALSE;
|
||||||
bat1_font_desc = NULL;
|
bat1_font_desc = NULL;
|
||||||
bat1_format = NULL;
|
bat1_format = NULL;
|
||||||
@@ -128,7 +136,9 @@ void cleanup_battery()
|
|||||||
free(ac_disconnected_cmd);
|
free(ac_disconnected_cmd);
|
||||||
ac_disconnected_cmd = NULL;
|
ac_disconnected_cmd = NULL;
|
||||||
destroy_timer(&battery_timer);
|
destroy_timer(&battery_timer);
|
||||||
|
destroy_timer(&battery_blink_timer);
|
||||||
battery_found = FALSE;
|
battery_found = FALSE;
|
||||||
|
free_and_null(battery_warn_bg);
|
||||||
|
|
||||||
battery_os_free();
|
battery_os_free();
|
||||||
}
|
}
|
||||||
@@ -310,6 +320,40 @@ void battery_default_font_changed()
|
|||||||
schedule_panel_redraw();
|
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)
|
void update_battery_tick(void *arg)
|
||||||
{
|
{
|
||||||
if (!battery_enabled)
|
if (!battery_enabled)
|
||||||
@@ -320,6 +364,7 @@ void update_battery_tick(void *arg)
|
|||||||
gboolean old_ac_connected = battery_state.ac_connected;
|
gboolean old_ac_connected = battery_state.ac_connected;
|
||||||
int16_t old_hours = battery_state.time.hours;
|
int16_t old_hours = battery_state.time.hours;
|
||||||
int8_t old_minutes = battery_state.time.minutes;
|
int8_t old_minutes = battery_state.time.minutes;
|
||||||
|
gboolean old_warn = battery_warn;
|
||||||
|
|
||||||
if (!battery_found) {
|
if (!battery_found) {
|
||||||
init_battery();
|
init_battery();
|
||||||
@@ -357,6 +402,20 @@ void update_battery_tick(void *arg)
|
|||||||
battery_full_cmd_sent = FALSE;
|
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++) {
|
for (int i = 0; i < num_panels; i++) {
|
||||||
// Show/hide if needed
|
// Show/hide if needed
|
||||||
if (!battery_found) {
|
if (!battery_found) {
|
||||||
@@ -370,8 +429,11 @@ void update_battery_tick(void *arg)
|
|||||||
// Redraw if needed
|
// Redraw if needed
|
||||||
if (panels[i].battery.area.on_screen) {
|
if (panels[i].battery.area.on_screen) {
|
||||||
if (old_found != battery_found || old_percentage != battery_state.percentage ||
|
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;
|
panels[i].battery.area.resize_needed = TRUE;
|
||||||
|
if (!battery_warn)
|
||||||
|
panels[i].battery.area.bg = panel_config.battery.area.bg;
|
||||||
schedule_panel_redraw();
|
schedule_panel_redraw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -478,7 +478,7 @@ void draw_button(void *obj, cairo_t *c)
|
|||||||
button->frontend->textx,
|
button->frontend->textx,
|
||||||
button->frontend->texty,
|
button->frontend->texty,
|
||||||
&button->backend->font_color,
|
&button->backend->font_color,
|
||||||
panel_config.font_shadow);
|
panel_config.font_shadow ? layout : NULL);
|
||||||
|
|
||||||
g_object_unref(layout);
|
g_object_unref(layout);
|
||||||
g_object_unref(context);
|
g_object_unref(context);
|
||||||
|
|||||||
+7
-1
@@ -173,7 +173,13 @@ gboolean time_format_needs_sec_ticks(char *time_format)
|
|||||||
{
|
{
|
||||||
if (!time_format)
|
if (!time_format)
|
||||||
return FALSE;
|
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 TRUE;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1016,6 +1016,8 @@ void add_entry(char *key, char *value)
|
|||||||
taskbar_sort_method = TASKBAR_SORT_CENTER;
|
taskbar_sort_method = TASKBAR_SORT_CENTER;
|
||||||
} else if (strcmp(value, "title") == 0) {
|
} else if (strcmp(value, "title") == 0) {
|
||||||
taskbar_sort_method = TASKBAR_SORT_TITLE;
|
taskbar_sort_method = TASKBAR_SORT_TITLE;
|
||||||
|
} else if (strcmp(value, "application") == 0) {
|
||||||
|
taskbar_sort_method = TASKBAR_SORT_APPLICATION;
|
||||||
} else if (strcmp(value, "lru") == 0) {
|
} else if (strcmp(value, "lru") == 0) {
|
||||||
taskbar_sort_method = TASKBAR_SORT_LRU;
|
taskbar_sort_method = TASKBAR_SORT_LRU;
|
||||||
} else if (strcmp(value, "mru") == 0) {
|
} else if (strcmp(value, "mru") == 0) {
|
||||||
|
|||||||
+49
-12
@@ -20,6 +20,8 @@
|
|||||||
|
|
||||||
#define MAX_TOOLTIP_LEN 4096
|
#define MAX_TOOLTIP_LEN 4096
|
||||||
|
|
||||||
|
bool debug_executors = false;
|
||||||
|
|
||||||
void execp_timer_callback(void *arg);
|
void execp_timer_callback(void *arg);
|
||||||
char *execp_get_tooltip(void *obj);
|
char *execp_get_tooltip(void *obj);
|
||||||
void execp_init_fonts();
|
void execp_init_fonts();
|
||||||
@@ -332,7 +334,7 @@ void execp_compute_icon_text_geometry(Execp *execp,
|
|||||||
int available_w, available_h;
|
int available_w, available_h;
|
||||||
if (panel_horizontal) {
|
if (panel_horizontal) {
|
||||||
available_w = panel->area.width;
|
available_w = panel->area.width;
|
||||||
available_h = area->height - 2 * *horiz_padding - left_right_border_width(area);
|
available_h = area->height - 2 * *vert_padding - left_right_border_width(area);
|
||||||
} else {
|
} else {
|
||||||
available_w = !text_next_line
|
available_w = !text_next_line
|
||||||
? area->width - *icon_w - (*icon_w ? *interior_padding : 0) - 2 * *horiz_padding -
|
? area->width - *icon_w - (*icon_w ? *interior_padding : 0) - 2 * *horiz_padding -
|
||||||
@@ -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 = *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));
|
*new_size = MAX(*new_size, *icon_h + 2 * *vert_padding + top_bottom_border_width(area));
|
||||||
} else {
|
} else {
|
||||||
|
if (strlen(execp->backend->text)) {
|
||||||
*new_size = *icon_h + *interior_padding + *txt_height + 2 * *vert_padding + top_bottom_border_width(area);
|
*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) {
|
if (*new_size != area->height) {
|
||||||
*resized = TRUE;
|
*resized = TRUE;
|
||||||
@@ -439,10 +445,17 @@ gboolean resize_execp(void *obj)
|
|||||||
execp->frontend->texty = (execp->area.height - txt_height) / 2;
|
execp->frontend->texty = (execp->area.height - txt_height) / 2;
|
||||||
execp->frontend->textx = execp->frontend->iconx + icon_w + interior_padding;
|
execp->frontend->textx = execp->frontend->iconx + icon_w + interior_padding;
|
||||||
} else {
|
} else {
|
||||||
|
if (strlen(execp->backend->text)) {
|
||||||
execp->frontend->icony = (execp->area.height - icon_h - interior_padding - txt_height) / 2;
|
execp->frontend->icony = (execp->area.height - icon_h - interior_padding - txt_height) / 2;
|
||||||
execp->frontend->iconx = (execp->area.width - icon_w) / 2;
|
execp->frontend->iconx = (execp->area.width - icon_w) / 2;
|
||||||
execp->frontend->texty = execp->frontend->icony + icon_h + interior_padding;
|
execp->frontend->texty = execp->frontend->icony + icon_h + interior_padding;
|
||||||
execp->frontend->textx = (execp->area.width - txt_width) / 2;
|
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 {
|
} else {
|
||||||
execp->frontend->texty = (execp->area.height - txt_height) / 2;
|
execp->frontend->texty = (execp->area.height - txt_height) / 2;
|
||||||
@@ -456,10 +469,17 @@ gboolean resize_execp(void *obj)
|
|||||||
execp->frontend->texty = (execp->area.height - txt_height) / 2;
|
execp->frontend->texty = (execp->area.height - txt_height) / 2;
|
||||||
execp->frontend->textx = execp->frontend->iconx + icon_w + interior_padding;
|
execp->frontend->textx = execp->frontend->iconx + icon_w + interior_padding;
|
||||||
} else {
|
} else {
|
||||||
|
if (strlen(execp->backend->text)) {
|
||||||
execp->frontend->icony = (execp->area.height - icon_h - interior_padding - txt_height) / 2;
|
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->iconx = left_border_width(&execp->area) + horiz_padding;
|
||||||
execp->frontend->texty = execp->frontend->icony + icon_h + interior_padding;
|
execp->frontend->texty = execp->frontend->icony + icon_h + interior_padding;
|
||||||
execp->frontend->textx = execp->frontend->iconx;
|
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 {
|
} else {
|
||||||
execp->frontend->texty = (execp->area.height - txt_height) / 2;
|
execp->frontend->texty = (execp->area.height - txt_height) / 2;
|
||||||
@@ -471,6 +491,18 @@ gboolean resize_execp(void *obj)
|
|||||||
return resized;
|
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)
|
void draw_execp(void *obj, cairo_t *c)
|
||||||
{
|
{
|
||||||
Execp *execp = (Execp *)obj;
|
Execp *execp = (Execp *)obj;
|
||||||
@@ -478,7 +510,8 @@ void draw_execp(void *obj, cairo_t *c)
|
|||||||
|
|
||||||
PangoContext *context = pango_cairo_create_context(c);
|
PangoContext *context = pango_cairo_create_context(c);
|
||||||
pango_cairo_context_set_resolution(context, 96 * panel->scale);
|
pango_cairo_context_set_resolution(context, 96 * panel->scale);
|
||||||
PangoLayout *layout = pango_layout_new(context);
|
PangoLayout *layout = create_execp_text_layout(execp, context);
|
||||||
|
PangoLayout *shadow_layout = NULL;
|
||||||
|
|
||||||
if (execp->backend->has_icon && execp->backend->icon) {
|
if (execp->backend->has_icon && execp->backend->icon) {
|
||||||
imlib_context_set_image(execp->backend->icon);
|
imlib_context_set_image(execp->backend->icon);
|
||||||
@@ -487,16 +520,18 @@ void draw_execp(void *obj, cairo_t *c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// draw layout
|
// draw layout
|
||||||
pango_layout_set_font_description(layout, execp->backend->font_desc);
|
if (!execp->backend->has_markup) {
|
||||||
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);
|
|
||||||
if (!execp->backend->has_markup)
|
|
||||||
pango_layout_set_text(layout, execp->backend->text, strlen(execp->backend->text));
|
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));
|
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);
|
pango_cairo_update_layout(c, layout);
|
||||||
draw_text(layout,
|
draw_text(layout,
|
||||||
@@ -504,7 +539,7 @@ void draw_execp(void *obj, cairo_t *c)
|
|||||||
execp->frontend->textx,
|
execp->frontend->textx,
|
||||||
execp->frontend->texty,
|
execp->frontend->texty,
|
||||||
&execp->backend->font_color,
|
&execp->backend->font_color,
|
||||||
panel_config.font_shadow);
|
shadow_layout);
|
||||||
|
|
||||||
g_object_unref(layout);
|
g_object_unref(layout);
|
||||||
g_object_unref(context);
|
g_object_unref(context);
|
||||||
@@ -529,12 +564,13 @@ void execp_dump_geometry(void *obj, int indent)
|
|||||||
imlib_context_set_image(tmp);
|
imlib_context_set_image(tmp);
|
||||||
}
|
}
|
||||||
fprintf(stderr,
|
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,
|
indent,
|
||||||
"",
|
"",
|
||||||
execp->frontend->textx,
|
execp->frontend->textx,
|
||||||
execp->frontend->texty,
|
execp->frontend->texty,
|
||||||
execp->frontend->textw,
|
execp->frontend->textw,
|
||||||
|
execp->frontend->texth,
|
||||||
execp->backend->centered ? "center" : "left",
|
execp->backend->centered ? "center" : "left",
|
||||||
execp->backend->text);
|
execp->backend->text);
|
||||||
}
|
}
|
||||||
@@ -635,6 +671,7 @@ void execp_timer_callback(void *arg)
|
|||||||
close(pipe_fd_stderr[0]);
|
close(pipe_fd_stderr[0]);
|
||||||
return;
|
return;
|
||||||
} else if (child == 0) {
|
} else if (child == 0) {
|
||||||
|
if (debug_executors)
|
||||||
fprintf(stderr, "tint2: Executing: %s\n", execp->backend->command);
|
fprintf(stderr, "tint2: Executing: %s\n", execp->backend->command);
|
||||||
// We are in the child
|
// We are in the child
|
||||||
close(pipe_fd_stdout[0]);
|
close(pipe_fd_stdout[0]);
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
|
|
||||||
|
extern bool debug_executors;
|
||||||
|
|
||||||
// Architecture:
|
// Architecture:
|
||||||
// Panel panel_config contains an array of Execp, each storing all config options and all the state variables.
|
// Panel panel_config contains an array of Execp, each storing all config options and all the state variables.
|
||||||
// Only these run commands.
|
// Only these run commands.
|
||||||
|
|||||||
+5
-3
@@ -106,6 +106,7 @@ void handle_env_vars()
|
|||||||
debug_dnd = getenv("DEBUG_DND") != NULL;
|
debug_dnd = getenv("DEBUG_DND") != NULL;
|
||||||
debug_thumbnails = getenv("DEBUG_THUMBNAILS") != NULL;
|
debug_thumbnails = getenv("DEBUG_THUMBNAILS") != NULL;
|
||||||
debug_timers = getenv("DEBUG_TIMERS") != NULL;
|
debug_timers = getenv("DEBUG_TIMERS") != NULL;
|
||||||
|
debug_executors = getenv("DEBUG_EXECUTORS") != NULL;
|
||||||
if (debug_fps) {
|
if (debug_fps) {
|
||||||
init_fps_distribution();
|
init_fps_distribution();
|
||||||
char *s = getenv("TRACING_FPS_THRESHOLD");
|
char *s = getenv("TRACING_FPS_THRESHOLD");
|
||||||
@@ -208,8 +209,8 @@ void init_X11_pre_config()
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
server.x11_fd = ConnectionNumber(server.display);
|
server.x11_fd = ConnectionNumber(server.display);
|
||||||
XSetErrorHandler((XErrorHandler)server_catch_error);
|
XSetErrorHandler(server_catch_error);
|
||||||
XSetIOErrorHandler((XIOErrorHandler)x11_io_error);
|
XSetIOErrorHandler(x11_io_error);
|
||||||
server_init_atoms();
|
server_init_atoms();
|
||||||
server.screen = DefaultScreen(server.display);
|
server.screen = DefaultScreen(server.display);
|
||||||
server.root_win = RootWindow(server.display, server.screen);
|
server.root_win = RootWindow(server.display, server.screen);
|
||||||
@@ -246,8 +247,9 @@ void init(int argc, char **argv)
|
|||||||
if (!config_read()) {
|
if (!config_read()) {
|
||||||
fprintf(stderr, "tint2: Could not read config file.\n");
|
fprintf(stderr, "tint2: Could not read config file.\n");
|
||||||
print_usage();
|
print_usage();
|
||||||
|
warnings_for_timers = false;
|
||||||
cleanup();
|
cleanup();
|
||||||
return;
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
init_post_config();
|
init_post_config();
|
||||||
|
|||||||
@@ -399,7 +399,12 @@ void launcher_icon_dump_geometry(void *obj, int indent)
|
|||||||
Imlib_Image scale_icon(Imlib_Image original, int icon_size)
|
Imlib_Image scale_icon(Imlib_Image original, int icon_size)
|
||||||
{
|
{
|
||||||
Imlib_Image icon_scaled;
|
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);
|
imlib_context_set_image(original);
|
||||||
icon_scaled = imlib_create_cropped_scaled_image(0,
|
icon_scaled = imlib_create_cropped_scaled_image(0,
|
||||||
0,
|
0,
|
||||||
|
|||||||
@@ -229,6 +229,10 @@ void init_panel()
|
|||||||
p->scale = 1;
|
p->scale = 1;
|
||||||
if (ui_scale_monitor_size_ref > 0)
|
if (ui_scale_monitor_size_ref > 0)
|
||||||
p->scale *= server.monitors[p->monitor].height / ui_scale_monitor_size_ref;
|
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);
|
fprintf(stderr, BLUE "tint2: panel %d uses scale %g " RESET "\n", i + 1, p->scale);
|
||||||
if (!p->area.bg)
|
if (!p->area.bg)
|
||||||
p->area.bg = &g_array_index(backgrounds, Background, 0);
|
p->area.bg = &g_array_index(backgrounds, Background, 0);
|
||||||
|
|||||||
+23
-5
@@ -107,6 +107,21 @@ Task *add_task(Window win)
|
|||||||
(int)win,
|
(int)win,
|
||||||
task_template.title ? task_template.title : "null");
|
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();
|
GPtrArray *task_buttons = g_ptr_array_new();
|
||||||
for (int j = 0; j < panels[monitor].num_desktops; j++) {
|
for (int j = 0; j < panels[monitor].num_desktops; j++) {
|
||||||
if (task_template.desktop != ALL_DESKTOPS && task_template.desktop != 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->area.on_screen = always_show_all_desktop_tasks;
|
||||||
}
|
}
|
||||||
task_instance->title = task_template.title;
|
task_instance->title = task_template.title;
|
||||||
|
task_instance->application = task_template.application;
|
||||||
if (panels[monitor].g_task.tooltip_enabled) {
|
if (panels[monitor].g_task.tooltip_enabled) {
|
||||||
task_instance->area._get_tooltip_text = task_get_tooltip;
|
task_instance->area._get_tooltip_text = task_get_tooltip;
|
||||||
task_instance->area._get_tooltip_image = task_get_thumbnail;
|
task_instance->area._get_tooltip_image = task_get_thumbnail;
|
||||||
@@ -208,12 +224,14 @@ void remove_task(Task *task)
|
|||||||
|
|
||||||
Window win = task->win;
|
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
|
// even with task_on_all_desktop and with task_on_all_panel
|
||||||
if (task->title)
|
if (task->title)
|
||||||
free(task->title);
|
free(task->title);
|
||||||
if (task->thumbnail)
|
if (task->thumbnail)
|
||||||
cairo_surface_destroy(task->thumbnail);
|
cairo_surface_destroy(task->thumbnail);
|
||||||
|
if (task->application)
|
||||||
|
free(task->application);
|
||||||
task_remove_icon(task);
|
task_remove_icon(task);
|
||||||
|
|
||||||
GPtrArray *task_buttons = g_hash_table_lookup(win_to_task, &win);
|
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,
|
task->icon[k] = adjust_icon(orig_image,
|
||||||
panel->g_task.alpha[k],
|
panel->g_task.alpha[k],
|
||||||
panel->g_task.saturation[k],
|
panel->g_task.saturation[k],
|
||||||
panel->g_task.brightness[k] != 0);
|
panel->g_task.brightness[k]);
|
||||||
if (panel_config.mouse_effects) {
|
if (panel_config.mouse_effects) {
|
||||||
task->icon_hover[k] = adjust_icon(task->icon[k],
|
task->icon_hover[k] = adjust_icon(task->icon[k],
|
||||||
panel_config.mouse_over_alpha,
|
panel_config.mouse_over_alpha,
|
||||||
@@ -479,7 +497,7 @@ void draw_task(void *obj, cairo_t *c)
|
|||||||
task->_text_posy = (panel->g_task.area.height - task->_text_height) / 2.0;
|
task->_text_posy = (panel->g_task.area.height - task->_text_height) / 2.0;
|
||||||
|
|
||||||
Color *config_text = &panel->g_task.font[task->current_state];
|
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(layout);
|
||||||
g_object_unref(context);
|
g_object_unref(context);
|
||||||
@@ -758,8 +776,8 @@ void blink_urgent(void *arg)
|
|||||||
GSList *urgent_task = urgent_list;
|
GSList *urgent_task = urgent_list;
|
||||||
while (urgent_task) {
|
while (urgent_task) {
|
||||||
Task *t = urgent_task->data;
|
Task *t = urgent_task->data;
|
||||||
if (t->urgent_tick < max_tick_urgent) {
|
if (t->urgent_tick <= max_tick_urgent) {
|
||||||
if (t->urgent_tick++ % 2)
|
if (++t->urgent_tick % 2)
|
||||||
set_task_state(t, TASK_URGENT);
|
set_task_state(t, TASK_URGENT);
|
||||||
else
|
else
|
||||||
set_task_state(t, window_is_iconified(t->win) ? TASK_ICONIFIED : TASK_NORMAL);
|
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_hover;
|
||||||
Color icon_color_press;
|
Color icon_color_press;
|
||||||
char *title;
|
char *title;
|
||||||
|
char *application;
|
||||||
int urgent_tick;
|
int urgent_tick;
|
||||||
// These may not be up-to-date
|
// These may not be up-to-date
|
||||||
int win_x;
|
int win_x;
|
||||||
|
|||||||
+12
-1
@@ -735,6 +735,14 @@ gint compare_task_titles(Task *a, Task *b, Taskbar *taskbar)
|
|||||||
return strnatcasecmp(a->title ? a->title : "", b->title ? b->title : "");
|
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)
|
gint compare_tasks(Task *a, Task *b, Taskbar *taskbar)
|
||||||
{
|
{
|
||||||
int trivial = compare_tasks_trivial(a, b, taskbar);
|
int trivial = compare_tasks_trivial(a, b, taskbar);
|
||||||
@@ -746,6 +754,8 @@ gint compare_tasks(Task *a, Task *b, Taskbar *taskbar)
|
|||||||
return compare_task_centers(a, b, taskbar);
|
return compare_task_centers(a, b, taskbar);
|
||||||
} else if (taskbar_sort_method == TASKBAR_SORT_TITLE) {
|
} else if (taskbar_sort_method == TASKBAR_SORT_TITLE) {
|
||||||
return compare_task_titles(a, b, taskbar);
|
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) {
|
} else if (taskbar_sort_method == TASKBAR_SORT_LRU) {
|
||||||
return compare_timespecs(&a->last_activation_time, &b->last_activation_time);
|
return compare_timespecs(&a->last_activation_time, &b->last_activation_time);
|
||||||
} else if (taskbar_sort_method == TASKBAR_SORT_MRU) {
|
} else if (taskbar_sort_method == TASKBAR_SORT_MRU) {
|
||||||
@@ -835,7 +845,8 @@ void taskbar_update_thumbnails(void *arg)
|
|||||||
c;
|
c;
|
||||||
c = c->next) {
|
c = c->next) {
|
||||||
Task *t = (Task *)c->data;
|
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)) {
|
(mode == THUMB_MODE_TOOLTIP_WINDOW && g_tooltip.mapped && g_tooltip.area == &t->area)) {
|
||||||
task_refresh_thumbnail(t);
|
task_refresh_thumbnail(t);
|
||||||
if (mode == THUMB_MODE_ALL)
|
if (mode == THUMB_MODE_ALL)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ typedef enum TaskbarSortMethod {
|
|||||||
TASKBAR_NOSORT = 0,
|
TASKBAR_NOSORT = 0,
|
||||||
TASKBAR_SORT_CENTER,
|
TASKBAR_SORT_CENTER,
|
||||||
TASKBAR_SORT_TITLE,
|
TASKBAR_SORT_TITLE,
|
||||||
|
TASKBAR_SORT_APPLICATION,
|
||||||
TASKBAR_SORT_LRU,
|
TASKBAR_SORT_LRU,
|
||||||
TASKBAR_SORT_MRU,
|
TASKBAR_SORT_MRU,
|
||||||
} TaskbarSortMethod;
|
} TaskbarSortMethod;
|
||||||
|
|||||||
@@ -215,7 +215,7 @@ 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);
|
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);
|
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(layout);
|
||||||
g_object_unref(context);
|
g_object_unref(context);
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ include_directories( ../util
|
|||||||
${RSVG_INCLUDE_DIRS} )
|
${RSVG_INCLUDE_DIRS} )
|
||||||
|
|
||||||
set(SOURCES ../util/common.c
|
set(SOURCES ../util/common.c
|
||||||
|
../util/bt.c
|
||||||
../util/strnatcmp.c
|
../util/strnatcmp.c
|
||||||
../util/cache.c
|
../util/cache.c
|
||||||
../util/timer.c
|
../util/timer.c
|
||||||
|
|||||||
@@ -383,6 +383,11 @@ static void menuAbout()
|
|||||||
|
|
||||||
// ====== Theme import/copy/delete ======
|
// ====== 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.
|
// Shows open dialog and copies the selected files to ~ without overwrite.
|
||||||
static void menuImportFile()
|
static void menuImportFile()
|
||||||
{
|
{
|
||||||
@@ -407,7 +412,7 @@ static void menuImportFile()
|
|||||||
gchar *newpath = import_no_overwrite(l->data);
|
gchar *newpath = import_no_overwrite(l->data);
|
||||||
g_free(newpath);
|
g_free(newpath);
|
||||||
}
|
}
|
||||||
g_slist_foreach(list, (GFunc)g_free, NULL);
|
g_slist_foreach(list, free_data, NULL);
|
||||||
g_slist_free(list);
|
g_slist_free(list);
|
||||||
gtk_widget_destroy(dialog);
|
gtk_widget_destroy(dialog);
|
||||||
}
|
}
|
||||||
|
|||||||
+294
-287
File diff suppressed because it is too large
Load Diff
+294
-287
File diff suppressed because it is too large
Load Diff
+294
-287
File diff suppressed because it is too large
Load Diff
+294
-287
File diff suppressed because it is too large
Load Diff
+294
-287
File diff suppressed because it is too large
Load Diff
+294
-287
File diff suppressed because it is too large
Load Diff
+294
-287
File diff suppressed because it is too large
Load Diff
+289
-284
File diff suppressed because it is too large
Load Diff
@@ -2718,6 +2718,7 @@ void create_taskbar(GtkWidget *parent)
|
|||||||
col++;
|
col++;
|
||||||
gtk_combo_box_append_text(GTK_COMBO_BOX(taskbar_sort_order), _("None"));
|
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 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), _("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 first"));
|
||||||
gtk_combo_box_append_text(GTK_COMBO_BOX(taskbar_sort_order), _("Most recently used last"));
|
gtk_combo_box_append_text(GTK_COMBO_BOX(taskbar_sort_order), _("Most recently used last"));
|
||||||
@@ -2728,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 "
|
"'None' means that new tasks are added to the end, and the user can also reorder task "
|
||||||
"buttons by mouse dragging. \n"
|
"buttons by mouse dragging. \n"
|
||||||
"'By title' means that tasks are sorted by their window titles. \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."),
|
"'By center' means that tasks are sorted geometrically by their window centers."),
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
|||||||
@@ -457,10 +457,12 @@ void config_write_taskbar(FILE *fp)
|
|||||||
} else if (gtk_combo_box_get_active(GTK_COMBO_BOX(taskbar_sort_order)) == 1) {
|
} else if (gtk_combo_box_get_active(GTK_COMBO_BOX(taskbar_sort_order)) == 1) {
|
||||||
fprintf(fp, "title");
|
fprintf(fp, "title");
|
||||||
} else if (gtk_combo_box_get_active(GTK_COMBO_BOX(taskbar_sort_order)) == 2) {
|
} 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) {
|
} 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) {
|
} 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");
|
fprintf(fp, "lru");
|
||||||
} else {
|
} else {
|
||||||
fprintf(fp, "none");
|
fprintf(fp, "none");
|
||||||
@@ -1559,12 +1561,14 @@ void add_entry(char *key, char *value)
|
|||||||
gtk_combo_box_set_active(GTK_COMBO_BOX(taskbar_sort_order), 0);
|
gtk_combo_box_set_active(GTK_COMBO_BOX(taskbar_sort_order), 0);
|
||||||
else if (strcmp(value, "title") == 0)
|
else if (strcmp(value, "title") == 0)
|
||||||
gtk_combo_box_set_active(GTK_COMBO_BOX(taskbar_sort_order), 1);
|
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);
|
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);
|
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);
|
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
|
else
|
||||||
gtk_combo_box_set_active(GTK_COMBO_BOX(taskbar_sort_order), 0);
|
gtk_combo_box_set_active(GTK_COMBO_BOX(taskbar_sort_order), 0);
|
||||||
} else if (strcmp(key, "task_align") == 0) {
|
} else if (strcmp(key, "task_align") == 0) {
|
||||||
|
|||||||
+4
-4
@@ -478,14 +478,14 @@ void draw(Area *a)
|
|||||||
a->_clear(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);
|
cairo_t *c = cairo_create(cs);
|
||||||
|
|
||||||
draw_background(a, c);
|
draw_background(a, c);
|
||||||
|
|
||||||
if (a->_draw_foreground)
|
if (a->_draw_foreground)
|
||||||
a->_draw_foreground(a, c);
|
a->_draw_foreground(a, c);
|
||||||
|
|
||||||
|
draw_cairo_surface_to_xpixmap(cs, a->pix);
|
||||||
cairo_destroy(c);
|
cairo_destroy(c);
|
||||||
cairo_surface_destroy(cs);
|
cairo_surface_destroy(cs);
|
||||||
}
|
}
|
||||||
@@ -1084,7 +1084,7 @@ void draw_text_area(Area *area,
|
|||||||
pango_layout_set_font_description(layout, line1_font_desc);
|
pango_layout_set_font_description(layout, line1_font_desc);
|
||||||
pango_layout_set_text(layout, line1, strlen(line1));
|
pango_layout_set_text(layout, line1, strlen(line1));
|
||||||
pango_cairo_update_layout(c, layout);
|
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]) {
|
if (line2 && line2[0]) {
|
||||||
@@ -1092,7 +1092,7 @@ void draw_text_area(Area *area,
|
|||||||
pango_layout_set_indent(layout, 0);
|
pango_layout_set_indent(layout, 0);
|
||||||
pango_layout_set_text(layout, line2, strlen(line2));
|
pango_layout_set_text(layout, line2, strlen(line2));
|
||||||
pango_cairo_update_layout(c, layout);
|
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(layout);
|
||||||
|
|||||||
+268
@@ -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
|
||||||
@@ -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
|
||||||
+74
-57
@@ -48,18 +48,10 @@
|
|||||||
#include <librsvg/rsvg.h>
|
#include <librsvg/rsvg.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_LIBUNWIND
|
|
||||||
#define UNW_LOCAL_ONLY
|
|
||||||
#include <libunwind.h>
|
|
||||||
#else
|
|
||||||
#ifdef ENABLE_EXECINFO
|
|
||||||
#include <execinfo.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "../panel.h"
|
#include "../panel.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "signals.h"
|
#include "signals.h"
|
||||||
|
#include "bt.h"
|
||||||
|
|
||||||
void write_string(int fd, const char *s)
|
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)
|
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");
|
log_string(log_fd, "\n" YELLOW "Backtrace:" RESET "\n");
|
||||||
|
for (size_t i = 0; i < bt.frame_count; i++) {
|
||||||
#ifdef ENABLE_LIBUNWIND
|
log_string(log_fd, bt.frames[i].name);
|
||||||
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);
|
|
||||||
log_string(log_fd, "\n");
|
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.
|
// 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
|
// Allow children to exist after parent destruction
|
||||||
setsid();
|
setsid();
|
||||||
// Run the command
|
// Run the command
|
||||||
if (dir)
|
if (dir) {
|
||||||
chdir(dir);
|
int ret = chdir(dir);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf(stderr, "tint2: failed to chdir to %s\n", dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
close_all_fds();
|
close_all_fds();
|
||||||
reset_signals();
|
reset_signals();
|
||||||
if (terminal) {
|
if (terminal) {
|
||||||
@@ -758,9 +728,37 @@ void render_image(Drawable d, int x, int y)
|
|||||||
XFreePixmap(server.display, pixmap);
|
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)
|
||||||
|
{
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
if (font_shadow) {
|
|
||||||
const int shadow_size = 3;
|
const int shadow_size = 3;
|
||||||
const double shadow_edge_alpha = 0.0;
|
const double shadow_edge_alpha = 0.0;
|
||||||
int i, j;
|
int i, j;
|
||||||
@@ -773,12 +771,17 @@ void draw_text(PangoLayout *layout, cairo_t *c, int posx, int posy, Color *color
|
|||||||
1.0 -
|
1.0 -
|
||||||
(1.0 - shadow_edge_alpha) *
|
(1.0 - shadow_edge_alpha) *
|
||||||
sqrt((i * i + j * j) / (double)(shadow_size * shadow_size)));
|
sqrt((i * i + j * j) / (double)(shadow_size * shadow_size)));
|
||||||
pango_cairo_update_layout(c, layout);
|
pango_cairo_update_layout(c, shadow_layout);
|
||||||
cairo_move_to(c, posx + i, posy + j);
|
cairo_move_to(c, posx + i, posy + j);
|
||||||
pango_cairo_show_layout(c, layout);
|
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);
|
cairo_set_source_rgba(c, color->rgb[0], color->rgb[1], color->rgb[2], color->alpha);
|
||||||
pango_cairo_update_layout(c, layout);
|
pango_cairo_update_layout(c, layout);
|
||||||
cairo_move_to(c, posx, posy);
|
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 load_image(const char *path, int cached)
|
||||||
{
|
{
|
||||||
Imlib_Image image;
|
Imlib_Image image;
|
||||||
|
static unsigned long counter = 0;
|
||||||
|
if (debug_icons)
|
||||||
|
fprintf(stderr, "tint2: loading icon %s\n", path);
|
||||||
#ifdef HAVE_RSVG
|
#ifdef HAVE_RSVG
|
||||||
if (cached) {
|
image = imlib_load_image(path);
|
||||||
image = imlib_load_image_immediately(path);
|
|
||||||
} else {
|
|
||||||
image = imlib_load_image_immediately_without_cache(path);
|
|
||||||
}
|
|
||||||
if (!image && g_str_has_suffix(path, ".svg")) {
|
if (!image && g_str_has_suffix(path, ".svg")) {
|
||||||
char tmp_filename[128];
|
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);
|
int fd = open(tmp_filename, O_CREAT | O_EXCL, 0600);
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
// We fork here because librsvg allocates memory like crazy
|
// We fork here because librsvg allocates memory like crazy
|
||||||
@@ -818,19 +821,17 @@ Imlib_Image load_image(const char *path, int cached)
|
|||||||
// Parent
|
// Parent
|
||||||
close(fd);
|
close(fd);
|
||||||
waitpid(pid, 0, 0);
|
waitpid(pid, 0, 0);
|
||||||
image = imlib_load_image_immediately_without_cache(tmp_filename);
|
image = imlib_load_image_immediately(tmp_filename);
|
||||||
unlink(tmp_filename);
|
unlink(tmp_filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if (cached) {
|
image = imlib_load_image(path);
|
||||||
image = imlib_load_image_immediately(path);
|
|
||||||
} else {
|
|
||||||
image = imlib_load_image_immediately_without_cache(path);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
imlib_context_set_image(image);
|
||||||
|
imlib_image_set_changes_on_disk();
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1228,3 +1229,19 @@ void dump_image_data(const char *file_name, const char *name)
|
|||||||
|
|
||||||
imlib_free_image();
|
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);
|
||||||
|
}
|
||||||
|
|||||||
+4
-1
@@ -126,7 +126,8 @@ void get_text_size2(const PangoFontDescription *font,
|
|||||||
gboolean markup,
|
gboolean markup,
|
||||||
double scale);
|
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
|
// Draws a rounded rectangle
|
||||||
void draw_rect(cairo_t *c, double x, double y, double w, double h, double r);
|
void draw_rect(cairo_t *c, double x, double y, double w, double h, double r);
|
||||||
@@ -153,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 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) \
|
#define free_and_null(p) \
|
||||||
{ \
|
{ \
|
||||||
free(p); \
|
free(p); \
|
||||||
|
|||||||
+331
@@ -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);
|
||||||
|
}
|
||||||
+4
-2
@@ -36,8 +36,9 @@
|
|||||||
|
|
||||||
Server server;
|
Server server;
|
||||||
|
|
||||||
void server_catch_error(Display *d, XErrorEvent *ev)
|
int server_catch_error(Display *d, XErrorEvent *ev)
|
||||||
{
|
{
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void server_init_atoms()
|
void server_init_atoms()
|
||||||
@@ -676,9 +677,10 @@ void handle_crash(const char *reason)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void x11_io_error(Display *display)
|
int x11_io_error(Display *display)
|
||||||
{
|
{
|
||||||
handle_crash("X11 I/O error");
|
handle_crash("X11 I/O error");
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_SN
|
#ifdef HAVE_SN
|
||||||
|
|||||||
+2
-2
@@ -164,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);
|
int get_property32(Window win, Atom at, Atom type);
|
||||||
void *server_get_property(Window win, Atom at, Atom type, int *num_results);
|
void *server_get_property(Window win, Atom at, Atom type, int *num_results);
|
||||||
Atom server_get_atom(char *atom_name);
|
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_atoms();
|
||||||
void server_init_visual();
|
void server_init_visual();
|
||||||
void server_init_xdamage();
|
void server_init_xdamage();
|
||||||
|
|
||||||
void x11_io_error(Display *display);
|
int x11_io_error(Display *display);
|
||||||
void handle_crash(const char *reason);
|
void handle_crash(const char *reason);
|
||||||
|
|
||||||
// detect root background
|
// detect root background
|
||||||
|
|||||||
+2
-1
@@ -25,6 +25,7 @@
|
|||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "test.h"
|
#include "test.h"
|
||||||
|
|
||||||
|
bool warnings_for_timers = true;
|
||||||
bool debug_timers = false;
|
bool debug_timers = false;
|
||||||
#define MOCK_ORIGIN 1000000
|
#define MOCK_ORIGIN 1000000
|
||||||
|
|
||||||
@@ -59,7 +60,7 @@ void init_timer(Timer *timer, const char *name)
|
|||||||
|
|
||||||
void destroy_timer(Timer *timer)
|
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_);
|
fprintf(stderr, RED "tint2: Attempt to destroy nonexisting timer: %s" RESET "\n", timer->name_);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include "bool.h"
|
#include "bool.h"
|
||||||
|
|
||||||
|
extern bool warnings_for_timers;
|
||||||
extern bool debug_timers;
|
extern bool debug_timers;
|
||||||
|
|
||||||
typedef void TimerCallback(void *arg);
|
typedef void TimerCallback(void *arg);
|
||||||
|
|||||||
+110
-115
@@ -21,6 +21,7 @@
|
|||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
|
#include <X11/extensions/Xrender.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -383,28 +384,42 @@ void smooth_thumbnail(cairo_surface_t *image_surface)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is measured to be slightly faster.
|
// This is measured to be slightly faster than XGetPixel.
|
||||||
#define GetPixel(ximg, x, y) ((u_int32_t *)&(ximg->data[y * ximg->bytes_per_line]))[x]
|
static u_int32_t GetPixel(XImage *ximg, unsigned x, unsigned y)
|
||||||
//#define GetPixel XGetPixel
|
{
|
||||||
|
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)
|
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;
|
cairo_surface_t *result = NULL;
|
||||||
XWindowAttributes wa;
|
XWindowAttributes wa;
|
||||||
if (!XGetWindowAttributes(server.display, win, &wa) || wa.width <= 0 || wa.height <= 0 ||
|
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;
|
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;
|
goto err0;
|
||||||
|
}
|
||||||
|
|
||||||
size_t w, h;
|
size_t w, h;
|
||||||
w = (size_t)wa.width;
|
w = (size_t)wa.width + wa.x;
|
||||||
h = (size_t)wa.height;
|
h = (size_t)wa.height + wa.y;
|
||||||
size_t tw, th, fw;
|
size_t tw, th, fw;
|
||||||
size_t ox, oy;
|
size_t ox, oy;
|
||||||
tw = size;
|
tw = size;
|
||||||
th = h * tw / w;
|
th = h * tw / w;
|
||||||
|
double scale = th / (double)h;
|
||||||
if (th > tw * 0.618) {
|
if (th > tw * 0.618) {
|
||||||
th = (size_t)(tw * 0.618);
|
th = (size_t)(tw * 0.618);
|
||||||
fw = w * th / h;
|
fw = w * th / h;
|
||||||
@@ -414,20 +429,69 @@ cairo_surface_t *get_window_thumbnail_ximage(Window win, size_t size, gboolean u
|
|||||||
fw = tw;
|
fw = tw;
|
||||||
ox = oy = 0;
|
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 = NULL;
|
||||||
XImage *ximg;
|
|
||||||
if (use_shm)
|
XGetWindowAttributes(server.display, win, &wa);
|
||||||
ximg = XShmCreateImage(server.display,
|
if (wa.map_state != IsViewable) {
|
||||||
wa.visual,
|
fprintf(stderr, YELLOW "tint2: win=%u: no thumbnail for non-viewable window" RESET "\n", win);
|
||||||
(unsigned)wa.depth,
|
goto err4;
|
||||||
ZPixmap,
|
}
|
||||||
NULL,
|
|
||||||
&shminfo,
|
Pixmap pix = XCreatePixmap(server.display, win, tw, th, wa.depth);
|
||||||
(unsigned)w,
|
if (!pix) {
|
||||||
(unsigned)h);
|
fprintf(stderr, YELLOW "tint2: win=%u: no pixmap" RESET "\n", win);
|
||||||
else
|
goto err4;
|
||||||
ximg = XGetImage(server.display, win, 0, 0, (unsigned)w, (unsigned)h, AllPlanes, ZPixmap);
|
}
|
||||||
|
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) {
|
if (!ximg) {
|
||||||
fprintf(stderr, RED "tint2: !ximg" RESET "\n");
|
fprintf(stderr, RED "tint2: !ximg" RESET "\n");
|
||||||
goto err0;
|
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");
|
fprintf(stderr, RED "tint2: unusual bits_per_pixel" RESET "\n");
|
||||||
goto err1;
|
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);
|
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);
|
u_int32_t *data = (u_int32_t *)cairo_image_surface_get_data(result);
|
||||||
memset(data, 0, tw * th);
|
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 rmask = (u_int32_t)ximg->red_mask;
|
||||||
const u_int32_t gmask = (u_int32_t)ximg->green_mask;
|
const u_int32_t gmask = (u_int32_t)ximg->green_mask;
|
||||||
const u_int32_t bmask = (u_int32_t)ximg->blue_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 y = 0; y < th; y++) {
|
||||||
for (size_t xt = 0, x = 0; xt < fw; xt++, x += xstep) {
|
for (size_t x = 0; x < tw; x++) {
|
||||||
size_t j = yt * tw + ox + xt;
|
u_int32_t c = (u_int32_t)XGetPixel(ximg, x, y);
|
||||||
u_int32_t c1 = (u_int32_t)GetPixel(ximg, (int)((x + offset_x1) / prec), (int)((y + offset_y1) / prec));
|
data[y * tw + x] = c;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
// Convert to argb32
|
||||||
if (rmask & 0xff0000) {
|
if (rmask & 0xff0000) {
|
||||||
// argb32 or rgb24 => Nothing to do
|
// 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
|
// 2nd pass
|
||||||
smooth_thumbnail(result);
|
//smooth_thumbnail(result);
|
||||||
|
cairo_surface_flush(result);
|
||||||
|
|
||||||
if (ximg) {
|
if (ximg) {
|
||||||
XDestroyImage(ximg);
|
XDestroyImage(ximg);
|
||||||
ximg = NULL;
|
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:
|
err1:
|
||||||
|
err4:
|
||||||
if (ximg)
|
if (ximg)
|
||||||
XDestroyImage(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:
|
err0:
|
||||||
return result;
|
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 *get_window_thumbnail(Window win, int size)
|
||||||
{
|
{
|
||||||
cairo_surface_t *image_surface = NULL;
|
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) {
|
if (!image_surface) {
|
||||||
image_surface = get_window_thumbnail_ximage(win, (size_t)size, FALSE);
|
image_surface = get_window_thumbnail_ximage(win, (size_t)size, FALSE);
|
||||||
if (image_surface && cairo_surface_is_blank(image_surface)) {
|
if (image_surface && cairo_surface_is_blank(image_surface)) {
|
||||||
|
fprintf(stderr, RED "tint2: captured blank thumbnail" RESET "\n");
|
||||||
cairo_surface_destroy(image_surface);
|
cairo_surface_destroy(image_surface);
|
||||||
image_surface = NULL;
|
image_surface = NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ clock_dwheel_command =
|
|||||||
# Battery
|
# Battery
|
||||||
battery_tooltip = 1
|
battery_tooltip = 1
|
||||||
battery_low_status = 10
|
battery_low_status = 10
|
||||||
battery_low_cmd = notify-send "battery low"
|
battery_low_cmd = xmessage 'tint2: Battery low!'
|
||||||
battery_full_cmd =
|
battery_full_cmd =
|
||||||
bat1_font = sans 8
|
bat1_font = sans 8
|
||||||
bat2_font = sans 6
|
bat2_font = sans 6
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ clock_dwheel_command =
|
|||||||
# Battery
|
# Battery
|
||||||
battery_tooltip = 1
|
battery_tooltip = 1
|
||||||
battery_low_status = 10
|
battery_low_status = 10
|
||||||
battery_low_cmd = notify-send "battery low"
|
battery_low_cmd = xmessage 'tint2: Battery low!'
|
||||||
battery_full_cmd =
|
battery_full_cmd =
|
||||||
bat1_font = sans 8
|
bat1_font = sans 8
|
||||||
bat2_font = sans 6
|
bat2_font = sans 6
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ clock_dwheel_command =
|
|||||||
# Battery
|
# Battery
|
||||||
battery_tooltip = 1
|
battery_tooltip = 1
|
||||||
battery_low_status = 10
|
battery_low_status = 10
|
||||||
battery_low_cmd = notify-send "battery low"
|
battery_low_cmd = xmessage 'tint2: Battery low!'
|
||||||
battery_full_cmd =
|
battery_full_cmd =
|
||||||
bat1_font = sans 8
|
bat1_font = sans 8
|
||||||
bat2_font = sans 6
|
bat2_font = sans 6
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ clock_dwheel_command =
|
|||||||
# Battery
|
# Battery
|
||||||
battery_tooltip = 1
|
battery_tooltip = 1
|
||||||
battery_low_status = 10
|
battery_low_status = 10
|
||||||
battery_low_cmd = notify-send "battery low"
|
battery_low_cmd = xmessage 'tint2: Battery low!'
|
||||||
battery_full_cmd =
|
battery_full_cmd =
|
||||||
bat1_font = sans 8
|
bat1_font = sans 8
|
||||||
bat2_font = sans 6
|
bat2_font = sans 6
|
||||||
|
|||||||
+1
-1
@@ -175,7 +175,7 @@ clock_dwheel_command =
|
|||||||
# Battery
|
# Battery
|
||||||
battery_tooltip = 1
|
battery_tooltip = 1
|
||||||
battery_low_status = 10
|
battery_low_status = 10
|
||||||
battery_low_cmd = notify-send "battery low"
|
battery_low_cmd = xmessage 'tint2: Battery low!'
|
||||||
battery_full_cmd =
|
battery_full_cmd =
|
||||||
battery_font_color = #ffffff 100
|
battery_font_color = #ffffff 100
|
||||||
bat1_format =
|
bat1_format =
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ clock_dwheel_command =
|
|||||||
# Battery
|
# Battery
|
||||||
battery_tooltip = 1
|
battery_tooltip = 1
|
||||||
battery_low_status = 10
|
battery_low_status = 10
|
||||||
battery_low_cmd = notify-send "battery low"
|
battery_low_cmd = xmessage 'tint2: Battery low!'
|
||||||
battery_full_cmd =
|
battery_full_cmd =
|
||||||
bat1_font = sans 8
|
bat1_font = sans 8
|
||||||
bat2_font = sans 6
|
bat2_font = sans 6
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ clock_dwheel_command =
|
|||||||
# Battery
|
# Battery
|
||||||
battery_tooltip = 1
|
battery_tooltip = 1
|
||||||
battery_low_status = 10
|
battery_low_status = 10
|
||||||
battery_low_cmd = notify-send "battery low"
|
battery_low_cmd = xmessage 'tint2: Battery low!'
|
||||||
battery_full_cmd =
|
battery_full_cmd =
|
||||||
bat1_font = sans 8
|
bat1_font = sans 8
|
||||||
bat2_font = sans 6
|
bat2_font = sans 6
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ clock_dwheel_command =
|
|||||||
# Battery
|
# Battery
|
||||||
battery_tooltip = 1
|
battery_tooltip = 1
|
||||||
battery_low_status = 10
|
battery_low_status = 10
|
||||||
battery_low_cmd = notify-send "battery low"
|
battery_low_cmd = xmessage 'tint2: Battery low!'
|
||||||
battery_full_cmd =
|
battery_full_cmd =
|
||||||
bat1_font = sans 8
|
bat1_font = sans 8
|
||||||
bat2_font = sans 6
|
bat2_font = sans 6
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ clock_dwheel_command =
|
|||||||
# Battery
|
# Battery
|
||||||
battery_tooltip = 1
|
battery_tooltip = 1
|
||||||
battery_low_status = 10
|
battery_low_status = 10
|
||||||
battery_low_cmd = notify-send "battery low"
|
battery_low_cmd = xmessage 'tint2: Battery low!'
|
||||||
battery_full_cmd =
|
battery_full_cmd =
|
||||||
bat1_font = sans 8
|
bat1_font = sans 8
|
||||||
bat2_font = sans 6
|
bat2_font = sans 6
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
configure
|
||||||
doc/tint2.1
|
doc/tint2.1
|
||||||
sample/icon_and_text_1.tint2rc
|
sample/icon_and_text_1.tint2rc
|
||||||
sample/icon_and_text_2.tint2rc
|
sample/icon_and_text_2.tint2rc
|
||||||
@@ -59,6 +60,8 @@ src/util/area.c
|
|||||||
src/util/area.h
|
src/util/area.h
|
||||||
src/util/blur.c
|
src/util/blur.c
|
||||||
src/util/blur.h
|
src/util/blur.h
|
||||||
|
src/util/bt.c
|
||||||
|
src/util/bt.h
|
||||||
src/util/common.c
|
src/util/common.c
|
||||||
src/util/common.h
|
src/util/common.h
|
||||||
src/util/server.c
|
src/util/server.c
|
||||||
|
|||||||
Reference in New Issue
Block a user