Compare commits
83 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
01f823cf79 | ||
|
|
978e1c90fc | ||
|
|
3fba8aa1cf | ||
|
|
26251849c6 | ||
|
|
abeb7ce2e6 | ||
|
|
abdb1aeff9 | ||
|
|
7e383c395e | ||
|
|
c3ed2dadf3 | ||
|
|
bd2ca94ffe | ||
|
|
1753641fc9 | ||
|
|
467ea1332c | ||
|
|
68c2ad7062 | ||
|
|
cc5842463d | ||
|
|
5e124c7a97 | ||
|
|
07865142b2 | ||
|
|
0c71fda5e1 | ||
|
|
8eaf187984 | ||
|
|
abe8a0eeb1 | ||
|
|
d82d782541 | ||
|
|
715eb556da | ||
|
|
b9e64da9da | ||
|
|
224b7fba82 | ||
|
|
d72fff9653 | ||
|
|
67c3e47414 | ||
|
|
e96e7fbee7 | ||
|
|
65c91667f9 | ||
|
|
9f4087b471 | ||
|
|
247687307b | ||
|
|
2c9d1fdf7d | ||
|
|
500b8f5bea | ||
|
|
7e6f7df55e | ||
|
|
47201cab84 | ||
|
|
f7d083904f | ||
|
|
f11d30f076 | ||
|
|
c0eaa8274f | ||
|
|
38488b8d75 | ||
|
|
07339c09a0 | ||
|
|
0521223899 | ||
|
|
cbf3cebbb0 | ||
|
|
4b50446a7b | ||
|
|
e8a6c93b28 | ||
|
|
5e6e1184fe | ||
|
|
89ab1fa6c4 | ||
|
|
e597973cd7 | ||
|
|
ebe30774ac | ||
|
|
d463dcb5b4 | ||
|
|
23782a4414 | ||
|
|
1be85e66fe | ||
|
|
2fe7efd4fe | ||
|
|
1b6fd91611 | ||
|
|
5730725762 | ||
|
|
87da8c76cc | ||
|
|
e5ecc0c15d | ||
|
|
812e306376 | ||
|
|
3155a5fc89 | ||
|
|
bc4af51e82 | ||
|
|
01de174919 | ||
|
|
7ddb373cb4 | ||
|
|
8ba1f26309 | ||
|
|
5a867a83c6 | ||
|
|
8a7e7e4281 | ||
|
|
0e8a6dd961 | ||
|
|
c4a0ec4140 | ||
|
|
07d907fc43 | ||
|
|
b1f83baf04 | ||
|
|
1ff3404e56 | ||
|
|
41190204b3 | ||
|
|
5bc978ee44 | ||
|
|
3b4028f443 | ||
|
|
acc3ee9205 | ||
|
|
d8770ed590 | ||
|
|
be7873a688 | ||
|
|
cf81f1c9f9 | ||
|
|
cde05df1bc | ||
|
|
5fee459945 | ||
|
|
6d67291928 | ||
|
|
4171e23153 | ||
|
|
725f625aba | ||
|
|
a6ea1eb5a9 | ||
|
|
14b983cd0c | ||
|
|
23ddb47e0c | ||
|
|
407aef3786 | ||
|
|
50c7bf77de |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,3 +1,5 @@
|
|||||||
build
|
build
|
||||||
*.user
|
*.user
|
||||||
version.h
|
version.h
|
||||||
|
*.todo
|
||||||
|
*.pyc
|
||||||
|
|||||||
3
AUTHORS
3
AUTHORS
@@ -31,6 +31,7 @@ Contributors:
|
|||||||
Matthew Otnel : config option systray_name_filter
|
Matthew Otnel : config option systray_name_filter
|
||||||
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
|
||||||
|
|
||||||
Translations:
|
Translations:
|
||||||
Bosnian:
|
Bosnian:
|
||||||
@@ -45,3 +46,5 @@ Translations:
|
|||||||
Daniel Napora <napcok@gmail.com>
|
Daniel Napora <napcok@gmail.com>
|
||||||
Serbian:
|
Serbian:
|
||||||
Dino Duratović <dinomol@mail.com>
|
Dino Duratović <dinomol@mail.com>
|
||||||
|
Spanish:
|
||||||
|
Vic <vicmz@yandex.com>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ endif()
|
|||||||
include( FindPkgConfig )
|
include( FindPkgConfig )
|
||||||
include( CheckLibraryExists )
|
include( CheckLibraryExists )
|
||||||
include( CheckCSourceCompiles )
|
include( CheckCSourceCompiles )
|
||||||
pkg_check_modules( X11 REQUIRED x11 xcomposite xdamage xinerama xrender xrandr>=1.3 )
|
pkg_check_modules( X11 REQUIRED x11 xcomposite xdamage xinerama xext xrender xrandr>=1.3 )
|
||||||
pkg_check_modules( PANGOCAIRO REQUIRED pangocairo )
|
pkg_check_modules( PANGOCAIRO REQUIRED pangocairo )
|
||||||
pkg_check_modules( PANGO REQUIRED pango )
|
pkg_check_modules( PANGO REQUIRED pango )
|
||||||
pkg_check_modules( CAIRO REQUIRED cairo )
|
pkg_check_modules( CAIRO REQUIRED cairo )
|
||||||
@@ -147,6 +147,9 @@ set( SOURCES src/config.c
|
|||||||
src/util/cache.c
|
src/util/cache.c
|
||||||
src/util/color.c
|
src/util/color.c
|
||||||
src/util/gradient.c
|
src/util/gradient.c
|
||||||
|
src/util/addr2line.c
|
||||||
|
src/util/print.c
|
||||||
|
src/util/mem.c
|
||||||
src/util/uevent.c
|
src/util/uevent.c
|
||||||
src/util/window.c )
|
src/util/window.c )
|
||||||
|
|
||||||
@@ -265,15 +268,20 @@ if( RT_LIBRARY )
|
|||||||
endif( RT_LIBRARY )
|
endif( RT_LIBRARY )
|
||||||
|
|
||||||
target_link_libraries( tint2 m )
|
target_link_libraries( tint2 m )
|
||||||
|
if(ENABLE_BACKTRACE)
|
||||||
|
target_link_libraries( tint2 dl )
|
||||||
|
target_link_libraries( tint2 z )
|
||||||
|
target_link_libraries( tint2 bfd )
|
||||||
|
endif(ENABLE_BACKTRACE)
|
||||||
|
|
||||||
add_dependencies( tint2 version )
|
add_dependencies( tint2 version )
|
||||||
set_target_properties( tint2 PROPERTIES COMPILE_FLAGS "-Wall -Wpointer-arith -fno-strict-aliasing -pthread -std=c99 ${ASAN_C_FLAGS} ${TRACING_C_FLAGS}" )
|
set_target_properties( tint2 PROPERTIES COMPILE_FLAGS "-Wall -Wpointer-arith -fno-strict-aliasing -pthread -std=c11 ${ASAN_C_FLAGS} ${TRACING_C_FLAGS}" )
|
||||||
set_target_properties( tint2 PROPERTIES LINK_FLAGS "-pthread -fno-strict-aliasing ${ASAN_L_FLAGS} ${BACKTRACE_L_FLAGS} ${TRACING_L_FLAGS}" )
|
set_target_properties( tint2 PROPERTIES LINK_FLAGS "-pthread -fno-strict-aliasing ${ASAN_L_FLAGS} ${BACKTRACE_L_FLAGS} ${TRACING_L_FLAGS}" )
|
||||||
|
|
||||||
install( TARGETS tint2 DESTINATION bin )
|
install( TARGETS tint2 DESTINATION bin )
|
||||||
install( FILES tint2.svg DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps )
|
install( FILES tint2.svg DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps )
|
||||||
install( FILES tint2.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications )
|
install( FILES tint2.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications )
|
||||||
install( FILES themes/tint2rc DESTINATION /etc/xdg/tint2 )
|
install( FILES themes/tint2rc DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/xdg/tint2 )
|
||||||
install( FILES default_icon.png DESTINATION ${CMAKE_INSTALL_DATADIR}/tint2 )
|
install( FILES default_icon.png DESTINATION ${CMAKE_INSTALL_DATADIR}/tint2 )
|
||||||
install( FILES AUTHORS ChangeLog README.md doc/tint2.md DESTINATION ${docdir} )
|
install( FILES AUTHORS ChangeLog README.md doc/tint2.md DESTINATION ${docdir} )
|
||||||
install( FILES doc/manual.html doc/readme.html DESTINATION ${htmldir} )
|
install( FILES doc/manual.html doc/readme.html DESTINATION ${htmldir} )
|
||||||
|
|||||||
12
ChangeLog
12
ChangeLog
@@ -1,3 +1,14 @@
|
|||||||
|
2017-11-10 master
|
||||||
|
- Enhancements:
|
||||||
|
- Added Spanish translation (contributed by Vicmz)
|
||||||
|
- Executor: updated tooltip documentation (issue #676)
|
||||||
|
- Systray: warn on duplicate config option systray_name_filter (issue #652)
|
||||||
|
|
||||||
|
2017-11-05 15.3
|
||||||
|
- Fixes:
|
||||||
|
- Launcher: Reset signal mask before executing commands (issue #674)
|
||||||
|
- cmake: Do not hardcode path to /etc
|
||||||
|
|
||||||
2017-10-01 15.2
|
2017-10-01 15.2
|
||||||
- Fixes:
|
- Fixes:
|
||||||
- Battery info is now again displayed even when current sensor is missing (https://github.com/jmc-88/tint3/issues/34)
|
- Battery info is now again displayed even when current sensor is missing (https://github.com/jmc-88/tint3/issues/34)
|
||||||
@@ -959,3 +970,4 @@ released tint-0.2
|
|||||||
.
|
.
|
||||||
.
|
.
|
||||||
.
|
.
|
||||||
|
.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Latest stable release: 15.2
|
# Latest stable release: 15.3
|
||||||
Changes: https://gitlab.com/o9000/tint2/blob/15.2/ChangeLog
|
Changes: https://gitlab.com/o9000/tint2/blob/15.3/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 15.2
|
git checkout 15.3
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake ..
|
cmake ..
|
||||||
|
|||||||
@@ -270,6 +270,8 @@ Try to respect as much as possible the order of the options as given below.</p><
|
|||||||
<li><code>color</code> is specified in hex RGB, e.g. #ff0000 is red</li>
|
<li><code>color</code> is specified in hex RGB, e.g. #ff0000 is red</li>
|
||||||
<li><code>opacity</code> varies from (0 to 100), where 0 is fully transparent, 100 is fully opaque</li>
|
<li><code>opacity</code> varies from (0 to 100), where 0 is fully transparent, 100 is fully opaque</li>
|
||||||
</ul></li>
|
</ul></li>
|
||||||
|
<li><p><code>border_content_tint_weight = integer</code> : Mixes the border color with the content color (for tasks, this is the average color of the window icon). Values must be between 0 (no mixing) and 100 (fully replaces the color). <em>(since 16.0)</em></p></li>
|
||||||
|
<li><p><code>background_content_tint_weight = integer</code> : Mixes the background color with the content color (for tasks, this is the average color of the window icon). Values must be between 0 (no mixing) and 100 (fully replaces the color). <em>(since 16.0)</em></p></li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>You can define as many backgrounds as you want. For example, the following config defines two backgrounds:</p><pre class="highlight plaintext"><code>rounded = 1
|
<p>You can define as many backgrounds as you want. For example, the following config defines two backgrounds:</p><pre class="highlight plaintext"><code>rounded = 1
|
||||||
border_width = 0
|
border_width = 0
|
||||||
@@ -481,6 +483,8 @@ panel_size = 94% 30
|
|||||||
<li><p><code>task_text = boolean (0 or 1)</code> : Whether to display the task text.</p></li>
|
<li><p><code>task_text = boolean (0 or 1)</code> : Whether to display the task text.</p></li>
|
||||||
<li><p><code>task_centered = boolean (0 or 1)</code> : Whether the task text is centered.</p></li>
|
<li><p><code>task_centered = boolean (0 or 1)</code> : Whether the task text is centered.</p></li>
|
||||||
<li><p><code>task_tooltip = boolean (0 or 1)</code> : Whether to show tooltips for tasks.</p></li>
|
<li><p><code>task_tooltip = boolean (0 or 1)</code> : Whether to show tooltips for tasks.</p></li>
|
||||||
|
<li><p><code>task_thumbnail = boolean (0 or 1)</code> : Whether to show thumbnail tooltips for tasks. <em>(since 16.0)</em></p></li>
|
||||||
|
<li><p><code>task_thumbnail_size = width</code> : Thumbnail size. <em>(since 16.0)</em></p></li>
|
||||||
<li><p><code>task_maximum_size = width height</code></p>
|
<li><p><code>task_maximum_size = width height</code></p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>width</code> is used with horizontal panels to limit the size of the tasks. Use <code>width = 0</code> to get full taskbar width.</li>
|
<li><code>width</code> is used with horizontal panels to limit the size of the tasks. Use <code>width = 0</code> to get full taskbar width.</li>
|
||||||
@@ -601,7 +605,7 @@ panel_size = 94% 30
|
|||||||
<li><p><code>execp_cache_icon = boolean (0 or 1)</code> : If <code>execp_cache_icon = 0</code>, the image is reloaded each time the command is executed (useful if the image file is changed on disk by the program executed by <code>execp_command</code>). <em>(since 0.12.4)</em></p></li>
|
<li><p><code>execp_cache_icon = boolean (0 or 1)</code> : If <code>execp_cache_icon = 0</code>, the image is reloaded each time the command is executed (useful if the image file is changed on disk by the program executed by <code>execp_command</code>). <em>(since 0.12.4)</em></p></li>
|
||||||
<li><p><code>execp_icon_w = integer</code> : You can use <code>execp_icon_w</code> and <code>execp_icon_h</code> to resize the image. If one of them is zero/missing, the image is rescaled proportionally. If both of them are zero/missing, the image is not rescaled. <em>(since 0.12.4)</em></p></li>
|
<li><p><code>execp_icon_w = integer</code> : You can use <code>execp_icon_w</code> and <code>execp_icon_h</code> to resize the image. If one of them is zero/missing, the image is rescaled proportionally. If both of them are zero/missing, the image is not rescaled. <em>(since 0.12.4)</em></p></li>
|
||||||
<li><p><code>execp_icon_h = integer</code> : See <code>execp_icon_w</code>. <em>(since 0.12.4)</em></p></li>
|
<li><p><code>execp_icon_h = integer</code> : See <code>execp_icon_w</code>. <em>(since 0.12.4)</em></p></li>
|
||||||
<li><p><code>execp_tooltip = text</code> : The tooltip. Leave it empty to not display a tooltip. Not specifying this option leads to showing an automatically generated tooltip with information about when the command was last executed. <em>(since 0.12.4)</em></p></li>
|
<li><p><code>execp_tooltip = text</code> : The tooltip. If left empty, no tooltip is displayed. If missing, the standard error of the command is shown as a tooltip (an ANSI clear screen sequence can reset the contents, bash: <code>printf '\e[2J'</code>, C: <code>printf("\x1b[2J");</code>). If the standard error is empty, the tooltip will show information about the time when the command was last executed. <em>(since 0.12.4)</em></p></li>
|
||||||
<li><p><code>execp_font = [FAMILY-LIST] [STYLE-OPTIONS] [SIZE]</code> : The font used to draw the text. <em>(since 0.12.4)</em></p></li>
|
<li><p><code>execp_font = [FAMILY-LIST] [STYLE-OPTIONS] [SIZE]</code> : The font used to draw the text. <em>(since 0.12.4)</em></p></li>
|
||||||
<li><p><code>execp_font_color = color opacity</code> : The font color. <em>(since 0.12.4)</em></p></li>
|
<li><p><code>execp_font_color = color opacity</code> : The font color. <em>(since 0.12.4)</em></p></li>
|
||||||
<li><p><code>execp_markup = boolean (0 or 1)</code> : If non-zero, the output of the command is treated as Pango markup, which allows rich text formatting. The format is <a href="https://developer.gnome.org/pygtk/stable/pango-markup-language.html">documented here</a>. Note that using this with commands that print data downloaded from the Internet is a possible security risk. <em>(since 0.12.4)</em></p></li>
|
<li><p><code>execp_markup = boolean (0 or 1)</code> : If non-zero, the output of the command is treated as Pango markup, which allows rich text formatting. The format is <a href="https://developer.gnome.org/pygtk/stable/pango-markup-language.html">documented here</a>. Note that using this with commands that print data downloaded from the Internet is a possible security risk. <em>(since 0.12.4)</em></p></li>
|
||||||
|
|||||||
@@ -199,9 +199,9 @@ pre {
|
|||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1 id="latest-stable-release-15-2"><span class="md2man-title">Latest</span> <span class="md2man-section">stable</span> <span class="md2man-date">release:</span> <span class="md2man-source">15.2</span><a name="latest-stable-release-15-2" href="#latest-stable-release-15-2" class="md2man-permalink" title="permalink"></a></h1><p>Changes: <a href="https://gitlab.com/o9000/tint2/blob/15.2/ChangeLog">https://gitlab.com/o9000/tint2/blob/15.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-15-3"><span class="md2man-title">Latest</span> <span class="md2man-section">stable</span> <span class="md2man-date">release:</span> <span class="md2man-source">15.3</span><a name="latest-stable-release-15-3" href="#latest-stable-release-15-3" class="md2man-permalink" title="permalink"></a></h1><p>Changes: <a href="https://gitlab.com/o9000/tint2/blob/15.3/ChangeLog">https://gitlab.com/o9000/tint2/blob/15.3/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 15.2
|
git checkout 15.3
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake ..
|
cmake ..
|
||||||
|
|||||||
12
doc/tint2.1
12
doc/tint2.1
@@ -1,4 +1,4 @@
|
|||||||
.TH TINT2 1 "2017\-10\-01" 15.2
|
.TH TINT2 1 "2017\-11\-05" 15.3
|
||||||
.SH NAME
|
.SH NAME
|
||||||
.PP
|
.PP
|
||||||
tint2 \- lightweight panel/taskbar
|
tint2 \- lightweight panel/taskbar
|
||||||
@@ -150,6 +150,10 @@ The tint2 config file starts with the options defining background elements with
|
|||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\fB\fCopacity\fR varies from (0 to 100), where 0 is fully transparent, 100 is fully opaque
|
\fB\fCopacity\fR varies from (0 to 100), where 0 is fully transparent, 100 is fully opaque
|
||||||
.RE
|
.RE
|
||||||
|
.IP \(bu 2
|
||||||
|
\fB\fCborder_content_tint_weight = integer\fR : Mixes the border color with the content color (for tasks, this is the average color of the window icon). Values must be between 0 (no mixing) and 100 (fully replaces the color). \fI(since 16.0)\fP
|
||||||
|
.IP \(bu 2
|
||||||
|
\fB\fCbackground_content_tint_weight = integer\fR : Mixes the background color with the content color (for tasks, this is the average color of the window icon). Values must be between 0 (no mixing) and 100 (fully replaces the color). \fI(since 16.0)\fP
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
You can define as many backgrounds as you want. For example, the following config defines two backgrounds:
|
You can define as many backgrounds as you want. For example, the following config defines two backgrounds:
|
||||||
@@ -508,6 +512,10 @@ The following options configure the task buttons in the taskbar:
|
|||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\fB\fCtask_tooltip = boolean (0 or 1)\fR : Whether to show tooltips for tasks.
|
\fB\fCtask_tooltip = boolean (0 or 1)\fR : Whether to show tooltips for tasks.
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
|
\fB\fCtask_thumbnail = boolean (0 or 1)\fR : Whether to show thumbnail tooltips for tasks. \fI(since 16.0)\fP
|
||||||
|
.IP \(bu 2
|
||||||
|
\fB\fCtask_thumbnail_size = width\fR : Thumbnail size. \fI(since 16.0)\fP
|
||||||
|
.IP \(bu 2
|
||||||
\fB\fCtask_maximum_size = width height\fR
|
\fB\fCtask_maximum_size = width height\fR
|
||||||
.RS
|
.RS
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
@@ -716,7 +724,7 @@ To hide the clock, comment \fB\fCtime1_format\fR and \fB\fCtime2_format\fR\&.
|
|||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\fB\fCexecp_icon_h = integer\fR : See \fB\fCexecp_icon_w\fR\&. \fI(since 0.12.4)\fP
|
\fB\fCexecp_icon_h = integer\fR : See \fB\fCexecp_icon_w\fR\&. \fI(since 0.12.4)\fP
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\fB\fCexecp_tooltip = text\fR : The tooltip. Leave it empty to not display a tooltip. Not specifying this option leads to showing an automatically generated tooltip with information about when the command was last executed. \fI(since 0.12.4)\fP
|
\fB\fCexecp_tooltip = text\fR : The tooltip. If left empty, no tooltip is displayed. If missing, the standard error of the command is shown as a tooltip (an ANSI clear screen sequence can reset the contents, bash: \fB\fCprintf '\\e[2J'\fR, C: \fB\fCprintf("\\x1b[2J");\fR). If the standard error is empty, the tooltip will show information about the time when the command was last executed. \fI(since 0.12.4)\fP
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
\fB\fCexecp_font = [FAMILY\-LIST] [STYLE\-OPTIONS] [SIZE]\fR : The font used to draw the text. \fI(since 0.12.4)\fP
|
\fB\fCexecp_font = [FAMILY\-LIST] [STYLE\-OPTIONS] [SIZE]\fR : The font used to draw the text. \fI(since 0.12.4)\fP
|
||||||
.IP \(bu 2
|
.IP \(bu 2
|
||||||
|
|||||||
12
doc/tint2.md
12
doc/tint2.md
@@ -1,4 +1,4 @@
|
|||||||
# TINT2 1 "2017-10-01" 15.2
|
# TINT2 1 "2017-11-05" 15.3
|
||||||
|
|
||||||
## NAME
|
## NAME
|
||||||
tint2 - lightweight panel/taskbar
|
tint2 - lightweight panel/taskbar
|
||||||
@@ -119,6 +119,10 @@ The tint2 config file starts with the options defining background elements with
|
|||||||
* `color` is specified in hex RGB, e.g. #ff0000 is red
|
* `color` is specified in hex RGB, e.g. #ff0000 is red
|
||||||
* `opacity` varies from (0 to 100), where 0 is fully transparent, 100 is fully opaque
|
* `opacity` varies from (0 to 100), where 0 is fully transparent, 100 is fully opaque
|
||||||
|
|
||||||
|
* `border_content_tint_weight = integer` : Mixes the border color with the content color (for tasks, this is the average color of the window icon). Values must be between 0 (no mixing) and 100 (fully replaces the color). *(since 16.0)*
|
||||||
|
|
||||||
|
* `background_content_tint_weight = integer` : Mixes the background color with the content color (for tasks, this is the average color of the window icon). Values must be between 0 (no mixing) and 100 (fully replaces the color). *(since 16.0)*
|
||||||
|
|
||||||
You can define as many backgrounds as you want. For example, the following config defines two backgrounds:
|
You can define as many backgrounds as you want. For example, the following config defines two backgrounds:
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -409,6 +413,10 @@ The following options configure the task buttons in the taskbar:
|
|||||||
|
|
||||||
* `task_tooltip = boolean (0 or 1)` : Whether to show tooltips for tasks.
|
* `task_tooltip = boolean (0 or 1)` : Whether to show tooltips for tasks.
|
||||||
|
|
||||||
|
* `task_thumbnail = boolean (0 or 1)` : Whether to show thumbnail tooltips for tasks. *(since 16.0)*
|
||||||
|
|
||||||
|
* `task_thumbnail_size = width` : Thumbnail size. *(since 16.0)*
|
||||||
|
|
||||||
* `task_maximum_size = width height`
|
* `task_maximum_size = width height`
|
||||||
* `width` is used with horizontal panels to limit the size of the tasks. Use `width = 0` to get full taskbar width.
|
* `width` is used with horizontal panels to limit the size of the tasks. Use `width = 0` to get full taskbar width.
|
||||||
* `height` is used with vertical panels.
|
* `height` is used with vertical panels.
|
||||||
@@ -591,7 +599,7 @@ The action semantics:
|
|||||||
|
|
||||||
* `execp_icon_h = integer` : See `execp_icon_w`. *(since 0.12.4)*
|
* `execp_icon_h = integer` : See `execp_icon_w`. *(since 0.12.4)*
|
||||||
|
|
||||||
* `execp_tooltip = text` : The tooltip. Leave it empty to not display a tooltip. Not specifying this option leads to showing an automatically generated tooltip with information about when the command was last executed. *(since 0.12.4)*
|
* `execp_tooltip = text` : The tooltip. If left empty, no tooltip is displayed. If missing, the standard error of the command is shown as a tooltip (an ANSI clear screen sequence can reset the contents, bash: `printf '\e[2J'`, C: `printf("\x1b[2J");`). If the standard error is empty, the tooltip will show information about the time when the command was last executed. *(since 0.12.4)*
|
||||||
|
|
||||||
* `execp_font = [FAMILY-LIST] [STYLE-OPTIONS] [SIZE]` : The font used to draw the text. *(since 0.12.4)*
|
* `execp_font = [FAMILY-LIST] [STYLE-OPTIONS] [SIZE]` : The font used to draw the text. *(since 0.12.4)*
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
MAJOR=0.14
|
SCRIPT_DIR=$(dirname "$0")
|
||||||
DIRTY=""
|
DIRTY=""
|
||||||
|
VERSION=""
|
||||||
|
|
||||||
if git status 1>/dev/null 2>/dev/null
|
if [ -d ${SCRIPT_DIR}/.git ] && git status 1>/dev/null 2>/dev/null
|
||||||
then
|
then
|
||||||
git update-index -q --ignore-submodules --refresh
|
git update-index -q --ignore-submodules --refresh
|
||||||
# Disallow unstaged changes in the working tree
|
# Disallow unstaged changes in the working tree
|
||||||
@@ -31,9 +32,23 @@ then
|
|||||||
DIRTY="-dirty"
|
DIRTY="-dirty"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
VERSION=$(git describe --exact-match 2>/dev/null || echo "$MAJOR-git$(git show -s --pretty=format:%ci | cut -d ' ' -f 1 | tr -d '-').$(git show -s --pretty=format:%h)")$DIRTY
|
if git describe 1>/dev/null 2>/dev/null
|
||||||
else
|
then
|
||||||
SCRIPT_DIR=$(dirname "$0")
|
VERSION=$(git describe 2>/dev/null)$DIRTY
|
||||||
|
elif git log -n 1 1>/dev/null 2>/dev/null
|
||||||
|
then
|
||||||
|
VERSION=$(head -n 1 "${SCRIPT_DIR}/ChangeLog" | cut -d ' ' -f 2)
|
||||||
|
if [ "$VERSION" = "master" ]
|
||||||
|
then
|
||||||
|
PREVIOUS=$(grep '^2' "${SCRIPT_DIR}/ChangeLog" | head -n 2 | tail -n 1 | cut -d ' ' -f 2)
|
||||||
|
HASH=$(git log -n 1 --pretty=format:%cI.%ct.%h | tr -d ':' | tr -d '-' | tr '.' '-' | sed 's/T[0-9\+]*//g' 2>/dev/null)
|
||||||
|
VERSION=$PREVIOUS-next-$HASH
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$VERSION" ]
|
||||||
|
then
|
||||||
VERSION=$(head -n 1 "${SCRIPT_DIR}/ChangeLog" | cut -d ' ' -f 2)
|
VERSION=$(head -n 1 "${SCRIPT_DIR}/ChangeLog" | cut -d ' ' -f 2)
|
||||||
if [ "$VERSION" = "master" ]
|
if [ "$VERSION" = "master" ]
|
||||||
then
|
then
|
||||||
@@ -41,7 +56,6 @@ else
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
VERSION=$(echo "$VERSION" | sed 's/^v//')
|
VERSION=$(echo "$VERSION" | sed 's/^v//')
|
||||||
|
|
||||||
echo '#define VERSION_STRING "'$VERSION'"' > version.h
|
echo '#define VERSION_STRING "'$VERSION'"' > version.h
|
||||||
|
|||||||
@@ -190,3 +190,7 @@ if __name__ == '__main__':
|
|||||||
run("cd tint2-%s ; mkdir build ; cd build ; cmake .. ; make" % readable_version)
|
run("cd tint2-%s ; mkdir build ; cd build ; cmake .. ; make" % readable_version)
|
||||||
assert_equal(run("./tint2-%s/build/tint2 -v" % readable_version).strip(), "tint2 version %s" % readable_version)
|
assert_equal(run("./tint2-%s/build/tint2 -v" % readable_version).strip(), "tint2 version %s" % readable_version)
|
||||||
os.system("git log -p -1 --word-diff")
|
os.system("git log -p -1 --word-diff")
|
||||||
|
print "Does this look correct? [y/n]"
|
||||||
|
choice = raw_input().lower()
|
||||||
|
if choice != "y":
|
||||||
|
run("git reset --hard HEAD~ ; git tag -d %s ; git tag -d %s" % (version, readable_version))
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
dh $@
|
dh $@
|
||||||
|
|
||||||
override_dh_auto_configure:
|
override_dh_auto_configure:
|
||||||
dh_auto_configure -- -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
dh_auto_configure -- -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_SYSCONFDIR=/etc
|
||||||
|
|
||||||
override_dh_auto_install:
|
override_dh_auto_install:
|
||||||
dh_auto_install --destdir=$(CURDIR)/debian/tmp
|
dh_auto_install --destdir=$(CURDIR)/debian/tmp
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
export PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
set -x
|
set -x
|
||||||
|
|
||||||
|
|||||||
@@ -52,11 +52,9 @@ void destroy_button(void *obj)
|
|||||||
Button *button = (Button *)obj;
|
Button *button = (Button *)obj;
|
||||||
if (button->frontend) {
|
if (button->frontend) {
|
||||||
// This is a frontend element
|
// This is a frontend element
|
||||||
if (button->frontend->icon) {
|
free_icon(button->frontend->icon);
|
||||||
imlib_context_set_image(button->frontend->icon);
|
free_icon(button->frontend->icon_hover);
|
||||||
imlib_free_image();
|
free_icon(button->frontend->icon_pressed);
|
||||||
button->frontend->icon = NULL;
|
|
||||||
}
|
|
||||||
button->backend->instances = g_list_remove_all(button->backend->instances, button);
|
button->backend->instances = g_list_remove_all(button->backend->instances, button);
|
||||||
free_and_null(button->frontend);
|
free_and_null(button->frontend);
|
||||||
remove_area(&button->area);
|
remove_area(&button->area);
|
||||||
@@ -79,7 +77,7 @@ void destroy_button(void *obj)
|
|||||||
|
|
||||||
if (button->backend->instances) {
|
if (button->backend->instances) {
|
||||||
fprintf(stderr, "tint2: Error: Attempt to destroy backend while there are still frontend instances!\n");
|
fprintf(stderr, "tint2: Error: Attempt to destroy backend while there are still frontend instances!\n");
|
||||||
exit(-1);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
free(button->backend);
|
free(button->backend);
|
||||||
free(button);
|
free(button);
|
||||||
|
|||||||
18
src/config.c
18
src/config.c
@@ -350,6 +350,12 @@ void add_entry(char *key, char *value)
|
|||||||
id = (id < gradients->len && id >= 0) ? id : -1;
|
id = (id < gradients->len && id >= 0) ? id : -1;
|
||||||
if (id >= 0)
|
if (id >= 0)
|
||||||
bg->gradients[MOUSE_DOWN] = &g_array_index(gradients, GradientClass, id);
|
bg->gradients[MOUSE_DOWN] = &g_array_index(gradients, GradientClass, id);
|
||||||
|
} else if (strcmp(key, "border_content_tint_weight") == 0) {
|
||||||
|
Background *bg = &g_array_index(backgrounds, Background, backgrounds->len - 1);
|
||||||
|
bg->border_content_tint_weight = MAX(0.0, MIN(1.0, atoi(value) / 100.));
|
||||||
|
} else if (strcmp(key, "background_content_tint_weight") == 0) {
|
||||||
|
Background *bg = &g_array_index(backgrounds, Background, backgrounds->len - 1);
|
||||||
|
bg->fill_content_tint_weight = MAX(0.0, MIN(1.0, atoi(value) / 100.));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Gradients */
|
/* Gradients */
|
||||||
@@ -1086,11 +1092,18 @@ void add_entry(char *key, char *value)
|
|||||||
panel_config.g_task.config_background_mask |= (1 << status);
|
panel_config.g_task.config_background_mask |= (1 << status);
|
||||||
if (status == TASK_NORMAL)
|
if (status == TASK_NORMAL)
|
||||||
panel_config.g_task.area.bg = panel_config.g_task.background[TASK_NORMAL];
|
panel_config.g_task.area.bg = panel_config.g_task.background[TASK_NORMAL];
|
||||||
|
if (panel_config.g_task.background[status]->border_content_tint_weight > 0 ||
|
||||||
|
panel_config.g_task.background[status]->fill_content_tint_weight > 0)
|
||||||
|
panel_config.g_task.has_content_tint = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// "tooltip" is deprecated but here for backwards compatibility
|
// "tooltip" is deprecated but here for backwards compatibility
|
||||||
else if (strcmp(key, "task_tooltip") == 0 || strcmp(key, "tooltip") == 0)
|
else if (strcmp(key, "task_tooltip") == 0 || strcmp(key, "tooltip") == 0)
|
||||||
panel_config.g_task.tooltip_enabled = atoi(value);
|
panel_config.g_task.tooltip_enabled = atoi(value);
|
||||||
|
else if (strcmp(key, "task_thumbnail") == 0)
|
||||||
|
panel_config.g_task.thumbnail_enabled = atoi(value);
|
||||||
|
else if (strcmp(key, "task_thumbnail_size") == 0)
|
||||||
|
panel_config.g_task.thumbnail_width = MAX(8, atoi(value));
|
||||||
|
|
||||||
/* Systray */
|
/* Systray */
|
||||||
else if (strcmp(key, "systray_padding") == 0) {
|
else if (strcmp(key, "systray_padding") == 0) {
|
||||||
@@ -1133,8 +1146,11 @@ void add_entry(char *key, char *value)
|
|||||||
} else if (strcmp(key, "systray_monitor") == 0) {
|
} else if (strcmp(key, "systray_monitor") == 0) {
|
||||||
systray_monitor = MAX(0, config_get_monitor(value));
|
systray_monitor = MAX(0, config_get_monitor(value));
|
||||||
} else if (strcmp(key, "systray_name_filter") == 0) {
|
} else if (strcmp(key, "systray_name_filter") == 0) {
|
||||||
if (systray_hide_name_filter)
|
if (systray_hide_name_filter) {
|
||||||
|
fprintf(stderr, "tint2: Error: duplicate option 'systray_name_filter'. Please use it only once. See "
|
||||||
|
"https://gitlab.com/o9000/tint2/issues/652\n");
|
||||||
free(systray_hide_name_filter);
|
free(systray_hide_name_filter);
|
||||||
|
}
|
||||||
systray_hide_name_filter = strdup(value);
|
systray_hide_name_filter = strdup(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,11 +70,7 @@ void destroy_execp(void *obj)
|
|||||||
stop_timeout(execp->backend->timer);
|
stop_timeout(execp->backend->timer);
|
||||||
execp->backend->timer = NULL;
|
execp->backend->timer = NULL;
|
||||||
|
|
||||||
if (execp->backend->icon) {
|
free_icon(execp->backend->icon);
|
||||||
imlib_context_set_image(execp->backend->icon);
|
|
||||||
imlib_free_image();
|
|
||||||
execp->backend->icon = NULL;
|
|
||||||
}
|
|
||||||
free_and_null(execp->backend->buf_stdout);
|
free_and_null(execp->backend->buf_stdout);
|
||||||
free_and_null(execp->backend->buf_stderr);
|
free_and_null(execp->backend->buf_stderr);
|
||||||
free_and_null(execp->backend->text);
|
free_and_null(execp->backend->text);
|
||||||
@@ -109,7 +105,7 @@ void destroy_execp(void *obj)
|
|||||||
|
|
||||||
if (execp->backend->instances) {
|
if (execp->backend->instances) {
|
||||||
fprintf(stderr, "tint2: Error: Attempt to destroy backend while there are still frontend instances!\n");
|
fprintf(stderr, "tint2: Error: Attempt to destroy backend while there are still frontend instances!\n");
|
||||||
exit(-1);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
free(execp->backend);
|
free(execp->backend);
|
||||||
free(execp);
|
free(execp);
|
||||||
|
|||||||
12
src/init.c
12
src/init.c
@@ -6,6 +6,11 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/Xutil.h>
|
||||||
|
#include <X11/Xatom.h>
|
||||||
|
#include <X11/extensions/XShm.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "drag_and_drop.h"
|
#include "drag_and_drop.h"
|
||||||
#include "fps_distribution.h"
|
#include "fps_distribution.h"
|
||||||
@@ -75,7 +80,7 @@ void handle_cli_arguments(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
if (error) {
|
if (error) {
|
||||||
print_usage();
|
print_usage();
|
||||||
exit(1);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,6 +93,7 @@ void handle_env_vars()
|
|||||||
debug_fps = getenv("DEBUG_FPS") != NULL;
|
debug_fps = getenv("DEBUG_FPS") != NULL;
|
||||||
debug_frames = getenv("DEBUG_FRAMES") != NULL;
|
debug_frames = getenv("DEBUG_FRAMES") != NULL;
|
||||||
debug_dnd = getenv("DEBUG_DND") != NULL;
|
debug_dnd = getenv("DEBUG_DND") != NULL;
|
||||||
|
debug_thumbnails = getenv("DEBUG_THUMBNAILS") != 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");
|
||||||
@@ -184,7 +190,7 @@ void init_X11_pre_config()
|
|||||||
server.display = XOpenDisplay(NULL);
|
server.display = XOpenDisplay(NULL);
|
||||||
if (!server.display) {
|
if (!server.display) {
|
||||||
fprintf(stderr, "tint2: could not open display!\n");
|
fprintf(stderr, "tint2: could not open display!\n");
|
||||||
exit(1);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
server.x11_fd = ConnectionNumber(server.display);
|
server.x11_fd = ConnectionNumber(server.display);
|
||||||
XSetErrorHandler((XErrorHandler)server_catch_error);
|
XSetErrorHandler((XErrorHandler)server_catch_error);
|
||||||
@@ -193,6 +199,7 @@ void init_X11_pre_config()
|
|||||||
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);
|
||||||
server.desktop = get_current_desktop();
|
server.desktop = get_current_desktop();
|
||||||
|
server.has_shm = XShmQueryExtension(server.display);
|
||||||
|
|
||||||
// Needed since the config file uses '.' as decimal separator
|
// Needed since the config file uses '.' as decimal separator
|
||||||
setlocale(LC_ALL, "");
|
setlocale(LC_ALL, "");
|
||||||
@@ -251,6 +258,7 @@ void cleanup()
|
|||||||
#ifdef ENABLE_BATTERY
|
#ifdef ENABLE_BATTERY
|
||||||
cleanup_battery();
|
cleanup_battery();
|
||||||
#endif
|
#endif
|
||||||
|
cleanup_separator();
|
||||||
cleanup_panel();
|
cleanup_panel();
|
||||||
cleanup_config();
|
cleanup_config();
|
||||||
|
|
||||||
|
|||||||
@@ -262,7 +262,7 @@ void handle_event_property_notify(XEvent *e)
|
|||||||
if (at == server.atom._NET_WM_VISIBLE_NAME || at == server.atom._NET_WM_NAME || at == server.atom.WM_NAME) {
|
if (at == server.atom._NET_WM_VISIBLE_NAME || at == server.atom._NET_WM_NAME || at == server.atom.WM_NAME) {
|
||||||
if (task_update_title(task)) {
|
if (task_update_title(task)) {
|
||||||
if (g_tooltip.mapped && (g_tooltip.area == (Area *)task)) {
|
if (g_tooltip.mapped && (g_tooltip.area == (Area *)task)) {
|
||||||
tooltip_copy_text((Area *)task);
|
tooltip_update_contents_for((Area *)task);
|
||||||
tooltip_update();
|
tooltip_update();
|
||||||
}
|
}
|
||||||
if (taskbar_sort_method == TASKBAR_SORT_TITLE)
|
if (taskbar_sort_method == TASKBAR_SORT_TITLE)
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ char *panel_window_name = NULL;
|
|||||||
gboolean debug_geometry;
|
gboolean debug_geometry;
|
||||||
gboolean debug_gradients;
|
gboolean debug_gradients;
|
||||||
gboolean startup_notifications;
|
gboolean startup_notifications;
|
||||||
|
gboolean debug_thumbnails;
|
||||||
|
|
||||||
gboolean panel_autohide;
|
gboolean panel_autohide;
|
||||||
int panel_autohide_show_timeout;
|
int panel_autohide_show_timeout;
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ extern gboolean debug_geometry;
|
|||||||
extern gboolean debug_fps;
|
extern gboolean debug_fps;
|
||||||
extern double tracing_fps_threshold;
|
extern double tracing_fps_threshold;
|
||||||
extern gboolean debug_frames;
|
extern gboolean debug_frames;
|
||||||
|
extern gboolean debug_thumbnails;
|
||||||
|
|
||||||
typedef struct Panel {
|
typedef struct Panel {
|
||||||
Area area;
|
Area area;
|
||||||
|
|||||||
@@ -147,6 +147,7 @@ typedef struct Server {
|
|||||||
Global_atom atom;
|
Global_atom atom;
|
||||||
int xdamage_event_type;
|
int xdamage_event_type;
|
||||||
int xdamage_event_error_type;
|
int xdamage_event_error_type;
|
||||||
|
gboolean has_shm;
|
||||||
#ifdef HAVE_SN
|
#ifdef HAVE_SN
|
||||||
SnDisplay *sn_display;
|
SnDisplay *sn_display;
|
||||||
GTree *pids;
|
GTree *pids;
|
||||||
|
|||||||
@@ -24,11 +24,23 @@ void signal_handler(int sig)
|
|||||||
signal_pending = sig;
|
signal_pending = sig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void reset_signals()
|
||||||
|
{
|
||||||
|
for (int sig = 1; sig < 32; sig++) {
|
||||||
|
signal(sig, SIG_DFL);
|
||||||
|
}
|
||||||
|
sigset_t signal_set;
|
||||||
|
sigemptyset(&signal_set);
|
||||||
|
sigprocmask(SIG_SETMASK, &signal_set, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
void init_signals()
|
void init_signals()
|
||||||
{
|
{
|
||||||
// Set signal handlers
|
// Set signal handlers
|
||||||
signal_pending = 0;
|
signal_pending = 0;
|
||||||
|
|
||||||
|
reset_signals();
|
||||||
|
|
||||||
struct sigaction sa_chld = {.sa_handler = SIG_IGN};
|
struct sigaction sa_chld = {.sa_handler = SIG_IGN};
|
||||||
sigaction(SIGCHLD, &sa_chld, 0);
|
sigaction(SIGCHLD, &sa_chld, 0);
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ void init_signals();
|
|||||||
void init_signals_postconfig();
|
void init_signals_postconfig();
|
||||||
void emit_self_restart(const char *reason);
|
void emit_self_restart(const char *reason);
|
||||||
int get_signal_pending();
|
int get_signal_pending();
|
||||||
|
void reset_signals();
|
||||||
|
|
||||||
void handle_sigchld_events();
|
void handle_sigchld_events();
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ GSList *urgent_list;
|
|||||||
|
|
||||||
void task_dump_geometry(void *obj, int indent);
|
void task_dump_geometry(void *obj, int indent);
|
||||||
int task_compute_desired_size(void *obj);
|
int task_compute_desired_size(void *obj);
|
||||||
|
void task_refresh_thumbnail(Task *task);
|
||||||
|
void task_get_content_color(void *obj, Color *color);
|
||||||
|
|
||||||
char *task_get_tooltip(void *obj)
|
char *task_get_tooltip(void *obj)
|
||||||
{
|
{
|
||||||
@@ -47,6 +49,17 @@ char *task_get_tooltip(void *obj)
|
|||||||
return strdup(t->title);
|
return strdup(t->title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cairo_surface_t *task_get_thumbnail(void *obj)
|
||||||
|
{
|
||||||
|
if (!panel_config.g_task.thumbnail_enabled)
|
||||||
|
return NULL;
|
||||||
|
Task *t = (Task *)obj;
|
||||||
|
if (!t->thumbnail)
|
||||||
|
task_refresh_thumbnail(t);
|
||||||
|
taskbar_start_thumbnail_timer(THUMB_MODE_TOOLTIP_WINDOW);
|
||||||
|
return t->thumbnail;
|
||||||
|
}
|
||||||
|
|
||||||
Task *add_task(Window win)
|
Task *add_task(Window win)
|
||||||
{
|
{
|
||||||
if (!win)
|
if (!win)
|
||||||
@@ -73,6 +86,7 @@ Task *add_task(Window win)
|
|||||||
task_template.area.has_mouse_press_effect = panel_config.mouse_effects;
|
task_template.area.has_mouse_press_effect = panel_config.mouse_effects;
|
||||||
task_template.area._dump_geometry = task_dump_geometry;
|
task_template.area._dump_geometry = task_dump_geometry;
|
||||||
task_template.area._is_under_mouse = full_width_area_is_under_mouse;
|
task_template.area._is_under_mouse = full_width_area_is_under_mouse;
|
||||||
|
task_template.area._get_content_color = task_get_content_color;
|
||||||
task_template.win = win;
|
task_template.win = win;
|
||||||
task_template.desktop = get_window_desktop(win);
|
task_template.desktop = get_window_desktop(win);
|
||||||
task_template.area.panel = &panels[monitor];
|
task_template.area.panel = &panels[monitor];
|
||||||
@@ -93,10 +107,6 @@ Task *add_task(Window win)
|
|||||||
(int)win,
|
(int)win,
|
||||||
task_template.title ? task_template.title : "null");
|
task_template.title ? task_template.title : "null");
|
||||||
|
|
||||||
// fprintf(stderr, "tint2: %s %d: win = %ld, task = %s\n", __func__, __LINE__, win, task_template.title ?
|
|
||||||
// task_template.title : "??");
|
|
||||||
// fprintf(stderr, "tint2: new task %s win %u: desktop %d, monitor %d\n", new_task.title, win, new_task.desktop, monitor);
|
|
||||||
|
|
||||||
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)
|
||||||
@@ -110,6 +120,7 @@ Task *add_task(Window win)
|
|||||||
task_instance->area._dump_geometry = task_dump_geometry;
|
task_instance->area._dump_geometry = task_dump_geometry;
|
||||||
task_instance->area._is_under_mouse = full_width_area_is_under_mouse;
|
task_instance->area._is_under_mouse = full_width_area_is_under_mouse;
|
||||||
task_instance->area._compute_desired_size = task_compute_desired_size;
|
task_instance->area._compute_desired_size = task_compute_desired_size;
|
||||||
|
task_instance->area._get_content_color = task_get_content_color;
|
||||||
task_instance->win = task_template.win;
|
task_instance->win = task_template.win;
|
||||||
task_instance->desktop = task_template.desktop;
|
task_instance->desktop = task_template.desktop;
|
||||||
task_instance->win_x = task_template.win_x;
|
task_instance->win_x = task_template.win_x;
|
||||||
@@ -118,12 +129,16 @@ Task *add_task(Window win)
|
|||||||
task_instance->win_h = task_template.win_h;
|
task_instance->win_h = task_template.win_h;
|
||||||
task_instance->current_state = TASK_UNDEFINED; // to update the current state later in set_task_state...
|
task_instance->current_state = TASK_UNDEFINED; // to update the current state later in set_task_state...
|
||||||
if (task_instance->desktop == ALL_DESKTOPS && server.desktop != j) {
|
if (task_instance->desktop == ALL_DESKTOPS && server.desktop != j) {
|
||||||
// fprintf(stderr, "tint2: %s %d: win = %ld hiding task: another desktop\n", __func__, __LINE__, 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;
|
||||||
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->icon_color = task_template.icon_color;
|
||||||
|
task_instance->icon_color_hover = task_template.icon_color_hover;
|
||||||
|
task_instance->icon_color_press = task_template.icon_color_press;
|
||||||
for (int k = 0; k < TASK_STATE_COUNT; ++k) {
|
for (int k = 0; k < TASK_STATE_COUNT; ++k) {
|
||||||
task_instance->icon[k] = task_template.icon[k];
|
task_instance->icon[k] = task_template.icon[k];
|
||||||
task_instance->icon_hover[k] = task_template.icon_hover[k];
|
task_instance->icon_hover[k] = task_template.icon_hover[k];
|
||||||
@@ -186,9 +201,6 @@ void remove_task(Task *task)
|
|||||||
if (!task)
|
if (!task)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// fprintf(stderr, "tint2: %s %d: win = %ld, task = %s\n", __func__, __LINE__, task->win, task->title ? task->title :
|
|
||||||
// "??");
|
|
||||||
|
|
||||||
if (taskbar_mode == MULTI_DESKTOP) {
|
if (taskbar_mode == MULTI_DESKTOP) {
|
||||||
Panel *panel = task->area.panel;
|
Panel *panel = task->area.panel;
|
||||||
panel->area.resize_needed = 1;
|
panel->area.resize_needed = 1;
|
||||||
@@ -198,9 +210,10 @@ void remove_task(Task *task)
|
|||||||
|
|
||||||
// free title and icon just for the first task
|
// free title and icon 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
|
||||||
// fprintf(stderr, "tint2: remove_task %s %d\n", task->title, task->desktop);
|
|
||||||
if (task->title)
|
if (task->title)
|
||||||
free(task->title);
|
free(task->title);
|
||||||
|
if (task->thumbnail)
|
||||||
|
cairo_surface_destroy(task->thumbnail);
|
||||||
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);
|
||||||
@@ -212,6 +225,8 @@ void remove_task(Task *task)
|
|||||||
task_drag = 0;
|
task_drag = 0;
|
||||||
if (g_slist_find(urgent_list, task2))
|
if (g_slist_find(urgent_list, task2))
|
||||||
del_urgent(task2);
|
del_urgent(task2);
|
||||||
|
if (g_tooltip.area == &task2->area)
|
||||||
|
tooltip_hide(NULL);
|
||||||
remove_area((Area *)task2);
|
remove_area((Area *)task2);
|
||||||
free(task2);
|
free(task2);
|
||||||
}
|
}
|
||||||
@@ -266,36 +281,23 @@ gboolean task_update_title(Task *task)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void task_update_icon(Task *task)
|
Imlib_Image task_get_icon(Window win, int icon_size)
|
||||||
{
|
{
|
||||||
Panel *panel = task->area.panel;
|
|
||||||
if (!panel->g_task.has_icon)
|
|
||||||
return;
|
|
||||||
|
|
||||||
task_remove_icon(task);
|
|
||||||
|
|
||||||
Imlib_Image img = NULL;
|
Imlib_Image img = NULL;
|
||||||
|
|
||||||
if (!img) {
|
if (!img) {
|
||||||
int len;
|
int len;
|
||||||
gulong *data = server_get_property(task->win, server.atom._NET_WM_ICON, XA_CARDINAL, &len);
|
gulong *data = server_get_property(win, server.atom._NET_WM_ICON, XA_CARDINAL, &len);
|
||||||
if (data) {
|
if (data) {
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
// get ARGB icon
|
// get ARGB icon
|
||||||
int w, h;
|
int w, h;
|
||||||
gulong *tmp_data = get_best_icon(data, get_icon_count(data, len), len, &w, &h, panel->g_task.icon_size1);
|
gulong *tmp_data = get_best_icon(data, get_icon_count(data, len), len, &w, &h, icon_size);
|
||||||
if (tmp_data) {
|
if (tmp_data) {
|
||||||
DATA32 icon_data[w * h];
|
DATA32 icon_data[w * h];
|
||||||
for (int j = 0; j < w * h; ++j)
|
for (int j = 0; j < w * h; ++j)
|
||||||
icon_data[j] = tmp_data[j];
|
icon_data[j] = tmp_data[j];
|
||||||
img = imlib_create_image_using_copied_data(w, h, icon_data);
|
img = imlib_create_image_using_copied_data(w, h, icon_data);
|
||||||
if (0 && img)
|
|
||||||
fprintf(stderr,
|
|
||||||
"%s: Got %dx%d icon via _NET_WM_ICON for %s\n",
|
|
||||||
__func__,
|
|
||||||
w,
|
|
||||||
h,
|
|
||||||
task->title ? task->title : "task");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
XFree(data);
|
XFree(data);
|
||||||
@@ -303,7 +305,7 @@ void task_update_icon(Task *task)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!img) {
|
if (!img) {
|
||||||
XWMHints *hints = XGetWMHints(server.display, task->win);
|
XWMHints *hints = XGetWMHints(server.display, win);
|
||||||
if (hints) {
|
if (hints) {
|
||||||
if (hints->flags & IconPixmapHint && hints->icon_pixmap != 0) {
|
if (hints->flags & IconPixmapHint && hints->icon_pixmap != 0) {
|
||||||
// get width, height and depth for the pixmap
|
// get width, height and depth for the pixmap
|
||||||
@@ -315,13 +317,6 @@ void task_update_icon(Task *task)
|
|||||||
XGetGeometry(server.display, hints->icon_pixmap, &root, &icon_x, &icon_y, &w, &h, &border_width, &bpp);
|
XGetGeometry(server.display, hints->icon_pixmap, &root, &icon_x, &icon_y, &w, &h, &border_width, &bpp);
|
||||||
imlib_context_set_drawable(hints->icon_pixmap);
|
imlib_context_set_drawable(hints->icon_pixmap);
|
||||||
img = imlib_create_image_from_drawable(hints->icon_mask, 0, 0, w, h, 0);
|
img = imlib_create_image_from_drawable(hints->icon_mask, 0, 0, w, h, 0);
|
||||||
if (0 && img)
|
|
||||||
fprintf(stderr,
|
|
||||||
"%s: Got %dx%d pixmap icon via WM_HINTS for %s\n",
|
|
||||||
__func__,
|
|
||||||
w,
|
|
||||||
h,
|
|
||||||
task->title ? task->title : "task");
|
|
||||||
}
|
}
|
||||||
XFree(hints);
|
XFree(hints);
|
||||||
}
|
}
|
||||||
@@ -332,6 +327,44 @@ void task_update_icon(Task *task)
|
|||||||
img = imlib_clone_image();
|
img = imlib_clone_image();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
|
||||||
|
void task_set_icon_color(Task *task, Imlib_Image icon)
|
||||||
|
{
|
||||||
|
get_image_mean_color(icon, &task->icon_color);
|
||||||
|
if (panel_config.mouse_effects) {
|
||||||
|
task->icon_color_hover = task->icon_color;
|
||||||
|
adjust_color(&task->icon_color_hover,
|
||||||
|
panel_config.mouse_over_alpha,
|
||||||
|
panel_config.mouse_over_saturation,
|
||||||
|
panel_config.mouse_over_brightness);
|
||||||
|
task->icon_color_press = task->icon_color;
|
||||||
|
adjust_color(&task->icon_color_press,
|
||||||
|
panel_config.mouse_pressed_alpha,
|
||||||
|
panel_config.mouse_pressed_saturation,
|
||||||
|
panel_config.mouse_pressed_brightness);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void task_update_icon(Task *task)
|
||||||
|
{
|
||||||
|
Panel *panel = task->area.panel;
|
||||||
|
if (!panel->g_task.has_icon) {
|
||||||
|
if (panel_config.g_task.has_content_tint) {
|
||||||
|
Imlib_Image img = task_get_icon(task->win, panel->g_task.icon_size1);
|
||||||
|
task_set_icon_color(task, img);
|
||||||
|
imlib_context_set_image(img);
|
||||||
|
imlib_free_image();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
task_remove_icon(task);
|
||||||
|
|
||||||
|
Imlib_Image img = task_get_icon(task->win, panel->g_task.icon_size1);
|
||||||
|
task_set_icon_color(task, img);
|
||||||
|
|
||||||
// transform icons
|
// transform icons
|
||||||
imlib_context_set_image(img);
|
imlib_context_set_image(img);
|
||||||
imlib_image_set_has_alpha(1);
|
imlib_image_set_has_alpha(1);
|
||||||
@@ -345,20 +378,10 @@ void task_update_icon(Task *task)
|
|||||||
task->icon_width = imlib_image_get_width();
|
task->icon_width = imlib_image_get_width();
|
||||||
task->icon_height = imlib_image_get_height();
|
task->icon_height = imlib_image_get_height();
|
||||||
for (int k = 0; k < TASK_STATE_COUNT; ++k) {
|
for (int k = 0; k < TASK_STATE_COUNT; ++k) {
|
||||||
imlib_context_set_image(orig_image);
|
task->icon[k] = adjust_icon(orig_image,
|
||||||
task->icon[k] = imlib_clone_image();
|
panel->g_task.alpha[k],
|
||||||
imlib_context_set_image(task->icon[k]);
|
panel->g_task.saturation[k],
|
||||||
DATA32 *data32;
|
panel->g_task.brightness[k] != 0);
|
||||||
if (panel->g_task.alpha[k] != 100 || panel->g_task.saturation[k] != 0 || panel->g_task.brightness[k] != 0) {
|
|
||||||
data32 = imlib_image_get_data();
|
|
||||||
adjust_asb(data32,
|
|
||||||
task->icon_width,
|
|
||||||
task->icon_height,
|
|
||||||
panel->g_task.alpha[k] / 100.0,
|
|
||||||
panel->g_task.saturation[k] / 100.0,
|
|
||||||
panel->g_task.brightness[k] / 100.0);
|
|
||||||
imlib_image_put_back_data(data32);
|
|
||||||
}
|
|
||||||
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,
|
||||||
@@ -376,9 +399,12 @@ void task_update_icon(Task *task)
|
|||||||
GPtrArray *task_buttons = get_task_buttons(task->win);
|
GPtrArray *task_buttons = get_task_buttons(task->win);
|
||||||
if (task_buttons) {
|
if (task_buttons) {
|
||||||
for (int i = 0; i < task_buttons->len; ++i) {
|
for (int i = 0; i < task_buttons->len; ++i) {
|
||||||
Task *task2 = g_ptr_array_index(task_buttons, i);
|
Task *task2 = (Task *)g_ptr_array_index(task_buttons, i);
|
||||||
task2->icon_width = task->icon_width;
|
task2->icon_width = task->icon_width;
|
||||||
task2->icon_height = task->icon_height;
|
task2->icon_height = task->icon_height;
|
||||||
|
task2->icon_color = task->icon_color;
|
||||||
|
task2->icon_color_hover = task->icon_color_hover;
|
||||||
|
task2->icon_color_press = task->icon_color_press;
|
||||||
for (int k = 0; k < TASK_STATE_COUNT; ++k) {
|
for (int k = 0; k < TASK_STATE_COUNT; ++k) {
|
||||||
task2->icon[k] = task->icon[k];
|
task2->icon[k] = task->icon[k];
|
||||||
task2->icon_hover[k] = task->icon_hover[k];
|
task2->icon_hover[k] = task->icon_hover[k];
|
||||||
@@ -484,6 +510,24 @@ void task_dump_geometry(void *obj, int indent)
|
|||||||
panel->g_task.icon_size1);
|
panel->g_task.icon_size1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void task_get_content_color(void *obj, Color *color)
|
||||||
|
{
|
||||||
|
Task *task = (Task *)obj;
|
||||||
|
Color *content_color = NULL;
|
||||||
|
if (panel_config.mouse_effects) {
|
||||||
|
if (task->area.mouse_state == MOUSE_OVER)
|
||||||
|
content_color = &task->icon_color_hover;
|
||||||
|
else if (task->area.mouse_state == MOUSE_DOWN)
|
||||||
|
content_color = &task->icon_color_press;
|
||||||
|
else
|
||||||
|
content_color = &task->icon_color;
|
||||||
|
} else {
|
||||||
|
content_color = &task->icon_color;
|
||||||
|
}
|
||||||
|
if (content_color)
|
||||||
|
*color = *content_color;
|
||||||
|
}
|
||||||
|
|
||||||
int task_compute_desired_size(void *obj)
|
int task_compute_desired_size(void *obj)
|
||||||
{
|
{
|
||||||
Task *task = (Task *)obj;
|
Task *task = (Task *)obj;
|
||||||
@@ -591,7 +635,6 @@ void reset_active_task()
|
|||||||
}
|
}
|
||||||
|
|
||||||
Window w1 = get_active_window();
|
Window w1 = get_active_window();
|
||||||
// fprintf(stderr, "tint2: Change active task %ld\n", w1);
|
|
||||||
|
|
||||||
if (w1) {
|
if (w1) {
|
||||||
if (!get_task_buttons(w1)) {
|
if (!get_task_buttons(w1)) {
|
||||||
@@ -603,11 +646,49 @@ void reset_active_task()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void task_refresh_thumbnail(Task *task)
|
||||||
|
{
|
||||||
|
if (!panel_config.g_task.thumbnail_enabled)
|
||||||
|
return;
|
||||||
|
if (task->current_state == TASK_ICONIFIED)
|
||||||
|
return;
|
||||||
|
double now = get_time();
|
||||||
|
if (now - task->thumbnail_last_update < 0.1)
|
||||||
|
return;
|
||||||
|
if (debug_thumbnails)
|
||||||
|
fprintf(stderr, "tint2: thumbnail for window: %s" RESET "\n", task->title ? task->title : "");
|
||||||
|
cairo_surface_t *thumbnail = get_window_thumbnail(task->win, panel_config.g_task.thumbnail_width);
|
||||||
|
if (!thumbnail)
|
||||||
|
return;
|
||||||
|
if (task->thumbnail)
|
||||||
|
cairo_surface_destroy(task->thumbnail);
|
||||||
|
task->thumbnail = thumbnail;
|
||||||
|
task->thumbnail_last_update = get_time();
|
||||||
|
if (debug_thumbnails)
|
||||||
|
fprintf(stderr,
|
||||||
|
YELLOW "tint2: %s took %f ms (window: %s)" RESET "\n",
|
||||||
|
__func__,
|
||||||
|
1000 * (task->thumbnail_last_update - now),
|
||||||
|
task->title ? task->title : "");
|
||||||
|
if (g_tooltip.mapped && (g_tooltip.area == &task->area)) {
|
||||||
|
tooltip_update_contents_for(&task->area);
|
||||||
|
tooltip_update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void set_task_state(Task *task, TaskState state)
|
void set_task_state(Task *task, TaskState state)
|
||||||
{
|
{
|
||||||
if (!task || state == TASK_UNDEFINED || state >= TASK_STATE_COUNT)
|
if (!task || state == TASK_UNDEFINED || state >= TASK_STATE_COUNT)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!task->thumbnail)
|
||||||
|
task_refresh_thumbnail(task);
|
||||||
|
if (state == TASK_ACTIVE) {
|
||||||
|
// For active windows, we get the thumbnail twice with a small delay in between.
|
||||||
|
// This is because they sometimes redraw their windows slowly.
|
||||||
|
taskbar_start_thumbnail_timer(THUMB_MODE_ACTIVE_WINDOW);
|
||||||
|
}
|
||||||
|
|
||||||
if (state == TASK_ACTIVE && task->current_state != state) {
|
if (state == TASK_ACTIVE && task->current_state != state) {
|
||||||
clock_gettime(CLOCK_MONOTONIC, &task->last_activation_time);
|
clock_gettime(CLOCK_MONOTONIC, &task->last_activation_time);
|
||||||
if (taskbar_sort_method == TASKBAR_SORT_LRU || taskbar_sort_method == TASKBAR_SORT_MRU) {
|
if (taskbar_sort_method == TASKBAR_SORT_LRU || taskbar_sort_method == TASKBAR_SORT_MRU) {
|
||||||
@@ -783,7 +864,6 @@ void task_handle_mouse_event(Task *task, MouseAction action)
|
|||||||
|
|
||||||
void task_update_desktop(Task *task)
|
void task_update_desktop(Task *task)
|
||||||
{
|
{
|
||||||
// fprintf(stderr, "tint2: %s %d:\n", __func__, __LINE__);
|
|
||||||
Window win = task->win;
|
Window win = task->win;
|
||||||
remove_task(task);
|
remove_task(task);
|
||||||
task = add_task(win);
|
task = add_task(win);
|
||||||
|
|||||||
@@ -42,10 +42,13 @@ typedef struct GlobalTask {
|
|||||||
// starting position for text ~ task_padding + task_border + icon_size
|
// starting position for text ~ task_padding + task_border + icon_size
|
||||||
double text_posx, text_height;
|
double text_posx, text_height;
|
||||||
gboolean has_font;
|
gboolean has_font;
|
||||||
|
gboolean has_content_tint;
|
||||||
PangoFontDescription *font_desc;
|
PangoFontDescription *font_desc;
|
||||||
Color font[TASK_STATE_COUNT];
|
Color font[TASK_STATE_COUNT];
|
||||||
int config_font_mask;
|
int config_font_mask;
|
||||||
gboolean tooltip_enabled;
|
gboolean tooltip_enabled;
|
||||||
|
gboolean thumbnail_enabled;
|
||||||
|
int thumbnail_width;
|
||||||
} GlobalTask;
|
} GlobalTask;
|
||||||
|
|
||||||
// Stores information about a task.
|
// Stores information about a task.
|
||||||
@@ -61,6 +64,9 @@ typedef struct Task {
|
|||||||
Imlib_Image icon_press[TASK_STATE_COUNT];
|
Imlib_Image icon_press[TASK_STATE_COUNT];
|
||||||
unsigned int icon_width;
|
unsigned int icon_width;
|
||||||
unsigned int icon_height;
|
unsigned int icon_height;
|
||||||
|
Color icon_color;
|
||||||
|
Color icon_color_hover;
|
||||||
|
Color icon_color_press;
|
||||||
char *title;
|
char *title;
|
||||||
int urgent_tick;
|
int urgent_tick;
|
||||||
// These may not be up-to-date
|
// These may not be up-to-date
|
||||||
@@ -74,6 +80,8 @@ typedef struct Task {
|
|||||||
double _text_posy;
|
double _text_posy;
|
||||||
int _icon_x;
|
int _icon_x;
|
||||||
int _icon_y;
|
int _icon_y;
|
||||||
|
cairo_surface_t *thumbnail;
|
||||||
|
double thumbnail_last_update;
|
||||||
} Task;
|
} Task;
|
||||||
|
|
||||||
extern timeout *urgent_timeout;
|
extern timeout *urgent_timeout;
|
||||||
@@ -91,6 +99,7 @@ gboolean task_update_title(Task *task);
|
|||||||
void reset_active_task();
|
void reset_active_task();
|
||||||
void set_task_state(Task *task, TaskState state);
|
void set_task_state(Task *task, TaskState state);
|
||||||
void task_handle_mouse_event(Task *task, MouseAction action);
|
void task_handle_mouse_event(Task *task, MouseAction action);
|
||||||
|
void task_refresh_thumbnail(Task *task);
|
||||||
|
|
||||||
// Given a pointer to the task that is currently under the mouse (current_task),
|
// Given a pointer to the task that is currently under the mouse (current_task),
|
||||||
// returns a pointer to the Task for the active window on the same taskbar.
|
// returns a pointer to the Task for the active window on the same taskbar.
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
#include "window.h"
|
#include "window.h"
|
||||||
#include "panel.h"
|
#include "panel.h"
|
||||||
#include "strnatcmp.h"
|
#include "strnatcmp.h"
|
||||||
|
#include "tooltip.h"
|
||||||
|
|
||||||
GHashTable *win_to_task;
|
GHashTable *win_to_task;
|
||||||
|
|
||||||
@@ -46,8 +47,12 @@ gboolean hide_taskbar_if_empty;
|
|||||||
gboolean always_show_all_desktop_tasks;
|
gboolean always_show_all_desktop_tasks;
|
||||||
TaskbarSortMethod taskbar_sort_method;
|
TaskbarSortMethod taskbar_sort_method;
|
||||||
Alignment taskbar_alignment;
|
Alignment taskbar_alignment;
|
||||||
|
static timeout *thumbnail_update_timer_all;
|
||||||
|
static timeout *thumbnail_update_timer_active;
|
||||||
|
static timeout *thumbnail_update_timer_tooltip;
|
||||||
|
|
||||||
static GList *taskbar_task_orderings = NULL;
|
static GList *taskbar_task_orderings = NULL;
|
||||||
|
static GList *taskbar_thumbnail_jobs_done = NULL;
|
||||||
|
|
||||||
void taskbar_init_fonts();
|
void taskbar_init_fonts();
|
||||||
int taskbar_compute_desired_size(void *obj);
|
int taskbar_compute_desired_size(void *obj);
|
||||||
@@ -55,6 +60,8 @@ int taskbar_compute_desired_size(void *obj);
|
|||||||
// Removes the task with &win = key. The other args are ignored.
|
// Removes the task with &win = key. The other args are ignored.
|
||||||
void taskbar_remove_task(Window *win);
|
void taskbar_remove_task(Window *win);
|
||||||
|
|
||||||
|
void taskbar_update_thumbnails(void *arg);
|
||||||
|
|
||||||
guint win_hash(gconstpointer key)
|
guint win_hash(gconstpointer key)
|
||||||
{
|
{
|
||||||
return *((const Window *)key);
|
return *((const Window *)key);
|
||||||
@@ -82,6 +89,10 @@ void default_taskbar()
|
|||||||
hide_task_diff_monitor = FALSE;
|
hide_task_diff_monitor = FALSE;
|
||||||
hide_taskbar_if_empty = FALSE;
|
hide_taskbar_if_empty = FALSE;
|
||||||
always_show_all_desktop_tasks = FALSE;
|
always_show_all_desktop_tasks = FALSE;
|
||||||
|
thumbnail_update_timer_all = NULL;
|
||||||
|
thumbnail_update_timer_active = NULL;
|
||||||
|
thumbnail_update_timer_tooltip = NULL;
|
||||||
|
taskbar_thumbnail_jobs_done = NULL;
|
||||||
taskbar_sort_method = TASKBAR_NOSORT;
|
taskbar_sort_method = TASKBAR_NOSORT;
|
||||||
taskbar_alignment = ALIGN_LEFT;
|
taskbar_alignment = ALIGN_LEFT;
|
||||||
default_taskbarname();
|
default_taskbarname();
|
||||||
@@ -107,7 +118,10 @@ void taskbar_save_orderings()
|
|||||||
for (int j = 0; j < panel->num_desktops; j++) {
|
for (int j = 0; j < panel->num_desktops; j++) {
|
||||||
Taskbar *taskbar = &panel->taskbar[j];
|
Taskbar *taskbar = &panel->taskbar[j];
|
||||||
GList *task_order = NULL;
|
GList *task_order = NULL;
|
||||||
for (GList *c = (taskbar->area.children && taskbarname_enabled) ? taskbar->area.children->next : taskbar->area.children; c; c = c->next) {
|
for (GList *c = (taskbar->area.children && taskbarname_enabled) ? taskbar->area.children->next
|
||||||
|
: taskbar->area.children;
|
||||||
|
c;
|
||||||
|
c = c->next) {
|
||||||
Task *t = (Task *)c->data;
|
Task *t = (Task *)c->data;
|
||||||
Window *window = calloc(1, sizeof(Window));
|
Window *window = calloc(1, sizeof(Window));
|
||||||
*window = t->win;
|
*window = t->win;
|
||||||
@@ -120,6 +134,10 @@ void taskbar_save_orderings()
|
|||||||
|
|
||||||
void cleanup_taskbar()
|
void cleanup_taskbar()
|
||||||
{
|
{
|
||||||
|
stop_timeout(thumbnail_update_timer_all);
|
||||||
|
stop_timeout(thumbnail_update_timer_active);
|
||||||
|
stop_timeout(thumbnail_update_timer_tooltip);
|
||||||
|
g_list_free(taskbar_thumbnail_jobs_done);
|
||||||
taskbar_save_orderings();
|
taskbar_save_orderings();
|
||||||
if (win_to_task) {
|
if (win_to_task) {
|
||||||
while (g_hash_table_size(win_to_task)) {
|
while (g_hash_table_size(win_to_task)) {
|
||||||
@@ -170,6 +188,9 @@ void init_taskbar()
|
|||||||
panel_config.g_task.has_text = panel_config.g_task.has_icon = 1;
|
panel_config.g_task.has_text = panel_config.g_task.has_icon = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (panel_config.g_task.thumbnail_width < 8)
|
||||||
|
panel_config.g_task.thumbnail_width = 210;
|
||||||
|
|
||||||
if (!win_to_task)
|
if (!win_to_task)
|
||||||
win_to_task = g_hash_table_new_full(win_hash, win_compare, free, free_ptr_array);
|
win_to_task = g_hash_table_new_full(win_hash, win_compare, free, free_ptr_array);
|
||||||
|
|
||||||
@@ -301,7 +322,8 @@ void init_taskbar_panel(void *p)
|
|||||||
if (!panel->g_task.background[j])
|
if (!panel->g_task.background[j])
|
||||||
panel->g_task.background[j] = &g_array_index(backgrounds, Background, 0);
|
panel->g_task.background[j] = &g_array_index(backgrounds, Background, 0);
|
||||||
if (panel->g_task.background[j]->border.radius > panel->g_task.area.height / 2) {
|
if (panel->g_task.background[j]->border.radius > panel->g_task.area.height / 2) {
|
||||||
fprintf(stderr, "tint2: task%sbackground_id has a too large rounded value. Please fix your tint2rc\n",
|
fprintf(stderr,
|
||||||
|
"tint2: task%sbackground_id has a too large rounded value. Please fix your tint2rc\n",
|
||||||
j == 0 ? "_" : j == 1 ? "_active_" : j == 2 ? "_iconified_" : "_urgent_");
|
j == 0 ? "_" : j == 1 ? "_active_" : j == 2 ? "_iconified_" : "_urgent_");
|
||||||
g_array_append_val(backgrounds, *panel->g_task.background[j]);
|
g_array_append_val(backgrounds, *panel->g_task.background[j]);
|
||||||
panel->g_task.background[j] = &g_array_index(backgrounds, Background, backgrounds->len - 1);
|
panel->g_task.background[j] = &g_array_index(backgrounds, Background, backgrounds->len - 1);
|
||||||
@@ -353,6 +375,21 @@ void init_taskbar_panel(void *p)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
init_taskbarname_panel(panel);
|
init_taskbarname_panel(panel);
|
||||||
|
taskbar_start_thumbnail_timer(THUMB_MODE_ALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void taskbar_start_thumbnail_timer(ThumbnailUpdateMode mode)
|
||||||
|
{
|
||||||
|
if (!panel_config.g_task.thumbnail_enabled)
|
||||||
|
return;
|
||||||
|
if (debug_thumbnails)
|
||||||
|
fprintf(stderr, BLUE "tint2: taskbar_start_thumbnail_timer %s" RESET "\n", mode == THUMB_MODE_ACTIVE_WINDOW ? "active" : mode == THUMB_MODE_TOOLTIP_WINDOW ? "tooltip" : "all");
|
||||||
|
change_timeout(mode == THUMB_MODE_ALL ? &thumbnail_update_timer_all :
|
||||||
|
mode == THUMB_MODE_ACTIVE_WINDOW ? &thumbnail_update_timer_active : &thumbnail_update_timer_tooltip,
|
||||||
|
mode == THUMB_MODE_TOOLTIP_WINDOW ? 1000 : 500,
|
||||||
|
mode == THUMB_MODE_ALL ? 10 * 1000 : 0,
|
||||||
|
taskbar_update_thumbnails,
|
||||||
|
(void *)(long)mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void taskbar_init_fonts()
|
void taskbar_init_fonts()
|
||||||
@@ -467,7 +504,6 @@ void taskbar_refresh_tasklist()
|
|||||||
{
|
{
|
||||||
if (!taskbar_enabled)
|
if (!taskbar_enabled)
|
||||||
return;
|
return;
|
||||||
// fprintf(stderr, "tint2: %s %d:\n", __func__, __LINE__);
|
|
||||||
|
|
||||||
int num_results;
|
int num_results;
|
||||||
Window *win = server_get_property(server.root_win, server.atom._NET_CLIENT_LIST, XA_WINDOW, &num_results);
|
Window *win = server_get_property(server.root_win, server.atom._NET_CLIENT_LIST, XA_WINDOW, &num_results);
|
||||||
@@ -521,7 +557,6 @@ gboolean resize_taskbar(void *obj)
|
|||||||
Taskbar *taskbar = (Taskbar *)obj;
|
Taskbar *taskbar = (Taskbar *)obj;
|
||||||
Panel *panel = (Panel *)taskbar->area.panel;
|
Panel *panel = (Panel *)taskbar->area.panel;
|
||||||
|
|
||||||
// fprintf(stderr, "tint2: resize_taskbar %d %d\n", taskbar->area.posx, taskbar->area.posy);
|
|
||||||
if (panel_horizontal) {
|
if (panel_horizontal) {
|
||||||
relayout_with_constraint(&taskbar->area, panel->g_task.maximum_width);
|
relayout_with_constraint(&taskbar->area, panel->g_task.maximum_width);
|
||||||
|
|
||||||
@@ -779,3 +814,48 @@ void update_minimized_icon_positions(void *p)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void taskbar_update_thumbnails(void *arg)
|
||||||
|
{
|
||||||
|
if (!panel_config.g_task.thumbnail_enabled)
|
||||||
|
return;
|
||||||
|
ThumbnailUpdateMode mode = (ThumbnailUpdateMode)(long)arg;
|
||||||
|
if (debug_thumbnails)
|
||||||
|
fprintf(stderr, BLUE "tint2: taskbar_update_thumbnails %s" RESET "\n", mode == THUMB_MODE_ACTIVE_WINDOW ? "active" : mode == THUMB_MODE_TOOLTIP_WINDOW ? "tooltip" : "all");
|
||||||
|
double start_time = get_time();
|
||||||
|
for (int i = 0; i < num_panels; i++) {
|
||||||
|
Panel *panel = &panels[i];
|
||||||
|
for (int j = 0; j < panel->num_desktops; j++) {
|
||||||
|
Taskbar *taskbar = &panel->taskbar[j];
|
||||||
|
for (GList *c = (taskbar->area.children && taskbarname_enabled) ? taskbar->area.children->next
|
||||||
|
: taskbar->area.children;
|
||||||
|
c;
|
||||||
|
c = c->next) {
|
||||||
|
Task *t = (Task *)c->data;
|
||||||
|
if ((mode == THUMB_MODE_ALL && t->current_state == TASK_ACTIVE && !g_list_find(taskbar_thumbnail_jobs_done, t)) || (mode == THUMB_MODE_ACTIVE_WINDOW && t->current_state == TASK_ACTIVE) ||
|
||||||
|
(mode == THUMB_MODE_TOOLTIP_WINDOW && g_tooltip.mapped && g_tooltip.area == &t->area)) {
|
||||||
|
task_refresh_thumbnail(t);
|
||||||
|
if (mode == THUMB_MODE_ALL)
|
||||||
|
taskbar_thumbnail_jobs_done = g_list_append(taskbar_thumbnail_jobs_done, t);
|
||||||
|
if (t->thumbnail && mode == THUMB_MODE_TOOLTIP_WINDOW) {
|
||||||
|
taskbar_start_thumbnail_timer(THUMB_MODE_TOOLTIP_WINDOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mode == THUMB_MODE_ALL) {
|
||||||
|
double now = get_time();
|
||||||
|
if (now - start_time > 0.030) {
|
||||||
|
change_timeout(&thumbnail_update_timer_all, 50, 10 * 1000, taskbar_update_thumbnails, arg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mode == THUMB_MODE_ALL) {
|
||||||
|
if (taskbar_thumbnail_jobs_done) {
|
||||||
|
g_list_free(taskbar_thumbnail_jobs_done);
|
||||||
|
taskbar_thumbnail_jobs_done = NULL;
|
||||||
|
change_timeout(&thumbnail_update_timer_all, 10 * 1000, 10 * 1000, taskbar_update_thumbnails, arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,6 +25,12 @@ typedef enum TaskbarSortMethod {
|
|||||||
TASKBAR_SORT_MRU,
|
TASKBAR_SORT_MRU,
|
||||||
} TaskbarSortMethod;
|
} TaskbarSortMethod;
|
||||||
|
|
||||||
|
typedef enum ThumbnailUpdateMode {
|
||||||
|
THUMB_MODE_ACTIVE_WINDOW = 0,
|
||||||
|
THUMB_MODE_TOOLTIP_WINDOW,
|
||||||
|
THUMB_MODE_ALL
|
||||||
|
} ThumbnailUpdateMode;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Area area;
|
Area area;
|
||||||
gchar *name;
|
gchar *name;
|
||||||
@@ -72,6 +78,7 @@ void init_taskbar_panel(void *p);
|
|||||||
|
|
||||||
gboolean resize_taskbar(void *obj);
|
gboolean resize_taskbar(void *obj);
|
||||||
void taskbar_default_font_changed();
|
void taskbar_default_font_changed();
|
||||||
|
void taskbar_start_thumbnail_timer(ThumbnailUpdateMode mode);
|
||||||
|
|
||||||
// Reloads the entire list of tasks from the window manager and recreates the task buttons.
|
// Reloads the entire list of tasks from the window manager and recreates the task buttons.
|
||||||
void taskbar_refresh_tasklist();
|
void taskbar_refresh_tasklist();
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ GtkWidget *current_background, *background_fill_color, *background_border_color,
|
|||||||
*background_fill_color_over, *background_border_color_over, *background_gradient_over, *background_fill_color_press,
|
*background_fill_color_over, *background_border_color_over, *background_gradient_over, *background_fill_color_press,
|
||||||
*background_border_color_press, *background_gradient_press, *background_border_width, *background_corner_radius,
|
*background_border_color_press, *background_gradient_press, *background_border_width, *background_corner_radius,
|
||||||
*background_border_sides_top, *background_border_sides_bottom, *background_border_sides_left,
|
*background_border_sides_top, *background_border_sides_bottom, *background_border_sides_left,
|
||||||
*background_border_sides_right;
|
*background_border_sides_right, *background_border_content_tint_weight, *background_fill_content_tint_weight;
|
||||||
|
|
||||||
GtkWidget *create_background_combo(const char *label)
|
GtkWidget *create_background_combo(const char *label)
|
||||||
{
|
{
|
||||||
@@ -115,7 +115,9 @@ void create_background(GtkWidget *parent)
|
|||||||
GTK_TYPE_BOOL,
|
GTK_TYPE_BOOL,
|
||||||
GTK_TYPE_BOOL,
|
GTK_TYPE_BOOL,
|
||||||
GTK_TYPE_BOOL,
|
GTK_TYPE_BOOL,
|
||||||
GTK_TYPE_BOOL);
|
GTK_TYPE_BOOL,
|
||||||
|
GTK_TYPE_DOUBLE,
|
||||||
|
GTK_TYPE_DOUBLE);
|
||||||
|
|
||||||
GtkWidget *table, *label, *button;
|
GtkWidget *table, *label, *button;
|
||||||
int row, col;
|
int row, col;
|
||||||
@@ -175,6 +177,19 @@ void create_background(GtkWidget *parent)
|
|||||||
col++;
|
col++;
|
||||||
gtk_tooltips_set_tip(tooltips, background_fill_color, _("The fill color of the current background"), NULL);
|
gtk_tooltips_set_tip(tooltips, background_fill_color, _("The fill color of the current background"), NULL);
|
||||||
|
|
||||||
|
row++, col = 2;
|
||||||
|
label = gtk_label_new(_("Fill tint"));
|
||||||
|
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
|
||||||
|
gtk_widget_show(label);
|
||||||
|
gtk_table_attach(GTK_TABLE(table), label, col, col + 1, row, row + 1, GTK_FILL, 0, 0, 0);
|
||||||
|
col++;
|
||||||
|
|
||||||
|
background_fill_content_tint_weight = gtk_spin_button_new_with_range(0, 100, 1);
|
||||||
|
gtk_widget_show(background_fill_content_tint_weight);
|
||||||
|
gtk_table_attach(GTK_TABLE(table), background_fill_content_tint_weight, col, col + 1, row, row + 1, GTK_FILL, 0, 0, 0);
|
||||||
|
col++;
|
||||||
|
gtk_tooltips_set_tip(tooltips, background_fill_content_tint_weight, _("How much the border color should be tinted with the content color"), NULL);
|
||||||
|
|
||||||
row++, col = 2;
|
row++, col = 2;
|
||||||
label = gtk_label_new(_("Border color"));
|
label = gtk_label_new(_("Border color"));
|
||||||
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
|
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
|
||||||
@@ -189,6 +204,19 @@ void create_background(GtkWidget *parent)
|
|||||||
col++;
|
col++;
|
||||||
gtk_tooltips_set_tip(tooltips, background_border_color, _("The border color of the current background"), NULL);
|
gtk_tooltips_set_tip(tooltips, background_border_color, _("The border color of the current background"), NULL);
|
||||||
|
|
||||||
|
row++, col = 2;
|
||||||
|
label = gtk_label_new(_("Border tint"));
|
||||||
|
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
|
||||||
|
gtk_widget_show(label);
|
||||||
|
gtk_table_attach(GTK_TABLE(table), label, col, col + 1, row, row + 1, GTK_FILL, 0, 0, 0);
|
||||||
|
col++;
|
||||||
|
|
||||||
|
background_border_content_tint_weight = gtk_spin_button_new_with_range(0, 100, 1);
|
||||||
|
gtk_widget_show(background_border_content_tint_weight);
|
||||||
|
gtk_table_attach(GTK_TABLE(table), background_border_content_tint_weight, col, col + 1, row, row + 1, GTK_FILL, 0, 0, 0);
|
||||||
|
col++;
|
||||||
|
gtk_tooltips_set_tip(tooltips, background_border_content_tint_weight, _("How much the border color should be tinted with the content color"), NULL);
|
||||||
|
|
||||||
row++, col = 2;
|
row++, col = 2;
|
||||||
label = gtk_label_new(_("Gradient"));
|
label = gtk_label_new(_("Gradient"));
|
||||||
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
|
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
|
||||||
@@ -366,6 +394,8 @@ void create_background(GtkWidget *parent)
|
|||||||
g_signal_connect(G_OBJECT(background_border_sides_bottom), "toggled", G_CALLBACK(background_update), NULL);
|
g_signal_connect(G_OBJECT(background_border_sides_bottom), "toggled", G_CALLBACK(background_update), NULL);
|
||||||
g_signal_connect(G_OBJECT(background_border_sides_left), "toggled", G_CALLBACK(background_update), NULL);
|
g_signal_connect(G_OBJECT(background_border_sides_left), "toggled", G_CALLBACK(background_update), NULL);
|
||||||
g_signal_connect(G_OBJECT(background_border_sides_right), "toggled", G_CALLBACK(background_update), NULL);
|
g_signal_connect(G_OBJECT(background_border_sides_right), "toggled", G_CALLBACK(background_update), NULL);
|
||||||
|
g_signal_connect(G_OBJECT(background_border_content_tint_weight), "value-changed", G_CALLBACK(background_update), NULL);
|
||||||
|
g_signal_connect(G_OBJECT(background_fill_content_tint_weight), "value-changed", G_CALLBACK(background_update), NULL);
|
||||||
|
|
||||||
change_paragraph(parent);
|
change_paragraph(parent);
|
||||||
}
|
}
|
||||||
@@ -750,6 +780,9 @@ void background_update(GtkWidget *widget, gpointer data)
|
|||||||
r = gtk_spin_button_get_value(GTK_SPIN_BUTTON(background_corner_radius));
|
r = gtk_spin_button_get_value(GTK_SPIN_BUTTON(background_corner_radius));
|
||||||
b = gtk_spin_button_get_value(GTK_SPIN_BUTTON(background_border_width));
|
b = gtk_spin_button_get_value(GTK_SPIN_BUTTON(background_border_width));
|
||||||
|
|
||||||
|
double fill_weight = gtk_spin_button_get_value(GTK_SPIN_BUTTON(background_fill_content_tint_weight));
|
||||||
|
double border_weight = gtk_spin_button_get_value(GTK_SPIN_BUTTON(background_border_content_tint_weight));
|
||||||
|
|
||||||
gboolean sideTop = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(background_border_sides_top));
|
gboolean sideTop = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(background_border_sides_top));
|
||||||
gboolean sideBottom = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(background_border_sides_bottom));
|
gboolean sideBottom = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(background_border_sides_bottom));
|
||||||
gboolean sideLeft = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(background_border_sides_left));
|
gboolean sideLeft = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(background_border_sides_left));
|
||||||
@@ -836,6 +869,10 @@ void background_update(GtkWidget *widget, gpointer data)
|
|||||||
sideLeft,
|
sideLeft,
|
||||||
bgColBorderSidesRight,
|
bgColBorderSidesRight,
|
||||||
sideRight,
|
sideRight,
|
||||||
|
bgColFillWeight,
|
||||||
|
fill_weight,
|
||||||
|
bgColBorderWeight,
|
||||||
|
border_weight,
|
||||||
-1);
|
-1);
|
||||||
background_update_image(index);
|
background_update_image(index);
|
||||||
}
|
}
|
||||||
@@ -862,6 +899,8 @@ void current_background_changed(GtkWidget *widget, gpointer data)
|
|||||||
gtk_widget_set_sensitive(background_border_sides_left, index > 0);
|
gtk_widget_set_sensitive(background_border_sides_left, index > 0);
|
||||||
gtk_widget_set_sensitive(background_border_sides_right, index > 0);
|
gtk_widget_set_sensitive(background_border_sides_right, index > 0);
|
||||||
gtk_widget_set_sensitive(background_corner_radius, index > 0);
|
gtk_widget_set_sensitive(background_corner_radius, index > 0);
|
||||||
|
gtk_widget_set_sensitive(background_border_content_tint_weight, index > 0);
|
||||||
|
gtk_widget_set_sensitive(background_fill_content_tint_weight, index > 0);
|
||||||
|
|
||||||
background_updates_disabled = TRUE;
|
background_updates_disabled = TRUE;
|
||||||
|
|
||||||
@@ -875,6 +914,9 @@ void current_background_changed(GtkWidget *widget, gpointer data)
|
|||||||
int r;
|
int r;
|
||||||
int b;
|
int b;
|
||||||
|
|
||||||
|
double fill_weight;
|
||||||
|
double border_weight;
|
||||||
|
|
||||||
gboolean sideTop;
|
gboolean sideTop;
|
||||||
gboolean sideBottom;
|
gboolean sideBottom;
|
||||||
gboolean sideLeft;
|
gboolean sideLeft;
|
||||||
@@ -938,6 +980,10 @@ void current_background_changed(GtkWidget *widget, gpointer data)
|
|||||||
&sideLeft,
|
&sideLeft,
|
||||||
bgColBorderSidesRight,
|
bgColBorderSidesRight,
|
||||||
&sideRight,
|
&sideRight,
|
||||||
|
bgColFillWeight,
|
||||||
|
&fill_weight,
|
||||||
|
bgColBorderWeight,
|
||||||
|
&border_weight,
|
||||||
-1);
|
-1);
|
||||||
|
|
||||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(background_border_sides_top), sideTop);
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(background_border_sides_top), sideTop);
|
||||||
@@ -968,6 +1014,9 @@ void current_background_changed(GtkWidget *widget, gpointer data)
|
|||||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(background_border_width), b);
|
gtk_spin_button_set_value(GTK_SPIN_BUTTON(background_border_width), b);
|
||||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(background_corner_radius), r);
|
gtk_spin_button_set_value(GTK_SPIN_BUTTON(background_corner_radius), r);
|
||||||
|
|
||||||
|
gtk_spin_button_set_value(GTK_SPIN_BUTTON(background_fill_content_tint_weight), fill_weight);
|
||||||
|
gtk_spin_button_set_value(GTK_SPIN_BUTTON(background_border_content_tint_weight), border_weight);
|
||||||
|
|
||||||
g_boxed_free(GDK_TYPE_COLOR, fillColor);
|
g_boxed_free(GDK_TYPE_COLOR, fillColor);
|
||||||
g_boxed_free(GDK_TYPE_COLOR, borderColor);
|
g_boxed_free(GDK_TYPE_COLOR, borderColor);
|
||||||
g_boxed_free(GDK_TYPE_COLOR, fillColorOver);
|
g_boxed_free(GDK_TYPE_COLOR, fillColorOver);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
2418
src/tint2conf/po/es.po
Normal file
2418
src/tint2conf/po/es.po
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -15,3 +15,22 @@ do
|
|||||||
cat ${lang}.pox > ${lang}.po
|
cat ${lang}.pox > ${lang}.po
|
||||||
rm ${lang}.pox
|
rm ${lang}.pox
|
||||||
done
|
done
|
||||||
|
|
||||||
|
set +e
|
||||||
|
set +x
|
||||||
|
echo "Status:"
|
||||||
|
for f in *.po
|
||||||
|
do
|
||||||
|
lang=$(basename $f .po)
|
||||||
|
fuzzy=$(cat ${lang}.po | grep -A2 "#, fuzzy")
|
||||||
|
missing=$(cat ${lang}.po | grep -B1 'msgstr ""')
|
||||||
|
if [ -z "$fuzzy" ] && [ -z "$missing" ]
|
||||||
|
then
|
||||||
|
echo $lang ": Up to date"
|
||||||
|
else
|
||||||
|
count=$(( $(echo -e "$fuzzy" "\n" "$missing" | grep "^--$" | wc -l) + 1))
|
||||||
|
echo "${lang}: Translation incomplete: ${count} strings to be updated. See ${lang}.todo"
|
||||||
|
echo "$fuzzy" > ${lang}.todo
|
||||||
|
echo "$missing" >> ${lang}.todo
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ GtkWidget *systray_background, *systray_monitor, *systray_name_filter;
|
|||||||
|
|
||||||
// tooltip
|
// tooltip
|
||||||
GtkWidget *tooltip_padding_x, *tooltip_padding_y, *tooltip_font, *tooltip_font_set, *tooltip_font_color;
|
GtkWidget *tooltip_padding_x, *tooltip_padding_y, *tooltip_font, *tooltip_font_set, *tooltip_font_color;
|
||||||
GtkWidget *tooltip_task_show, *tooltip_show_after, *tooltip_hide_after;
|
GtkWidget *tooltip_task_show, *tooltip_show_after, *tooltip_hide_after, *tooltip_task_thumbnail, *tooltip_task_thumbnail_size;
|
||||||
GtkWidget *clock_format_tooltip, *clock_tmz_tooltip;
|
GtkWidget *clock_format_tooltip, *clock_tmz_tooltip;
|
||||||
GtkWidget *tooltip_background;
|
GtkWidget *tooltip_background;
|
||||||
|
|
||||||
@@ -3288,6 +3288,36 @@ void create_task(GtkWidget *parent)
|
|||||||
"over task buttons."),
|
"over task buttons."),
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
row++, col = 2;
|
||||||
|
label = gtk_label_new(_("Thumbnails"));
|
||||||
|
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
|
||||||
|
gtk_widget_show(label);
|
||||||
|
gtk_table_attach(GTK_TABLE(table), label, col, col + 1, row, row + 1, GTK_FILL, 0, 0, 0);
|
||||||
|
col++;
|
||||||
|
|
||||||
|
tooltip_task_thumbnail = gtk_check_button_new();
|
||||||
|
gtk_widget_show(tooltip_task_thumbnail);
|
||||||
|
gtk_table_attach(GTK_TABLE(table), tooltip_task_thumbnail, col, col + 1, row, row + 1, GTK_FILL, 0, 0, 0);
|
||||||
|
col++;
|
||||||
|
gtk_tooltips_set_tip(tooltips,
|
||||||
|
tooltip_task_thumbnail,
|
||||||
|
_("If enabled, a tooltip showing the window thumbnail is displayed when the mouse cursor moves "
|
||||||
|
"over task buttons."),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
row++, col = 2;
|
||||||
|
label = gtk_label_new(_("Thumbnail size"));
|
||||||
|
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
|
||||||
|
gtk_widget_show(label);
|
||||||
|
gtk_table_attach(GTK_TABLE(table), label, col, col + 1, row, row + 1, GTK_FILL, 0, 0, 0);
|
||||||
|
col++;
|
||||||
|
|
||||||
|
tooltip_task_thumbnail_size = gtk_spin_button_new_with_range(8, 9000, 1);
|
||||||
|
gtk_spin_button_set_value(GTK_SPIN_BUTTON(tooltip_task_thumbnail_size), 210);
|
||||||
|
gtk_widget_show(tooltip_task_thumbnail_size);
|
||||||
|
gtk_table_attach(GTK_TABLE(table), tooltip_task_thumbnail_size, col, col + 1, row, row + 1, GTK_FILL, 0, 0, 0);
|
||||||
|
col++;
|
||||||
|
|
||||||
row++, col = 2;
|
row++, col = 2;
|
||||||
label = gtk_label_new(_("Maximum width"));
|
label = gtk_label_new(_("Maximum width"));
|
||||||
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
|
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
|
||||||
@@ -5136,8 +5166,8 @@ void create_systemtray(GtkWidget *parent)
|
|||||||
_("Specifies the order used to arrange the system tray icons. \n"
|
_("Specifies the order used to arrange the system tray icons. \n"
|
||||||
"'Ascending' means that icons are sorted in ascending order of their window names. \n"
|
"'Ascending' means that icons are sorted in ascending order of their window names. \n"
|
||||||
"'Descending' means that icons are sorted in descending order of their window names. \n"
|
"'Descending' means that icons are sorted in descending order of their window names. \n"
|
||||||
"'Left to right' means that icons are always added to the left. \n"
|
"'Left to right' means that icons are always added to the right. \n"
|
||||||
"'Right to left' means that icons are always added to the right."),
|
"'Right to left' means that icons are always added to the left."),
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
row++;
|
row++;
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ extern GtkWidget *systray_background, *systray_monitor, *systray_name_filter;
|
|||||||
|
|
||||||
// tooltip
|
// tooltip
|
||||||
extern GtkWidget *tooltip_padding_x, *tooltip_padding_y, *tooltip_font, *tooltip_font_set, *tooltip_font_color;
|
extern GtkWidget *tooltip_padding_x, *tooltip_padding_y, *tooltip_font, *tooltip_font_set, *tooltip_font_color;
|
||||||
extern GtkWidget *tooltip_task_show, *tooltip_show_after, *tooltip_hide_after;
|
extern GtkWidget *tooltip_task_show, *tooltip_show_after, *tooltip_hide_after, *tooltip_task_thumbnail, *tooltip_task_thumbnail_size;
|
||||||
extern GtkWidget *clock_format_tooltip, *clock_tmz_tooltip;
|
extern GtkWidget *clock_format_tooltip, *clock_tmz_tooltip;
|
||||||
extern GtkWidget *tooltip_background;
|
extern GtkWidget *tooltip_background;
|
||||||
|
|
||||||
@@ -203,6 +203,8 @@ enum {
|
|||||||
bgColBorderSidesBottom,
|
bgColBorderSidesBottom,
|
||||||
bgColBorderSidesLeft,
|
bgColBorderSidesLeft,
|
||||||
bgColBorderSidesRight,
|
bgColBorderSidesRight,
|
||||||
|
bgColFillWeight,
|
||||||
|
bgColBorderWeight,
|
||||||
bgNumCols
|
bgNumCols
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -211,7 +213,7 @@ extern GtkWidget *current_background, *background_fill_color, *background_border
|
|||||||
*background_fill_color_over, *background_border_color_over, *background_gradient_over, *background_fill_color_press,
|
*background_fill_color_over, *background_border_color_over, *background_gradient_over, *background_fill_color_press,
|
||||||
*background_border_color_press, *background_gradient_press, *background_border_width, *background_border_sides_top,
|
*background_border_color_press, *background_gradient_press, *background_border_width, *background_border_sides_top,
|
||||||
*background_border_sides_bottom, *background_border_sides_left, *background_border_sides_right,
|
*background_border_sides_bottom, *background_border_sides_left, *background_border_sides_right,
|
||||||
*background_corner_radius;
|
*background_corner_radius, *background_border_content_tint_weight, *background_fill_content_tint_weight;
|
||||||
|
|
||||||
// gradients
|
// gradients
|
||||||
enum { grColPixbuf = 0, grColId, grColText, grNumCols };
|
enum { grColPixbuf = 0, grColId, grColText, grNumCols };
|
||||||
|
|||||||
@@ -161,6 +161,8 @@ void config_write_backgrounds(FILE *fp)
|
|||||||
|
|
||||||
int r;
|
int r;
|
||||||
int b;
|
int b;
|
||||||
|
double fill_weight;
|
||||||
|
double border_weight;
|
||||||
gboolean sideTop;
|
gboolean sideTop;
|
||||||
gboolean sideBottom;
|
gboolean sideBottom;
|
||||||
gboolean sideLeft;
|
gboolean sideLeft;
|
||||||
@@ -228,6 +230,10 @@ void config_write_backgrounds(FILE *fp)
|
|||||||
&sideLeft,
|
&sideLeft,
|
||||||
bgColBorderSidesRight,
|
bgColBorderSidesRight,
|
||||||
&sideRight,
|
&sideRight,
|
||||||
|
bgColFillWeight,
|
||||||
|
&fill_weight,
|
||||||
|
bgColBorderWeight,
|
||||||
|
&border_weight,
|
||||||
-1);
|
-1);
|
||||||
fprintf(fp, "# Background %d: %s\n", index, text ? text : "");
|
fprintf(fp, "# Background %d: %s\n", index, text ? text : "");
|
||||||
fprintf(fp, "rounded = %d\n", r);
|
fprintf(fp, "rounded = %d\n", r);
|
||||||
@@ -245,6 +251,9 @@ void config_write_backgrounds(FILE *fp)
|
|||||||
strcat(sides, "R");
|
strcat(sides, "R");
|
||||||
fprintf(fp, "border_sides = %s\n", sides);
|
fprintf(fp, "border_sides = %s\n", sides);
|
||||||
|
|
||||||
|
fprintf(fp, "border_content_tint_weight = %d\n", (int)(border_weight));
|
||||||
|
fprintf(fp, "background_content_tint_weight = %d\n", (int)(fill_weight));
|
||||||
|
|
||||||
config_write_color(fp, "background_color", *fillColor, fillOpacity);
|
config_write_color(fp, "background_color", *fillColor, fillOpacity);
|
||||||
config_write_color(fp, "border_color", *borderColor, borderOpacity);
|
config_write_color(fp, "border_color", *borderColor, borderOpacity);
|
||||||
if (gradient_id >= 0)
|
if (gradient_id >= 0)
|
||||||
@@ -517,6 +526,11 @@ void config_write_task(FILE *fp)
|
|||||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(task_font_set)))
|
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(task_font_set)))
|
||||||
fprintf(fp, "task_font = %s\n", gtk_font_button_get_font_name(GTK_FONT_BUTTON(task_font)));
|
fprintf(fp, "task_font = %s\n", gtk_font_button_get_font_name(GTK_FONT_BUTTON(task_font)));
|
||||||
fprintf(fp, "task_tooltip = %d\n", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tooltip_task_show)) ? 1 : 0);
|
fprintf(fp, "task_tooltip = %d\n", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tooltip_task_show)) ? 1 : 0);
|
||||||
|
fprintf(fp, "task_thumbnail = %d\n", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tooltip_task_thumbnail)) ? 1 : 0);
|
||||||
|
fprintf(fp,
|
||||||
|
"task_thumbnail_size = %d\n",
|
||||||
|
(int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(tooltip_task_thumbnail_size)));
|
||||||
|
|
||||||
|
|
||||||
// same for: "" _normal _active _urgent _iconified
|
// same for: "" _normal _active _urgent _iconified
|
||||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(task_default_color_set))) {
|
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(task_default_color_set))) {
|
||||||
@@ -1225,6 +1239,12 @@ void add_entry(char *key, char *value)
|
|||||||
int id = gradient_index_safe(atoi(value));
|
int id = gradient_index_safe(atoi(value));
|
||||||
gtk_combo_box_set_active(GTK_COMBO_BOX(background_gradient_press), id);
|
gtk_combo_box_set_active(GTK_COMBO_BOX(background_gradient_press), id);
|
||||||
background_force_update();
|
background_force_update();
|
||||||
|
} else if (strcmp(key, "border_content_tint_weight") == 0) {
|
||||||
|
gtk_spin_button_set_value(GTK_SPIN_BUTTON(background_border_content_tint_weight), atoi(value));
|
||||||
|
background_force_update();
|
||||||
|
} else if (strcmp(key, "background_content_tint_weight") == 0) {
|
||||||
|
gtk_spin_button_set_value(GTK_SPIN_BUTTON(background_fill_content_tint_weight), atoi(value));
|
||||||
|
background_force_update();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Panel */
|
/* Panel */
|
||||||
@@ -1732,6 +1752,10 @@ void add_entry(char *key, char *value)
|
|||||||
else if (strcmp(key, "task_tooltip") == 0 || strcmp(key, "tooltip") == 0) {
|
else if (strcmp(key, "task_tooltip") == 0 || strcmp(key, "tooltip") == 0) {
|
||||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tooltip_task_show), atoi(value));
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tooltip_task_show), atoi(value));
|
||||||
}
|
}
|
||||||
|
else if (strcmp(key, "task_thumbnail") == 0)
|
||||||
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tooltip_task_thumbnail), atoi(value));
|
||||||
|
else if (strcmp(key, "task_thumbnail_size") == 0)
|
||||||
|
gtk_spin_button_set_value(GTK_SPIN_BUTTON(tooltip_task_thumbnail_size), MAX(8, atoi(value)));
|
||||||
|
|
||||||
/* Systray */
|
/* Systray */
|
||||||
else if (strcmp(key, "systray") == 0) {
|
else if (strcmp(key, "systray") == 0) {
|
||||||
|
|||||||
@@ -54,8 +54,9 @@ void default_tooltip()
|
|||||||
void cleanup_tooltip()
|
void cleanup_tooltip()
|
||||||
{
|
{
|
||||||
stop_tooltip_timeout();
|
stop_tooltip_timeout();
|
||||||
|
stop_timeout(g_tooltip.update_timeout);
|
||||||
tooltip_hide(NULL);
|
tooltip_hide(NULL);
|
||||||
tooltip_copy_text(NULL);
|
tooltip_update_contents_for(NULL);
|
||||||
if (g_tooltip.window)
|
if (g_tooltip.window)
|
||||||
XDestroyWindow(server.display, g_tooltip.window);
|
XDestroyWindow(server.display, g_tooltip.window);
|
||||||
g_tooltip.window = 0;
|
g_tooltip.window = 0;
|
||||||
@@ -118,7 +119,7 @@ void tooltip_trigger_show(Area *area, Panel *p, XEvent *e)
|
|||||||
just_shown = TRUE;
|
just_shown = TRUE;
|
||||||
g_tooltip.panel = p;
|
g_tooltip.panel = p;
|
||||||
if (g_tooltip.mapped && g_tooltip.area != area) {
|
if (g_tooltip.mapped && g_tooltip.area != area) {
|
||||||
tooltip_copy_text(area);
|
tooltip_update_contents_for(area);
|
||||||
tooltip_update();
|
tooltip_update();
|
||||||
stop_tooltip_timeout();
|
stop_tooltip_timeout();
|
||||||
} else if (!g_tooltip.mapped) {
|
} else if (!g_tooltip.mapped) {
|
||||||
@@ -133,7 +134,7 @@ void tooltip_show(void *arg)
|
|||||||
XTranslateCoordinates(server.display, server.root_win, g_tooltip.panel->main_win, x, y, &mx, &my, &w);
|
XTranslateCoordinates(server.display, server.root_win, g_tooltip.panel->main_win, x, y, &mx, &my, &w);
|
||||||
Area *area = find_area_under_mouse(g_tooltip.panel, mx, my);
|
Area *area = find_area_under_mouse(g_tooltip.panel, mx, my);
|
||||||
if (!g_tooltip.mapped && area->_get_tooltip_text) {
|
if (!g_tooltip.mapped && area->_get_tooltip_text) {
|
||||||
tooltip_copy_text(area);
|
tooltip_update_contents_for(area);
|
||||||
g_tooltip.mapped = True;
|
g_tooltip.mapped = True;
|
||||||
XMapWindow(server.display, g_tooltip.window);
|
XMapWindow(server.display, g_tooltip.window);
|
||||||
tooltip_update();
|
tooltip_update();
|
||||||
@@ -144,7 +145,7 @@ void tooltip_show(void *arg)
|
|||||||
void tooltip_update_geometry()
|
void tooltip_update_geometry()
|
||||||
{
|
{
|
||||||
Panel *panel = g_tooltip.panel;
|
Panel *panel = g_tooltip.panel;
|
||||||
int screen_width = server.monitors[panel->monitor].x + server.monitors[panel->monitor].width;
|
int screen_width = server.monitors[panel->monitor].width;
|
||||||
|
|
||||||
cairo_surface_t *cs = cairo_xlib_surface_create(server.display, g_tooltip.window, server.visual, width, height);
|
cairo_surface_t *cs = cairo_xlib_surface_create(server.display, g_tooltip.window, server.visual, width, height);
|
||||||
cairo_t *c = cairo_create(cs);
|
cairo_t *c = cairo_create(cs);
|
||||||
@@ -152,16 +153,25 @@ void tooltip_update_geometry()
|
|||||||
|
|
||||||
pango_layout_set_font_description(layout, g_tooltip.font_desc);
|
pango_layout_set_font_description(layout, g_tooltip.font_desc);
|
||||||
PangoRectangle r1, r2;
|
PangoRectangle r1, r2;
|
||||||
pango_layout_set_text(layout, "1234567890", -1);
|
pango_layout_set_text(layout, "1234567890abcdef", -1);
|
||||||
pango_layout_get_pixel_extents(layout, &r1, &r2);
|
pango_layout_get_pixel_extents(layout, &r1, &r2);
|
||||||
int max_width = MIN(r2.width * 7, screen_width * 2 / 3);
|
int max_width = MIN(r2.width * 5, screen_width * 2 / 3);
|
||||||
|
if (g_tooltip.image && cairo_image_surface_get_width(g_tooltip.image) > 0) {
|
||||||
|
max_width = left_right_bg_border_width(g_tooltip.bg) + 2 * g_tooltip.paddingx +
|
||||||
|
cairo_image_surface_get_width(g_tooltip.image);
|
||||||
|
}
|
||||||
pango_layout_set_width(layout, max_width * PANGO_SCALE);
|
pango_layout_set_width(layout, max_width * PANGO_SCALE);
|
||||||
|
|
||||||
pango_layout_set_text(layout, g_tooltip.tooltip_text, -1);
|
pango_layout_set_text(layout, g_tooltip.tooltip_text ? g_tooltip.tooltip_text : "1234567890abcdef", -1);
|
||||||
pango_layout_set_wrap(layout, PANGO_WRAP_WORD);
|
pango_layout_set_wrap(layout, PANGO_WRAP_WORD);
|
||||||
pango_layout_get_pixel_extents(layout, &r1, &r2);
|
pango_layout_get_pixel_extents(layout, &r1, &r2);
|
||||||
width = left_right_bg_border_width(g_tooltip.bg) + 2 * g_tooltip.paddingx + r2.width;
|
width = left_right_bg_border_width(g_tooltip.bg) + 2 * g_tooltip.paddingx + r2.width;
|
||||||
height = top_bottom_bg_border_width(g_tooltip.bg) + 2 * g_tooltip.paddingy + r2.height;
|
height = top_bottom_bg_border_width(g_tooltip.bg) + 2 * g_tooltip.paddingy + r2.height;
|
||||||
|
if (g_tooltip.image && cairo_image_surface_get_width(g_tooltip.image) > 0) {
|
||||||
|
width = left_right_bg_border_width(g_tooltip.bg) + 2 * g_tooltip.paddingx +
|
||||||
|
cairo_image_surface_get_width(g_tooltip.image);
|
||||||
|
height += g_tooltip.paddingy + cairo_image_surface_get_height(g_tooltip.image);
|
||||||
|
}
|
||||||
|
|
||||||
if (panel_horizontal && panel_position & BOTTOM)
|
if (panel_horizontal && panel_position & BOTTOM)
|
||||||
y = panel->posy - height;
|
y = panel->posy - height;
|
||||||
@@ -278,8 +288,16 @@ void tooltip_update()
|
|||||||
-r1.x / 2 + left_bg_border_width(g_tooltip.bg) + g_tooltip.paddingx,
|
-r1.x / 2 + left_bg_border_width(g_tooltip.bg) + g_tooltip.paddingx,
|
||||||
-r1.y / 2 + 1 + top_bg_border_width(g_tooltip.bg) + g_tooltip.paddingy);
|
-r1.y / 2 + 1 + top_bg_border_width(g_tooltip.bg) + g_tooltip.paddingy);
|
||||||
pango_cairo_show_layout(c, layout);
|
pango_cairo_show_layout(c, layout);
|
||||||
|
|
||||||
g_object_unref(layout);
|
g_object_unref(layout);
|
||||||
|
|
||||||
|
if (g_tooltip.image) {
|
||||||
|
cairo_translate(c,
|
||||||
|
left_bg_border_width(g_tooltip.bg) + g_tooltip.paddingx,
|
||||||
|
height - bottom_bg_border_width(g_tooltip.bg) - g_tooltip.paddingy - cairo_image_surface_get_height(g_tooltip.image));
|
||||||
|
cairo_set_source_surface(c, g_tooltip.image, 0, 0);
|
||||||
|
cairo_paint(c);
|
||||||
|
}
|
||||||
|
|
||||||
cairo_destroy(c);
|
cairo_destroy(c);
|
||||||
cairo_surface_destroy(cs);
|
cairo_surface_destroy(cs);
|
||||||
}
|
}
|
||||||
@@ -287,7 +305,7 @@ void tooltip_update()
|
|||||||
void tooltip_trigger_hide()
|
void tooltip_trigger_hide()
|
||||||
{
|
{
|
||||||
if (g_tooltip.mapped) {
|
if (g_tooltip.mapped) {
|
||||||
tooltip_copy_text(0);
|
tooltip_update_contents_for(NULL);
|
||||||
start_hide_timeout();
|
start_hide_timeout();
|
||||||
} else {
|
} else {
|
||||||
// tooltip not visible yet, but maybe a timeout is still pending
|
// tooltip not visible yet, but maybe a timeout is still pending
|
||||||
@@ -302,6 +320,7 @@ void tooltip_hide(void *arg)
|
|||||||
XUnmapWindow(server.display, g_tooltip.window);
|
XUnmapWindow(server.display, g_tooltip.window);
|
||||||
XFlush(server.display);
|
XFlush(server.display);
|
||||||
}
|
}
|
||||||
|
g_tooltip.area = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void start_show_timeout()
|
void start_show_timeout()
|
||||||
@@ -319,12 +338,25 @@ void stop_tooltip_timeout()
|
|||||||
stop_timeout(g_tooltip.timeout);
|
stop_timeout(g_tooltip.timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tooltip_copy_text(Area *area)
|
void tooltip_update_contents_timeout(void *arg)
|
||||||
{
|
{
|
||||||
free(g_tooltip.tooltip_text);
|
tooltip_update_contents_for(g_tooltip.area);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tooltip_update_contents_for(Area *area)
|
||||||
|
{
|
||||||
|
free_and_null(g_tooltip.tooltip_text);
|
||||||
|
if (g_tooltip.image)
|
||||||
|
cairo_surface_destroy(g_tooltip.image);
|
||||||
|
g_tooltip.image = NULL;
|
||||||
if (area && area->_get_tooltip_text)
|
if (area && area->_get_tooltip_text)
|
||||||
g_tooltip.tooltip_text = area->_get_tooltip_text(area);
|
g_tooltip.tooltip_text = area->_get_tooltip_text(area);
|
||||||
|
if (area && area->_get_tooltip_image) {
|
||||||
|
g_tooltip.image = area->_get_tooltip_image(area);
|
||||||
|
if (g_tooltip.image)
|
||||||
|
cairo_surface_reference(g_tooltip.image);
|
||||||
else
|
else
|
||||||
g_tooltip.tooltip_text = NULL;
|
change_timeout(&g_tooltip.update_timeout, 300, 0, tooltip_update_contents_timeout, NULL);
|
||||||
|
}
|
||||||
g_tooltip.area = area;
|
g_tooltip.area = area;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ typedef struct {
|
|||||||
Color font_color;
|
Color font_color;
|
||||||
Background *bg;
|
Background *bg;
|
||||||
timeout *timeout;
|
timeout *timeout;
|
||||||
|
timeout *update_timeout;
|
||||||
|
cairo_surface_t *image;
|
||||||
} Tooltip;
|
} Tooltip;
|
||||||
|
|
||||||
extern Tooltip g_tooltip;
|
extern Tooltip g_tooltip;
|
||||||
@@ -53,7 +55,7 @@ void tooltip_show(void * /*arg*/);
|
|||||||
void tooltip_update();
|
void tooltip_update();
|
||||||
void tooltip_trigger_hide();
|
void tooltip_trigger_hide();
|
||||||
void tooltip_hide(void * /*arg*/);
|
void tooltip_hide(void * /*arg*/);
|
||||||
void tooltip_copy_text(Area *area);
|
void tooltip_update_contents_for(Area *area);
|
||||||
void tooltip_default_font_changed();
|
void tooltip_default_font_changed();
|
||||||
|
|
||||||
#endif // TOOLTIP_H
|
#endif // TOOLTIP_H
|
||||||
|
|||||||
238
src/util/addr2line.c
Normal file
238
src/util/addr2line.c
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
/* addr2line.c -- convert addresses to line number and function name
|
||||||
|
Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
|
||||||
|
2007, 2009 Free Software Foundation, Inc.
|
||||||
|
Contributed by Ulrich Lauther <Ulrich.Lauther@mchp.siemens.de>
|
||||||
|
|
||||||
|
This file is part of GNU Binutils.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3, or (at your option)
|
||||||
|
any later version.
|
||||||
|
|
||||||
|
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, 51 Franklin Street - Fifth Floor, Boston,
|
||||||
|
MA 02110-1301, USA. */
|
||||||
|
|
||||||
|
/* Derived from objdump.c and nm.c by Ulrich.Lauther@mchp.siemens.de */
|
||||||
|
|
||||||
|
#ifdef ENABLE_EXECINFO
|
||||||
|
|
||||||
|
#include <bfd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "addr2line.h"
|
||||||
|
#include "print.h"
|
||||||
|
|
||||||
|
static bfd_boolean unwind_inlines = 1; /* -i, unwind inlined functions. */
|
||||||
|
static bfd_boolean with_addresses = 0; /* -a, show addresses. */
|
||||||
|
static bfd_boolean with_functions = 1; /* -f, show function names. */
|
||||||
|
static bfd_boolean do_demangle = 1; /* -C, demangle names. */
|
||||||
|
static bfd_boolean base_names = 1; /* -s, strip directory names. */
|
||||||
|
|
||||||
|
typedef struct Lookup {
|
||||||
|
char *exe_file_name;
|
||||||
|
void *address;
|
||||||
|
char *result;
|
||||||
|
bfd *abfd;
|
||||||
|
asymbol **syms;
|
||||||
|
bfd_vma pc;
|
||||||
|
const char *filename;
|
||||||
|
const char *functionname;
|
||||||
|
unsigned int line;
|
||||||
|
unsigned int discriminator;
|
||||||
|
bfd_boolean found;
|
||||||
|
} Lookup;
|
||||||
|
|
||||||
|
static asymbol **slurp_symtab(bfd *);
|
||||||
|
static void find_address_in_section(bfd *, asection *, void *unused);
|
||||||
|
static void translate_address(Lookup *lookup);
|
||||||
|
|
||||||
|
static asymbol **slurp_symtab(bfd *abfd)
|
||||||
|
{
|
||||||
|
if ((bfd_get_file_flags(abfd) & HAS_SYMS) == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
long storage = bfd_get_symtab_upper_bound(abfd);
|
||||||
|
bfd_boolean dynamic = FALSE;
|
||||||
|
if (storage == 0) {
|
||||||
|
storage = bfd_get_dynamic_symtab_upper_bound(abfd);
|
||||||
|
dynamic = TRUE;
|
||||||
|
}
|
||||||
|
if (storage < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
asymbol **syms = (asymbol **)malloc(storage);
|
||||||
|
long symcount;
|
||||||
|
if (dynamic)
|
||||||
|
symcount = bfd_canonicalize_dynamic_symtab(abfd, syms);
|
||||||
|
else
|
||||||
|
symcount = bfd_canonicalize_symtab(abfd, syms);
|
||||||
|
if (symcount < 0)
|
||||||
|
return syms;
|
||||||
|
|
||||||
|
// If there are no symbols left after canonicalization and
|
||||||
|
// we have not tried the dynamic symbols then give them a go.
|
||||||
|
if (symcount == 0 && !dynamic && (storage = bfd_get_dynamic_symtab_upper_bound(abfd)) > 0) {
|
||||||
|
free(syms);
|
||||||
|
syms = (asymbol **)malloc(storage);
|
||||||
|
symcount = bfd_canonicalize_dynamic_symtab(abfd, syms);
|
||||||
|
}
|
||||||
|
return syms;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void find_address_in_section(bfd *abfd, asection *section, void *unused)
|
||||||
|
{
|
||||||
|
Lookup *lookup = (Lookup *)abfd->usrdata;
|
||||||
|
|
||||||
|
bfd_vma vma;
|
||||||
|
bfd_size_type size;
|
||||||
|
|
||||||
|
if (lookup->found)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((bfd_get_section_flags(abfd, section) & SEC_ALLOC) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
vma = bfd_get_section_vma(abfd, section);
|
||||||
|
if (lookup->pc < vma)
|
||||||
|
return;
|
||||||
|
|
||||||
|
size = bfd_get_section_size(section);
|
||||||
|
if (lookup->pc >= vma + size)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lookup->found = bfd_find_nearest_line_discriminator(abfd,
|
||||||
|
section,
|
||||||
|
lookup->syms,
|
||||||
|
lookup->pc - vma,
|
||||||
|
&lookup->filename,
|
||||||
|
&lookup->functionname,
|
||||||
|
&lookup->line,
|
||||||
|
&lookup->discriminator);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void translate_address(Lookup *lookup)
|
||||||
|
{
|
||||||
|
Buffer *buffer = NULL;
|
||||||
|
lookup->pc = (bfd_vma)lookup->address;
|
||||||
|
|
||||||
|
if (with_addresses) {
|
||||||
|
char tmp[256];
|
||||||
|
bfd_sprintf_vma(lookup->abfd, tmp, lookup->pc);
|
||||||
|
buffer = buffer_printf(buffer, "0x%s: ", tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
lookup->found = FALSE;
|
||||||
|
bfd_map_over_sections(lookup->abfd, find_address_in_section, NULL);
|
||||||
|
|
||||||
|
if (!lookup->found) {
|
||||||
|
if (with_functions)
|
||||||
|
buffer = buffer_printf(buffer, "?? ");
|
||||||
|
buffer = buffer_printf(buffer, "??:0");
|
||||||
|
} else {
|
||||||
|
while (1) {
|
||||||
|
if (with_functions) {
|
||||||
|
const char *name;
|
||||||
|
char *alloc = NULL;
|
||||||
|
|
||||||
|
name = lookup->functionname;
|
||||||
|
if (name == NULL || *name == '\0')
|
||||||
|
name = "??";
|
||||||
|
else if (do_demangle) {
|
||||||
|
alloc = bfd_demangle(lookup->abfd, name, 3);
|
||||||
|
if (alloc != NULL)
|
||||||
|
name = alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = buffer_printf(buffer, "%s", name);
|
||||||
|
buffer = buffer_printf(buffer, " at ");
|
||||||
|
|
||||||
|
if (alloc != NULL)
|
||||||
|
free(alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (base_names && lookup->filename != NULL) {
|
||||||
|
const char *h = strrchr(lookup->filename, '/');
|
||||||
|
if (h != NULL)
|
||||||
|
lookup->filename = h + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = buffer_printf(buffer, "%s:", lookup->filename ? lookup->filename : "??");
|
||||||
|
if (lookup->line != 0) {
|
||||||
|
if (lookup->discriminator != 0)
|
||||||
|
buffer = buffer_printf(buffer, "%u (discriminator %u)", lookup->line, lookup->discriminator);
|
||||||
|
else
|
||||||
|
buffer = buffer_printf(buffer, "%u", lookup->line);
|
||||||
|
} else {
|
||||||
|
buffer = buffer_printf(buffer, "??");
|
||||||
|
}
|
||||||
|
if (!unwind_inlines)
|
||||||
|
lookup->found = FALSE;
|
||||||
|
else
|
||||||
|
lookup->found =
|
||||||
|
bfd_find_inliner_info(lookup->abfd, &lookup->filename, &lookup->functionname, &lookup->line);
|
||||||
|
if (!lookup->found)
|
||||||
|
break;
|
||||||
|
buffer = buffer_printf(buffer, " (inlined by) ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (buffer)
|
||||||
|
lookup->result = buffer->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
Lookup *addr2line_init(const char *file_name)
|
||||||
|
{
|
||||||
|
bfd *abfd = bfd_openr(file_name, NULL);
|
||||||
|
if (abfd == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// Decompress sections.
|
||||||
|
abfd->flags |= BFD_DECOMPRESS;
|
||||||
|
|
||||||
|
if (bfd_check_format(abfd, bfd_archive))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
char **matching = NULL;
|
||||||
|
if (!bfd_check_format_matches(abfd, bfd_object, &matching)) {
|
||||||
|
free(matching);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
Lookup *lookup = (Lookup *)calloc(1, sizeof(Lookup));
|
||||||
|
lookup->abfd = abfd;
|
||||||
|
lookup->abfd->usrdata = lookup;
|
||||||
|
lookup->syms = slurp_symtab(abfd);
|
||||||
|
lookup->exe_file_name = strdup(file_name);
|
||||||
|
return lookup;
|
||||||
|
|
||||||
|
err:
|
||||||
|
bfd_close(abfd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addr2line_destroy(Lookup *lookup)
|
||||||
|
{
|
||||||
|
free(lookup->syms);
|
||||||
|
bfd_close(lookup->abfd);
|
||||||
|
free(lookup->exe_file_name);
|
||||||
|
free(lookup);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *addr2line_lookup(Lookup *lookup, void *address)
|
||||||
|
{
|
||||||
|
lookup->address = address;
|
||||||
|
lookup->result = NULL;
|
||||||
|
translate_address(lookup);
|
||||||
|
return lookup->result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
14
src/util/addr2line.h
Normal file
14
src/util/addr2line.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#ifndef ADDR2LINE
|
||||||
|
#define ADDR2LINE
|
||||||
|
|
||||||
|
#ifdef ENABLE_EXECINFO
|
||||||
|
|
||||||
|
typedef struct Lookup Lookup;
|
||||||
|
|
||||||
|
Lookup *addr2line_init(const char *file_name);
|
||||||
|
void addr2line_destroy(Lookup *lookup);
|
||||||
|
char *addr2line_lookup(Lookup *lookup, void *address);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -490,28 +490,59 @@ void draw(Area *a)
|
|||||||
cairo_surface_destroy(cs);
|
cairo_surface_destroy(cs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double tint_color_channel(double a, double b, double tint_weight)
|
||||||
|
{
|
||||||
|
double gamma = 2.2;
|
||||||
|
if (tint_weight == 0.0)
|
||||||
|
return a;
|
||||||
|
double result = sqrt((1.-tint_weight)*pow(a, gamma) + tint_weight * pow(b, gamma));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_cairo_source_tinted(cairo_t *c, Color *color1, Color *color2, double tint_weight)
|
||||||
|
{
|
||||||
|
cairo_set_source_rgba(c,
|
||||||
|
tint_color_channel(color1->rgb[0], color2->rgb[0], tint_weight),
|
||||||
|
tint_color_channel(color1->rgb[1], color2->rgb[1], tint_weight),
|
||||||
|
tint_color_channel(color1->rgb[2], color2->rgb[2], tint_weight),
|
||||||
|
color1->alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_cairo_source_bg_color(Area *a, cairo_t *c)
|
||||||
|
{
|
||||||
|
Color content_color;
|
||||||
|
if (a->_get_content_color)
|
||||||
|
a->_get_content_color(a, &content_color);
|
||||||
|
else
|
||||||
|
bzero(&content_color, sizeof(content_color));
|
||||||
|
if (a->mouse_state == MOUSE_OVER)
|
||||||
|
set_cairo_source_tinted(c, &a->bg->fill_color_hover, &content_color, a->bg->fill_content_tint_weight);
|
||||||
|
else if (a->mouse_state == MOUSE_DOWN)
|
||||||
|
set_cairo_source_tinted(c, &a->bg->fill_color_pressed, &content_color, a->bg->fill_content_tint_weight);
|
||||||
|
else
|
||||||
|
set_cairo_source_tinted(c, &a->bg->fill_color, &content_color, a->bg->fill_content_tint_weight);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_cairo_source_border_color(Area *a, cairo_t *c)
|
||||||
|
{
|
||||||
|
Color content_color;
|
||||||
|
if (a->_get_content_color)
|
||||||
|
a->_get_content_color(a, &content_color);
|
||||||
|
else
|
||||||
|
bzero(&content_color, sizeof(content_color));
|
||||||
|
if (a->mouse_state == MOUSE_OVER)
|
||||||
|
set_cairo_source_tinted(c, &a->bg->border_color_hover, &content_color, a->bg->border_content_tint_weight);
|
||||||
|
else if (a->mouse_state == MOUSE_DOWN)
|
||||||
|
set_cairo_source_tinted(c, &a->bg->border_color_pressed, &content_color, a->bg->border_content_tint_weight);
|
||||||
|
else
|
||||||
|
set_cairo_source_tinted(c, &a->bg->border.color, &content_color, a->bg->border_content_tint_weight);
|
||||||
|
}
|
||||||
|
|
||||||
void draw_background(Area *a, cairo_t *c)
|
void draw_background(Area *a, cairo_t *c)
|
||||||
{
|
{
|
||||||
if ((a->bg->fill_color.alpha > 0.0) ||
|
if ((a->bg->fill_color.alpha > 0.0) ||
|
||||||
(panel_config.mouse_effects && (a->has_mouse_over_effect || a->has_mouse_press_effect))) {
|
(panel_config.mouse_effects && (a->has_mouse_over_effect || a->has_mouse_press_effect))) {
|
||||||
if (a->mouse_state == MOUSE_OVER)
|
|
||||||
cairo_set_source_rgba(c,
|
|
||||||
a->bg->fill_color_hover.rgb[0],
|
|
||||||
a->bg->fill_color_hover.rgb[1],
|
|
||||||
a->bg->fill_color_hover.rgb[2],
|
|
||||||
a->bg->fill_color_hover.alpha);
|
|
||||||
else if (a->mouse_state == MOUSE_DOWN)
|
|
||||||
cairo_set_source_rgba(c,
|
|
||||||
a->bg->fill_color_pressed.rgb[0],
|
|
||||||
a->bg->fill_color_pressed.rgb[1],
|
|
||||||
a->bg->fill_color_pressed.rgb[2],
|
|
||||||
a->bg->fill_color_pressed.alpha);
|
|
||||||
else
|
|
||||||
cairo_set_source_rgba(c,
|
|
||||||
a->bg->fill_color.rgb[0],
|
|
||||||
a->bg->fill_color.rgb[1],
|
|
||||||
a->bg->fill_color.rgb[2],
|
|
||||||
a->bg->fill_color.alpha);
|
|
||||||
// Not sure about this
|
// Not sure about this
|
||||||
draw_rect(c,
|
draw_rect(c,
|
||||||
left_border_width(a),
|
left_border_width(a),
|
||||||
@@ -519,7 +550,7 @@ void draw_background(Area *a, cairo_t *c)
|
|||||||
a->width - left_right_border_width(a),
|
a->width - left_right_border_width(a),
|
||||||
a->height - top_bottom_border_width(a),
|
a->height - top_bottom_border_width(a),
|
||||||
a->bg->border.radius - a->bg->border.width / 1.571);
|
a->bg->border.radius - a->bg->border.width / 1.571);
|
||||||
|
set_cairo_source_bg_color(a, c);
|
||||||
cairo_fill(c);
|
cairo_fill(c);
|
||||||
}
|
}
|
||||||
for (GList *l = a->gradient_instances_by_state[a->mouse_state]; l; l = l->next) {
|
for (GList *l = a->gradient_instances_by_state[a->mouse_state]; l; l = l->next) {
|
||||||
@@ -540,24 +571,7 @@ void draw_background(Area *a, cairo_t *c)
|
|||||||
cairo_set_line_width(c, a->bg->border.width);
|
cairo_set_line_width(c, a->bg->border.width);
|
||||||
|
|
||||||
// draw border inside (x, y, width, height)
|
// draw border inside (x, y, width, height)
|
||||||
if (a->mouse_state == MOUSE_OVER)
|
set_cairo_source_border_color(a, c);
|
||||||
cairo_set_source_rgba(c,
|
|
||||||
a->bg->border_color_hover.rgb[0],
|
|
||||||
a->bg->border_color_hover.rgb[1],
|
|
||||||
a->bg->border_color_hover.rgb[2],
|
|
||||||
a->bg->border_color_hover.alpha);
|
|
||||||
else if (a->mouse_state == MOUSE_DOWN)
|
|
||||||
cairo_set_source_rgba(c,
|
|
||||||
a->bg->border_color_pressed.rgb[0],
|
|
||||||
a->bg->border_color_pressed.rgb[1],
|
|
||||||
a->bg->border_color_pressed.rgb[2],
|
|
||||||
a->bg->border_color_pressed.alpha);
|
|
||||||
else
|
|
||||||
cairo_set_source_rgba(c,
|
|
||||||
a->bg->border.color.rgb[0],
|
|
||||||
a->bg->border.color.rgb[1],
|
|
||||||
a->bg->border.color.rgb[2],
|
|
||||||
a->bg->border.color.alpha);
|
|
||||||
draw_rect_on_sides(c,
|
draw_rect_on_sides(c,
|
||||||
left_border_width(a) / 2.,
|
left_border_width(a) / 2.,
|
||||||
top_border_width(a) / 2.,
|
top_border_width(a) / 2.,
|
||||||
|
|||||||
@@ -154,6 +154,8 @@ typedef struct Background {
|
|||||||
Color border_color_pressed;
|
Color border_color_pressed;
|
||||||
// Pointer to a GradientClass or NULL, no ownership
|
// Pointer to a GradientClass or NULL, no ownership
|
||||||
GradientClass *gradients[MOUSE_STATE_COUNT];
|
GradientClass *gradients[MOUSE_STATE_COUNT];
|
||||||
|
double fill_content_tint_weight;
|
||||||
|
double border_content_tint_weight;
|
||||||
} Background;
|
} Background;
|
||||||
|
|
||||||
typedef enum Layout {
|
typedef enum Layout {
|
||||||
@@ -233,6 +235,7 @@ typedef struct Area {
|
|||||||
// Returns a copy of the tooltip to be displayed for this widget.
|
// Returns a copy of the tooltip to be displayed for this widget.
|
||||||
// The caller takes ownership of the pointer.
|
// The caller takes ownership of the pointer.
|
||||||
char *(*_get_tooltip_text)(void *obj);
|
char *(*_get_tooltip_text)(void *obj);
|
||||||
|
cairo_surface_t *(*_get_tooltip_image)(void *obj);
|
||||||
|
|
||||||
// Returns true if the Area handles a mouse event at the given x, y coordinates relative to the window.
|
// Returns true if the Area handles a mouse event at the given x, y coordinates relative to the window.
|
||||||
// Leave this to NULL to use a default implementation.
|
// Leave this to NULL to use a default implementation.
|
||||||
@@ -240,6 +243,8 @@ typedef struct Area {
|
|||||||
|
|
||||||
// Prints the geometry of the object on stderr, with left indentation of indent spaces.
|
// Prints the geometry of the object on stderr, with left indentation of indent spaces.
|
||||||
void (*_dump_geometry)(void *obj, int indent);
|
void (*_dump_geometry)(void *obj, int indent);
|
||||||
|
|
||||||
|
void (*_get_content_color)(void *obj, Color *color);
|
||||||
} Area;
|
} Area;
|
||||||
|
|
||||||
// Initializes the Background member to default values.
|
// Initializes the Background member to default values.
|
||||||
|
|||||||
@@ -59,6 +59,7 @@
|
|||||||
|
|
||||||
#include "../panel.h"
|
#include "../panel.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
|
#include "signals.h"
|
||||||
|
|
||||||
void write_string(int fd, const char *s)
|
void write_string(int fd, const char *s)
|
||||||
{
|
{
|
||||||
@@ -398,6 +399,7 @@ pid_t tint_exec(const char *command,
|
|||||||
if (dir)
|
if (dir)
|
||||||
chdir(dir);
|
chdir(dir);
|
||||||
close_all_fds();
|
close_all_fds();
|
||||||
|
reset_signals();
|
||||||
if (terminal) {
|
if (terminal) {
|
||||||
#if !defined(__OpenBSD__)
|
#if !defined(__OpenBSD__)
|
||||||
fprintf(stderr, "tint2: executing in x-terminal-emulator: %s\n", command);
|
fprintf(stderr, "tint2: executing in x-terminal-emulator: %s\n", command);
|
||||||
@@ -409,7 +411,9 @@ pid_t tint_exec(const char *command,
|
|||||||
execvp("x-terminal-emulator", words.we_wordv);
|
execvp("x-terminal-emulator", words.we_wordv);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
fprintf(stderr, "tint2: could not execute command in x-terminal-emulator: %s, executting in shell\n", command);
|
fprintf(stderr,
|
||||||
|
"tint2: could not execute command in x-terminal-emulator: %s, executting in shell\n",
|
||||||
|
command);
|
||||||
}
|
}
|
||||||
execlp("sh", "sh", "-c", command, NULL);
|
execlp("sh", "sh", "-c", command, NULL);
|
||||||
fprintf(stderr, "tint2: Failed to execute %s\n", command);
|
fprintf(stderr, "tint2: Failed to execute %s\n", command);
|
||||||
@@ -806,7 +810,7 @@ Imlib_Image load_image(const char *path, int cached)
|
|||||||
GdkPixbuf *pixbuf = rsvg_handle_get_pixbuf(svg);
|
GdkPixbuf *pixbuf = rsvg_handle_get_pixbuf(svg);
|
||||||
gdk_pixbuf_save(pixbuf, tmp_filename, "png", NULL, NULL);
|
gdk_pixbuf_save(pixbuf, tmp_filename, "png", NULL, NULL);
|
||||||
}
|
}
|
||||||
exit(0);
|
_exit(0);
|
||||||
} else {
|
} else {
|
||||||
// Parent
|
// Parent
|
||||||
close(fd);
|
close(fd);
|
||||||
@@ -933,10 +937,9 @@ void get_text_size2(const PangoFontDescription *font,
|
|||||||
|
|
||||||
available_width = MAX(0, available_width);
|
available_width = MAX(0, available_width);
|
||||||
available_height = MAX(0, available_height);
|
available_height = MAX(0, available_height);
|
||||||
Pixmap pmap = XCreatePixmap(server.display, server.root_win, available_height, available_width, server.depth);
|
|
||||||
|
|
||||||
cairo_surface_t *cs =
|
cairo_surface_t *cs =
|
||||||
cairo_xlib_surface_create(server.display, pmap, server.visual, available_height, available_width);
|
cairo_image_surface_create(CAIRO_FORMAT_ARGB32, available_height, available_width);
|
||||||
cairo_t *c = cairo_create(cs);
|
cairo_t *c = cairo_create(cs);
|
||||||
|
|
||||||
PangoLayout *layout = pango_cairo_create_layout(c);
|
PangoLayout *layout = pango_cairo_create_layout(c);
|
||||||
@@ -960,7 +963,6 @@ void get_text_size2(const PangoFontDescription *font,
|
|||||||
g_object_unref(layout);
|
g_object_unref(layout);
|
||||||
cairo_destroy(c);
|
cairo_destroy(c);
|
||||||
cairo_surface_destroy(cs);
|
cairo_surface_destroy(cs);
|
||||||
XFreePixmap(server.display, pmap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !GLIB_CHECK_VERSION(2, 34, 0)
|
#if !GLIB_CHECK_VERSION(2, 34, 0)
|
||||||
@@ -1055,3 +1057,57 @@ GString *tint2_g_string_replace(GString *s, const char *from, const char *to)
|
|||||||
g_string_free(result, TRUE);
|
g_string_free(result, TRUE);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void get_image_mean_color(const Imlib_Image image, Color *mean_color)
|
||||||
|
{
|
||||||
|
bzero(mean_color, sizeof(*mean_color));
|
||||||
|
|
||||||
|
if (!image)
|
||||||
|
return;
|
||||||
|
imlib_context_set_image(image);
|
||||||
|
imlib_image_set_has_alpha(1);
|
||||||
|
size_t size = (size_t)imlib_image_get_width() * (size_t)imlib_image_get_height();
|
||||||
|
DATA32 *data = imlib_image_get_data_for_reading_only();
|
||||||
|
DATA32 sum_r, sum_g, sum_b, count;
|
||||||
|
sum_r = sum_g = sum_b = count = 0;
|
||||||
|
for (size_t i = 0; i < size; i++) {
|
||||||
|
DATA32 argb, a, r, g, b;
|
||||||
|
argb = data[i];
|
||||||
|
a = (argb >> 24) & 0xff;
|
||||||
|
r = (argb >> 16) & 0xff;
|
||||||
|
g = (argb >> 8) & 0xff;
|
||||||
|
b = (argb) & 0xff;
|
||||||
|
if (a) {
|
||||||
|
sum_r += r;
|
||||||
|
sum_g += g;
|
||||||
|
sum_b += b;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!count)
|
||||||
|
count = 1;
|
||||||
|
mean_color->alpha = 1.0;
|
||||||
|
mean_color->rgb[0] = sum_r / 255.0 / count;
|
||||||
|
mean_color->rgb[1] = sum_g / 255.0 / count;
|
||||||
|
mean_color->rgb[2] = sum_b / 255.0 / count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void adjust_color(Color *color, int alpha, int saturation, int brightness)
|
||||||
|
{
|
||||||
|
if (alpha == 100 && saturation == 0 && brightness == 0)
|
||||||
|
return;
|
||||||
|
DATA32 argb = (((DATA32)(color->alpha * 255) & 0xff) << 24) |
|
||||||
|
(((DATA32)(color->rgb[0] * 255) & 0xff) << 16) |
|
||||||
|
(((DATA32)(color->rgb[1] * 255) & 0xff) << 8) |
|
||||||
|
(((DATA32)(color->rgb[2] * 255) & 0xff) << 0);
|
||||||
|
adjust_asb(&argb, 1, 1, alpha / 100.0, saturation / 100.0, brightness / 100.0);
|
||||||
|
DATA32 a = (argb >> 24) & 0xff;
|
||||||
|
DATA32 r = (argb >> 16) & 0xff;
|
||||||
|
DATA32 g = (argb >> 8) & 0xff;
|
||||||
|
DATA32 b = (argb) & 0xff;
|
||||||
|
color->alpha = a / 255.;
|
||||||
|
color->rgb[0] = r / 255.;
|
||||||
|
color->rgb[1] = g / 255.;
|
||||||
|
color->rgb[2] = b / 255.;
|
||||||
|
}
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ Imlib_Image load_image(const char *path, int cached);
|
|||||||
// * 1 = white
|
// * 1 = white
|
||||||
void adjust_asb(DATA32 *data, int w, int h, float alpha_adjust, float satur_adjust, float bright_adjust);
|
void adjust_asb(DATA32 *data, int w, int h, float alpha_adjust, float satur_adjust, float bright_adjust);
|
||||||
Imlib_Image adjust_icon(Imlib_Image original, int alpha, int saturation, int brightness);
|
Imlib_Image adjust_icon(Imlib_Image original, int alpha, int saturation, int brightness);
|
||||||
|
void adjust_color(Color *color, int alpha, int saturation, int brightness);
|
||||||
|
|
||||||
void create_heuristic_mask(DATA32 *data, int w, int h);
|
void create_heuristic_mask(DATA32 *data, int w, int h);
|
||||||
|
|
||||||
@@ -150,6 +151,8 @@ gint cmp_ptr(gconstpointer a, gconstpointer b);
|
|||||||
|
|
||||||
GString *tint2_g_string_replace(GString *s, const char *from, const char *to);
|
GString *tint2_g_string_replace(GString *s, const char *from, const char *to);
|
||||||
|
|
||||||
|
void get_image_mean_color(const Imlib_Image image, Color *mean_color);
|
||||||
|
|
||||||
#define free_and_null(p) \
|
#define free_and_null(p) \
|
||||||
{ \
|
{ \
|
||||||
free(p); \
|
free(p); \
|
||||||
|
|||||||
471
src/util/mem.c
Normal file
471
src/util/mem.c
Normal file
@@ -0,0 +1,471 @@
|
|||||||
|
#ifdef ENABLE_EXECINFO
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <execinfo.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdc-predef.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
|
#include "addr2line.h"
|
||||||
|
#include "mem.h"
|
||||||
|
#include "print.h"
|
||||||
|
|
||||||
|
#ifndef RTLD_NEXT
|
||||||
|
# define RTLD_NEXT ((void *) -1l)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef thread_local
|
||||||
|
# if __STDC_VERSION__ >= 201112 && !defined __STDC_NO_THREADS__
|
||||||
|
# define thread_local _Thread_local
|
||||||
|
# elif defined _WIN32 && ( \
|
||||||
|
defined _MSC_VER || \
|
||||||
|
defined __ICL || \
|
||||||
|
defined __DMC__ || \
|
||||||
|
defined __BORLANDC__ )
|
||||||
|
# define thread_local __declspec(thread)
|
||||||
|
/* note that ICC (linux) and Clang are covered by __GNUC__ */
|
||||||
|
# elif defined __GNUC__ || \
|
||||||
|
defined __SUNPRO_C || \
|
||||||
|
defined __xlC__
|
||||||
|
# define thread_local __thread
|
||||||
|
# else
|
||||||
|
# error "Cannot define thread_local"
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define get_caller() __builtin_extract_return_addr(__builtin_return_address(0))
|
||||||
|
|
||||||
|
#define size_t_mul_overflow(a, b) (a > 0 && b > SIZE_MAX / a)
|
||||||
|
|
||||||
|
typedef struct ListItem {
|
||||||
|
struct ListItem *next;
|
||||||
|
struct ListItem *prev;
|
||||||
|
void *data;
|
||||||
|
} ListItem;
|
||||||
|
|
||||||
|
typedef struct List {
|
||||||
|
ListItem *head;
|
||||||
|
ListItem *tail;
|
||||||
|
} List;
|
||||||
|
|
||||||
|
void list_append(List *list, void *data)
|
||||||
|
{
|
||||||
|
ListItem *n = (ListItem*)calloc(1, sizeof(ListItem));
|
||||||
|
n->data = data;
|
||||||
|
if (!list->tail) {
|
||||||
|
list->head = list->tail = n;
|
||||||
|
} else {
|
||||||
|
list->tail->next = n;
|
||||||
|
n->prev = list->tail;
|
||||||
|
list->tail = list->tail->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef size_t (*HashFunc)(void *data);
|
||||||
|
typedef int (*EqualFunc)(void *data1, void *data2);
|
||||||
|
typedef void *(*CopyFunc)(void *data);
|
||||||
|
|
||||||
|
typedef struct HashTable {
|
||||||
|
List *buckets;
|
||||||
|
size_t num_buckets;
|
||||||
|
size_t (*hash_func)(void *data);
|
||||||
|
int (*equal_func)(void *data1, void *data2);
|
||||||
|
void *(*copy_func)(void *data);
|
||||||
|
} HashTable;
|
||||||
|
|
||||||
|
size_t hash_void(void *data)
|
||||||
|
{
|
||||||
|
return (size_t)data;
|
||||||
|
}
|
||||||
|
|
||||||
|
int equal_void(void *data1, void *data2)
|
||||||
|
{
|
||||||
|
return data1 == data2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *copy_void(void *data)
|
||||||
|
{
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hash_table_init(HashTable *table, size_t num_buckets, HashFunc hash_func, EqualFunc equal_func, CopyFunc copy_func)
|
||||||
|
{
|
||||||
|
if (table->buckets)
|
||||||
|
return;
|
||||||
|
if (num_buckets < 1)
|
||||||
|
num_buckets = 4096;
|
||||||
|
table->num_buckets = num_buckets;
|
||||||
|
table->buckets = (List*)calloc(table->num_buckets, sizeof(List));
|
||||||
|
table->hash_func = hash_func ? hash_func : hash_void;
|
||||||
|
table->equal_func = equal_func ? equal_func : equal_void;
|
||||||
|
table->copy_func = copy_func ? copy_func : copy_void;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *hash_table_add(HashTable *table, void *data)
|
||||||
|
{
|
||||||
|
size_t hash = table->hash_func(data);
|
||||||
|
size_t bucket = hash % table->num_buckets;
|
||||||
|
for (ListItem *existing = table->buckets[bucket].head; existing; existing = existing->next) {
|
||||||
|
if (table->equal_func(existing->data, data))
|
||||||
|
return existing->data;
|
||||||
|
}
|
||||||
|
list_append(&table->buckets[bucket], table->copy_func(data));
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX_TRACE_SIZE 120
|
||||||
|
|
||||||
|
typedef struct Trace {
|
||||||
|
void *entries[MAX_TRACE_SIZE+8];
|
||||||
|
size_t id;
|
||||||
|
} Trace;
|
||||||
|
|
||||||
|
#define LARGE_THRESH (10 * 1024 * 1024)
|
||||||
|
|
||||||
|
static void *(*calloc_original)(size_t count, size_t size) = NULL;
|
||||||
|
static void *(*realloc_original)(void *p, size_t size) = NULL;
|
||||||
|
static void *(*malloc_original)(size_t size) = NULL;
|
||||||
|
static void *(*free_original)(void *p) = NULL;
|
||||||
|
static gzFile mem_log = NULL;
|
||||||
|
static pid_t mem_log_owner = 0;
|
||||||
|
pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
static HashTable traces;
|
||||||
|
static size_t next_trace_id = 0;
|
||||||
|
pthread_mutex_t trace_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
static HashTable addr2lines;
|
||||||
|
pthread_mutex_t addr2lines_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
thread_local int paused = 0;
|
||||||
|
|
||||||
|
static double get_unix_time()
|
||||||
|
{
|
||||||
|
struct timeval tv;
|
||||||
|
if (gettimeofday(&tv, NULL) != 0)
|
||||||
|
return 0;
|
||||||
|
return tv.tv_sec + 1.0e-6 * tv.tv_usec;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__ ((noinline))
|
||||||
|
static void get_backtrace(Trace *trace) {
|
||||||
|
int size = backtrace(trace->entries, MAX_TRACE_SIZE);
|
||||||
|
trace->entries[size] = NULL;
|
||||||
|
for (void **p = trace->entries; *p; p++) {
|
||||||
|
*p = *(p+2);
|
||||||
|
}
|
||||||
|
trace->id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int trace_size(Trace *trace)
|
||||||
|
{
|
||||||
|
int size = 0;
|
||||||
|
for (void **p = trace->entries; *p; p++) {
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct FilenameLookup {
|
||||||
|
char *file_name;
|
||||||
|
Lookup *lookup;
|
||||||
|
} FilenameLookup;
|
||||||
|
|
||||||
|
size_t hash_lookup(void *data)
|
||||||
|
{
|
||||||
|
FilenameLookup *lookup = (FilenameLookup *)data;
|
||||||
|
size_t seed = 14695981039346656037ULL;
|
||||||
|
size_t hash = seed;
|
||||||
|
for (char *p = lookup->file_name; *p; p++) {
|
||||||
|
hash = (hash ^ (size_t)(*p)) * 1099511628211ULL;
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
int equal_lookup(void *data1, void *data2)
|
||||||
|
{
|
||||||
|
FilenameLookup *lookup1 = (FilenameLookup *)data1;
|
||||||
|
FilenameLookup *lookup2 = (FilenameLookup *)data2;
|
||||||
|
return strcmp(lookup1->file_name, lookup2->file_name) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *resolve_symbol(char *file_name, void *address)
|
||||||
|
{
|
||||||
|
FilenameLookup *lookup = (FilenameLookup *)calloc(1, sizeof(FilenameLookup));
|
||||||
|
lookup->file_name = strdup(file_name);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&addr2lines_mutex);
|
||||||
|
hash_table_init(&addr2lines, 0, hash_lookup, equal_lookup, NULL);
|
||||||
|
FilenameLookup *existing = (FilenameLookup *)hash_table_add(&addr2lines, lookup);
|
||||||
|
if (existing == lookup) {
|
||||||
|
lookup->lookup = addr2line_init(lookup->file_name);
|
||||||
|
} else {
|
||||||
|
free(lookup->file_name);
|
||||||
|
free(lookup);
|
||||||
|
}
|
||||||
|
char *result = addr2line_lookup(existing->lookup, address);
|
||||||
|
pthread_mutex_unlock(&addr2lines_mutex);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *backtrace_to_string(Trace *trace)
|
||||||
|
{
|
||||||
|
int size = trace_size(trace);
|
||||||
|
char **strings = backtrace_symbols(trace->entries, size);
|
||||||
|
if (!strings)
|
||||||
|
return NULL;
|
||||||
|
Buffer *buffer = NULL;
|
||||||
|
buffer = buffer_printf(buffer, "t %lu ", trace->id);
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
buffer = buffer_printf(buffer, "%s", strings[i]);
|
||||||
|
// /lib/x86_64-linux-gnu/libglib-2.0.so.0(g_realloc+0xf) [0x7efda85c96af]
|
||||||
|
char *func_start = strstr(strings[i], "(");
|
||||||
|
if (func_start) {
|
||||||
|
*func_start = 0;
|
||||||
|
char *file_name = strings[i];
|
||||||
|
char *resolved = resolve_symbol(file_name, trace->entries[i]);
|
||||||
|
if (resolved) {
|
||||||
|
buffer = buffer_printf(buffer, " %s", resolved);
|
||||||
|
free(resolved);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer = buffer_printf(buffer, "|");
|
||||||
|
}
|
||||||
|
free(strings);
|
||||||
|
buffer = buffer_printf(buffer, "\n");
|
||||||
|
return buffer->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t hash_trace(Trace *trace)
|
||||||
|
{
|
||||||
|
size_t seed = 14695981039346656037ULL;
|
||||||
|
size_t hash = seed;
|
||||||
|
for (void **p = trace->entries; *p; p++) {
|
||||||
|
hash = (hash ^ (size_t)(*p)) * 1099511628211ULL;
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int equal_traces(Trace *a, Trace *b)
|
||||||
|
{
|
||||||
|
void **pa, **pb;
|
||||||
|
for (pa = a->entries, pb = b->entries; *pa && *pb; pa++, pb++) {
|
||||||
|
if (*pa != *pb)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (*pa || *pb)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Trace *copy_trace(Trace *trace)
|
||||||
|
{
|
||||||
|
Trace *result = (Trace*)calloc(1, sizeof(Trace));
|
||||||
|
*result = *trace;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int trace_assign_id(Trace *trace)
|
||||||
|
{
|
||||||
|
int created = 0;
|
||||||
|
pthread_mutex_lock(&trace_mutex);
|
||||||
|
hash_table_init(&traces, 1024 * 1024, (HashFunc)hash_trace, (EqualFunc)equal_traces, (CopyFunc)copy_trace);
|
||||||
|
trace->id = 0;
|
||||||
|
Trace *existing = (Trace*)hash_table_add(&traces, trace);
|
||||||
|
if (!existing->id) {
|
||||||
|
next_trace_id++;
|
||||||
|
existing->id = trace->id = next_trace_id;
|
||||||
|
created = 1;
|
||||||
|
} else {
|
||||||
|
trace->id = existing->id;
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&trace_mutex);
|
||||||
|
return created;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void log_flush();
|
||||||
|
|
||||||
|
static void log_init()
|
||||||
|
{
|
||||||
|
char path[256];
|
||||||
|
sprintf(path, "/tmp/tint2.%lu.memtrace", (size_t)getpid());
|
||||||
|
pthread_mutex_lock(&log_mutex);
|
||||||
|
if (!mem_log) {
|
||||||
|
mem_log = gzopen(path, "w");
|
||||||
|
mem_log_owner = getpid();
|
||||||
|
atexit(log_flush);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&log_mutex);
|
||||||
|
if (mem_log)
|
||||||
|
fprintf(stderr, "Writing memory log to %s\n", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void log_write(char *buffer)
|
||||||
|
{
|
||||||
|
if (mem_log) {
|
||||||
|
pthread_mutex_lock(&log_mutex);
|
||||||
|
if (getpid() == mem_log_owner)
|
||||||
|
gzwrite(mem_log, buffer, (unsigned)strlen(buffer));
|
||||||
|
pthread_mutex_unlock(&log_mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void log_flush()
|
||||||
|
{
|
||||||
|
if (mem_log) {
|
||||||
|
pthread_mutex_lock(&log_mutex);
|
||||||
|
if (getpid() == mem_log_owner)
|
||||||
|
gzflush(mem_log, Z_SYNC_FLUSH);
|
||||||
|
pthread_mutex_unlock(&log_mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void malloc_profile_load_pointers()
|
||||||
|
{
|
||||||
|
realloc_original = dlsym(RTLD_NEXT, "realloc");
|
||||||
|
malloc_original = dlsym(RTLD_NEXT, "malloc");
|
||||||
|
calloc_original = dlsym(RTLD_NEXT, "calloc");
|
||||||
|
free_original = dlsym(RTLD_NEXT, "free");
|
||||||
|
int trace_mem = getenv("TRACE_MEM") != NULL;
|
||||||
|
if (trace_mem)
|
||||||
|
log_init();
|
||||||
|
else
|
||||||
|
paused = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *calloc(size_t count, size_t size)
|
||||||
|
{
|
||||||
|
if (paused)
|
||||||
|
return calloc_original ? calloc_original(count, size) : 0;
|
||||||
|
paused = 1;
|
||||||
|
if (!calloc_original) {
|
||||||
|
malloc_profile_load_pointers();
|
||||||
|
if (!calloc_original)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
void *result = calloc_original(count, size);
|
||||||
|
if (mem_log) {
|
||||||
|
Trace trace;
|
||||||
|
get_backtrace(&trace);
|
||||||
|
int created = trace_assign_id(&trace);
|
||||||
|
if (created) {
|
||||||
|
char *str = backtrace_to_string(&trace);
|
||||||
|
if (str) {
|
||||||
|
log_write(str);
|
||||||
|
free(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
char buffer[1024];
|
||||||
|
sprintf(buffer, "[%f] t %lu : %p = c %lu %lu\n", get_unix_time(), trace.id, result, count, size);
|
||||||
|
log_write(buffer);
|
||||||
|
if (size_t_mul_overflow(count, size) || (count * size) > LARGE_THRESH)
|
||||||
|
log_flush();
|
||||||
|
}
|
||||||
|
paused = 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *realloc(void *p, size_t size)
|
||||||
|
{
|
||||||
|
if (paused)
|
||||||
|
return realloc_original ? realloc_original(p, size) : 0;
|
||||||
|
paused = 1;
|
||||||
|
if (!realloc_original) {
|
||||||
|
malloc_profile_load_pointers();
|
||||||
|
if (!realloc_original)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
void *result = realloc_original(p, size);
|
||||||
|
if (mem_log) {
|
||||||
|
Trace trace;
|
||||||
|
get_backtrace(&trace);
|
||||||
|
int created = trace_assign_id(&trace);
|
||||||
|
if (created) {
|
||||||
|
char *str = backtrace_to_string(&trace);
|
||||||
|
if (str) {
|
||||||
|
log_write(str);
|
||||||
|
free(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
char buffer[1024];
|
||||||
|
sprintf(buffer, "[%f] t %lu : %p = r %p %lu\n", get_unix_time(), trace.id, result, p, size);
|
||||||
|
log_write(buffer);
|
||||||
|
if (size > LARGE_THRESH)
|
||||||
|
log_flush();
|
||||||
|
}
|
||||||
|
paused = 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *malloc(size_t size)
|
||||||
|
{
|
||||||
|
if (paused)
|
||||||
|
return malloc_original ? malloc_original(size) : 0;
|
||||||
|
paused = 1;
|
||||||
|
if (!malloc_original) {
|
||||||
|
malloc_profile_load_pointers();
|
||||||
|
if (!malloc_original)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
void *result = malloc_original(size);
|
||||||
|
if (mem_log) {
|
||||||
|
Trace trace;
|
||||||
|
get_backtrace(&trace);
|
||||||
|
int created = trace_assign_id(&trace);
|
||||||
|
if (created) {
|
||||||
|
char *str = backtrace_to_string(&trace);
|
||||||
|
if (str) {
|
||||||
|
log_write(str);
|
||||||
|
free(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
char buffer[1024];
|
||||||
|
sprintf(buffer, "[%f] t %lu : %p = m %lu\n", get_unix_time(), trace.id, result, size);
|
||||||
|
log_write(buffer);
|
||||||
|
if (size > LARGE_THRESH)
|
||||||
|
log_flush();
|
||||||
|
}
|
||||||
|
paused = 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(void *p)
|
||||||
|
{
|
||||||
|
if (paused) {
|
||||||
|
if (free_original)
|
||||||
|
free_original(p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
paused = 1;
|
||||||
|
if (!free_original) {
|
||||||
|
malloc_profile_load_pointers();
|
||||||
|
if (!free_original)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
free_original(p);
|
||||||
|
if (mem_log) {
|
||||||
|
Trace trace;
|
||||||
|
get_backtrace(&trace);
|
||||||
|
int created = trace_assign_id(&trace);
|
||||||
|
if (created) {
|
||||||
|
char *str = backtrace_to_string(&trace);
|
||||||
|
if (str) {
|
||||||
|
log_write(str);
|
||||||
|
free(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
char buffer[1024];
|
||||||
|
sprintf(buffer, "[%f] t %lu : 0 = f %p\n", get_unix_time(), trace.id, p);
|
||||||
|
log_write(buffer);
|
||||||
|
}
|
||||||
|
paused = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
4
src/util/mem.h
Normal file
4
src/util/mem.h
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
#ifndef MEM_H
|
||||||
|
#define MEM_H
|
||||||
|
|
||||||
|
#endif
|
||||||
40
src/util/print.c
Normal file
40
src/util/print.c
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "print.h"
|
||||||
|
|
||||||
|
Buffer *vbuffer_printf(Buffer *buffer, const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
va_list ap1;
|
||||||
|
va_copy(ap1, ap);
|
||||||
|
int ret = vsnprintf(NULL, 0, fmt, ap1) + 1;
|
||||||
|
va_end(ap1);
|
||||||
|
if (ret < 1)
|
||||||
|
return buffer;
|
||||||
|
|
||||||
|
size_t size = (size_t)ret;
|
||||||
|
if (!buffer)
|
||||||
|
buffer = (Buffer*)calloc(1, sizeof(Buffer));
|
||||||
|
if (!buffer->data) {
|
||||||
|
buffer->size = 2 * size + 128;
|
||||||
|
buffer->data = (char*) calloc(buffer->size, 1);
|
||||||
|
} else if (strlen(buffer->data) + size >= buffer->size + 1) {
|
||||||
|
buffer->size = 2 * (size + buffer->size) + 128;
|
||||||
|
buffer->data = (char*) realloc(buffer->data, buffer->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
vsnprintf(buffer->data + strlen(buffer->data), size, fmt, ap);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer *buffer_printf(Buffer *buffer, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
buffer = vbuffer_printf(buffer, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
16
src/util/print.h
Normal file
16
src/util/print.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#ifndef PRINT_H
|
||||||
|
#define PRINT_H
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
typedef struct Buffer {
|
||||||
|
char *data;
|
||||||
|
size_t size;
|
||||||
|
} Buffer;
|
||||||
|
|
||||||
|
Buffer *vbuffer_printf(Buffer *buffer, const char *fmt, va_list ap);
|
||||||
|
Buffer *buffer_printf(Buffer *buffer, const char *fmt, ...);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -45,6 +45,8 @@ struct _timeout {
|
|||||||
multi_timeout *multi_timeout;
|
multi_timeout *multi_timeout;
|
||||||
timeout **self;
|
timeout **self;
|
||||||
gboolean expired;
|
gboolean expired;
|
||||||
|
// timer has been restarted from its own callback function
|
||||||
|
gboolean reactivated;
|
||||||
};
|
};
|
||||||
|
|
||||||
void add_timeout_intern(int value_msec, int interval_msec, void (*_callback)(void *), void *arg, timeout *t);
|
void add_timeout_intern(int value_msec, int interval_msec, void (*_callback)(void *), void *arg, timeout *t);
|
||||||
@@ -158,10 +160,12 @@ void handle_expired_timers()
|
|||||||
if (compare_timespecs(&t->timeout_expires, &cur_time) <= 0) {
|
if (compare_timespecs(&t->timeout_expires, &cur_time) <= 0) {
|
||||||
// it's time for the callback function
|
// it's time for the callback function
|
||||||
t->expired = t->interval_msec == 0;
|
t->expired = t->interval_msec == 0;
|
||||||
|
t->reactivated = FALSE;
|
||||||
t->_callback(t->arg);
|
t->_callback(t->arg);
|
||||||
// If _callback() calls stop_timeout(t) the timer 't' was freed and is not in the timeout_list
|
// If _callback() calls stop_timeout(t) the timer 't' was freed and is not in the timeout_list
|
||||||
if (g_slist_find(timeout_list, t)) {
|
if (g_slist_find(timeout_list, t)) {
|
||||||
// Timer still exists
|
// Timer still exists
|
||||||
|
if (!t->reactivated) {
|
||||||
timeout_list = g_slist_remove(timeout_list, t);
|
timeout_list = g_slist_remove(timeout_list, t);
|
||||||
if (t->interval_msec > 0) {
|
if (t->interval_msec > 0) {
|
||||||
add_timeout_intern(t->interval_msec, t->interval_msec, t->_callback, t->arg, t);
|
add_timeout_intern(t->interval_msec, t->interval_msec, t->_callback, t->arg, t);
|
||||||
@@ -172,6 +176,7 @@ void handle_expired_timers()
|
|||||||
free(t);
|
free(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -208,6 +213,7 @@ void add_timeout_intern(int value_msec, int interval_msec, void (*_callback)(),
|
|||||||
can_align = align_with_existing_timeouts(t);
|
can_align = align_with_existing_timeouts(t);
|
||||||
if (!can_align)
|
if (!can_align)
|
||||||
timeout_list = g_slist_insert_sorted(timeout_list, t, compare_timeouts);
|
timeout_list = g_slist_insert_sorted(timeout_list, t, compare_timeouts);
|
||||||
|
t->reactivated = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
gint compare_timeouts(gconstpointer t1, gconstpointer t2)
|
gint compare_timeouts(gconstpointer t1, gconstpointer t2)
|
||||||
@@ -384,6 +390,7 @@ void callback_multi_timeout(void *arg)
|
|||||||
gettime(&cur_time);
|
gettime(&cur_time);
|
||||||
GSList *it = mth->timeout_list;
|
GSList *it = mth->timeout_list;
|
||||||
while (it) {
|
while (it) {
|
||||||
|
GSList *next = it->next;
|
||||||
timeout *t = it->data;
|
timeout *t = it->data;
|
||||||
if (++t->multi_timeout->current_count >= t->multi_timeout->count_to_expiration) {
|
if (++t->multi_timeout->current_count >= t->multi_timeout->count_to_expiration) {
|
||||||
t->_callback(t->arg);
|
t->_callback(t->arg);
|
||||||
@@ -395,7 +402,7 @@ void callback_multi_timeout(void *arg)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
it = it->next;
|
it = next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,11 +24,17 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <Imlib2.h>
|
#include <Imlib2.h>
|
||||||
#include <cairo.h>
|
#include <cairo.h>
|
||||||
#include <cairo-xlib.h>
|
#include <cairo-xlib.h>
|
||||||
|
|
||||||
|
#include <X11/extensions/XShm.h>
|
||||||
|
#include <sys/ipc.h>
|
||||||
|
#include <sys/shm.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
@@ -157,7 +163,8 @@ int get_window_desktop(Window win)
|
|||||||
|
|
||||||
if (best_match < 0)
|
if (best_match < 0)
|
||||||
best_match = 0;
|
best_match = 0;
|
||||||
// fprintf(stderr, "tint2: window %lx %s : viewport %d, (%d, %d)\n", win, get_task(win) ? get_task(win)->title : "??",
|
// fprintf(stderr, "tint2: window %lx %s : viewport %d, (%d, %d)\n", win, get_task(win) ? get_task(win)->title :
|
||||||
|
// "??",
|
||||||
// best_match+1, x, y);
|
// best_match+1, x, y);
|
||||||
return best_match;
|
return best_match;
|
||||||
}
|
}
|
||||||
@@ -190,15 +197,18 @@ int get_window_monitor(Window win)
|
|||||||
return best_match;
|
return best_match;
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_window_coordinates(Window win, int *x, int *y, int *w, int *h)
|
gboolean get_window_coordinates(Window win, int *x, int *y, int *w, int *h)
|
||||||
{
|
{
|
||||||
int dummy_int;
|
int dummy_int;
|
||||||
unsigned ww, wh, bw, bh;
|
unsigned ww, wh, bw, bh;
|
||||||
Window src;
|
Window src;
|
||||||
XTranslateCoordinates(server.display, win, server.root_win, 0, 0, x, y, &src);
|
if (!XTranslateCoordinates(server.display, win, server.root_win, 0, 0, x, y, &src))
|
||||||
XGetGeometry(server.display, win, &src, &dummy_int, &dummy_int, &ww, &wh, &bw, &bh);
|
return FALSE;
|
||||||
|
if (!XGetGeometry(server.display, win, &src, &dummy_int, &dummy_int, &ww, &wh, &bw, &bh))
|
||||||
|
return FALSE;
|
||||||
*w = ww + bw;
|
*w = ww + bw;
|
||||||
*h = wh + bh;
|
*h = wh + bw;
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean window_is_iconified(Window win)
|
gboolean window_is_iconified(Window win)
|
||||||
@@ -352,3 +362,251 @@ char *get_window_name(Window win)
|
|||||||
XFree(text_property.value);
|
XFree(text_property.value);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void smooth_thumbnail(cairo_surface_t *image_surface)
|
||||||
|
{
|
||||||
|
u_int32_t *data = (u_int32_t *)cairo_image_surface_get_data(image_surface);
|
||||||
|
const size_t tw = cairo_image_surface_get_width(image_surface);
|
||||||
|
const size_t th = cairo_image_surface_get_height(image_surface);
|
||||||
|
const size_t rmask = 0xff0000;
|
||||||
|
const size_t gmask = 0xff00;
|
||||||
|
const size_t bmask = 0xff;
|
||||||
|
for (size_t i = 0; i < tw * (th - 1) - 1; i++) {
|
||||||
|
u_int32_t c1 = data[i];
|
||||||
|
u_int32_t c2 = data[i + 1];
|
||||||
|
u_int32_t c3 = data[i + tw];
|
||||||
|
u_int32_t c4 = data[i + tw + 1];
|
||||||
|
u_int32_t b = (5 * (c1 & bmask) + 1 * (c2 & bmask) + 1 * (c3 & bmask) + 1 * (c4 & bmask)) / 8;
|
||||||
|
u_int32_t g = (5 * (c1 & gmask) + 1 * (c2 & gmask) + 1 * (c3 & gmask) + 1 * (c4 & gmask)) / 8;
|
||||||
|
u_int32_t r = (5 * (c1 & rmask) + 1 * (c2 & rmask) + 1 * (c3 & rmask) + 1 * (c4 & rmask)) / 8;
|
||||||
|
data[i] = (r & rmask) | (g & gmask) | (b & bmask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is measured to be slightly faster.
|
||||||
|
#define GetPixel(ximg, x, y) ((u_int32_t *)&(ximg->data[y * ximg->bytes_per_line]))[x]
|
||||||
|
//#define GetPixel XGetPixel
|
||||||
|
|
||||||
|
cairo_surface_t *get_window_thumbnail_ximage(Window win, size_t size, gboolean use_shm)
|
||||||
|
{
|
||||||
|
cairo_surface_t *result = NULL;
|
||||||
|
XWindowAttributes wa;
|
||||||
|
if (!XGetWindowAttributes(server.display, win, &wa) || wa.width <= 0 || wa.height <= 0 ||
|
||||||
|
wa.map_state != IsViewable)
|
||||||
|
goto err0;
|
||||||
|
|
||||||
|
if (window_is_iconified(win))
|
||||||
|
goto err0;
|
||||||
|
|
||||||
|
size_t w, h;
|
||||||
|
w = (size_t)wa.width;
|
||||||
|
h = (size_t)wa.height;
|
||||||
|
size_t tw, th, fw;
|
||||||
|
size_t ox, oy;
|
||||||
|
tw = size;
|
||||||
|
th = h * tw / w;
|
||||||
|
if (th > tw * 0.618) {
|
||||||
|
th = (size_t)(tw * 0.618);
|
||||||
|
fw = w * th / h;
|
||||||
|
ox = (tw - fw) / 2;
|
||||||
|
oy = 0;
|
||||||
|
} else {
|
||||||
|
fw = tw;
|
||||||
|
ox = oy = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
XShmSegmentInfo shminfo;
|
||||||
|
XImage *ximg;
|
||||||
|
if (use_shm)
|
||||||
|
ximg = XShmCreateImage(server.display,
|
||||||
|
wa.visual,
|
||||||
|
(unsigned)wa.depth,
|
||||||
|
ZPixmap,
|
||||||
|
NULL,
|
||||||
|
&shminfo,
|
||||||
|
(unsigned)w,
|
||||||
|
(unsigned)h);
|
||||||
|
else
|
||||||
|
ximg = XGetImage(server.display, win, 0, 0, (unsigned)w, (unsigned)h, AllPlanes, ZPixmap);
|
||||||
|
if (!ximg) {
|
||||||
|
fprintf(stderr, RED "tint2: !ximg" RESET "\n");
|
||||||
|
goto err0;
|
||||||
|
}
|
||||||
|
if (ximg->bits_per_pixel != 24 && ximg->bits_per_pixel != 32) {
|
||||||
|
fprintf(stderr, RED "tint2: unusual bits_per_pixel" RESET "\n");
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
|
if (use_shm) {
|
||||||
|
shminfo.shmid = shmget(IPC_PRIVATE, (size_t)(ximg->bytes_per_line * ximg->height), IPC_CREAT | 0777);
|
||||||
|
if (shminfo.shmid < 0) {
|
||||||
|
fprintf(stderr, RED "tint2: !shmget" RESET "\n");
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
|
shminfo.shmaddr = ximg->data = (char *)shmat(shminfo.shmid, 0, 0);
|
||||||
|
if (!shminfo.shmaddr) {
|
||||||
|
fprintf(stderr, RED "tint2: !shmat" RESET "\n");
|
||||||
|
goto err2;
|
||||||
|
}
|
||||||
|
shminfo.readOnly = False;
|
||||||
|
if (!XShmAttach(server.display, &shminfo)) {
|
||||||
|
fprintf(stderr, RED "tint2: !xshmattach" RESET "\n");
|
||||||
|
goto err3;
|
||||||
|
}
|
||||||
|
if (!XShmGetImage(server.display, win, ximg, 0, 0, AllPlanes)) {
|
||||||
|
fprintf(stderr, RED "tint2: !xshmgetimage" RESET "\n");
|
||||||
|
goto err4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XGetWindowAttributes(server.display, win, &wa);
|
||||||
|
if (wa.map_state != IsViewable)
|
||||||
|
goto err4;
|
||||||
|
|
||||||
|
result = cairo_image_surface_create(CAIRO_FORMAT_RGB24, (int)tw, (int)th);
|
||||||
|
u_int32_t *data = (u_int32_t *)cairo_image_surface_get_data(result);
|
||||||
|
memset(data, 0, tw * th);
|
||||||
|
|
||||||
|
// Fixed-point precision
|
||||||
|
const size_t prec = 1 << 16;
|
||||||
|
const size_t xstep = w * prec / fw;
|
||||||
|
const size_t ystep = h * prec / th;
|
||||||
|
|
||||||
|
const size_t offset_y1 = 0 * ystep / 8;
|
||||||
|
const size_t offset_x1 = 3 * xstep / 8;
|
||||||
|
|
||||||
|
const size_t offset_y2 = 1 * ystep / 8;
|
||||||
|
const size_t offset_x2 = 6 * xstep / 8;
|
||||||
|
|
||||||
|
const size_t offset_y3 = 4 * ystep / 8;
|
||||||
|
const size_t offset_x3 = 2 * xstep / 8;
|
||||||
|
|
||||||
|
const size_t offset_y4 = 4 * ystep / 8;
|
||||||
|
const size_t offset_x4 = 4 * xstep / 8;
|
||||||
|
|
||||||
|
const size_t offset_y5 = 4 * ystep / 8;
|
||||||
|
const size_t offset_x5 = 7 * xstep / 8;
|
||||||
|
|
||||||
|
const size_t offset_y6 = 6 * ystep / 8;
|
||||||
|
const size_t offset_x6 = 1 * xstep / 8;
|
||||||
|
|
||||||
|
const size_t offset_y7 = 7 * ystep / 8;
|
||||||
|
const size_t offset_x7 = 6 * xstep / 8;
|
||||||
|
|
||||||
|
const u_int32_t rmask = (u_int32_t)ximg->red_mask;
|
||||||
|
const u_int32_t gmask = (u_int32_t)ximg->green_mask;
|
||||||
|
const u_int32_t bmask = (u_int32_t)ximg->blue_mask;
|
||||||
|
for (size_t yt = 0, y = 0; yt < th; yt++, y += ystep) {
|
||||||
|
for (size_t xt = 0, x = 0; xt < fw; xt++, x += xstep) {
|
||||||
|
size_t j = yt * tw + ox + xt;
|
||||||
|
u_int32_t c1 = (u_int32_t)GetPixel(ximg, (int)((x + offset_x1) / prec), (int)((y + offset_y1) / prec));
|
||||||
|
u_int32_t c2 = (u_int32_t)GetPixel(ximg, (int)((x + offset_x2) / prec), (int)((y + offset_y2) / prec));
|
||||||
|
u_int32_t c3 = (u_int32_t)GetPixel(ximg, (int)((x + offset_x3) / prec), (int)((y + offset_y3) / prec));
|
||||||
|
u_int32_t c4 = (u_int32_t)GetPixel(ximg, (int)((x + offset_x4) / prec), (int)((y + offset_y4) / prec));
|
||||||
|
u_int32_t c5 = (u_int32_t)GetPixel(ximg, (int)((x + offset_x5) / prec), (int)((y + offset_y5) / prec));
|
||||||
|
u_int32_t c6 = (u_int32_t)GetPixel(ximg, (int)((x + offset_x6) / prec), (int)((y + offset_y6) / prec));
|
||||||
|
u_int32_t c7 = (u_int32_t)GetPixel(ximg, (int)((x + offset_x7) / prec), (int)((y + offset_y7) / prec));
|
||||||
|
u_int32_t b = ((c1 & bmask) + (c2 & bmask) + (c3 & bmask) + (c4 & bmask) + (c5 & bmask) * 2 + (c6 & bmask) +
|
||||||
|
(c7 & bmask)) /
|
||||||
|
8;
|
||||||
|
u_int32_t g = ((c1 & gmask) + (c2 & gmask) + (c3 & gmask) + (c4 & gmask) + (c5 & gmask) * 2 + (c6 & gmask) +
|
||||||
|
(c7 & gmask)) /
|
||||||
|
8;
|
||||||
|
u_int32_t r = ((c1 & rmask) + (c2 & rmask) + (c3 & rmask) + (c4 & rmask) + (c5 & rmask) * 2 + (c6 & rmask) +
|
||||||
|
(c7 & rmask)) /
|
||||||
|
8;
|
||||||
|
data[j] = (r & rmask) | (g & gmask) | (b & bmask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Convert to argb32
|
||||||
|
if (rmask & 0xff0000) {
|
||||||
|
// argb32 or rgb24 => Nothing to do
|
||||||
|
} else if (rmask & 0xff) {
|
||||||
|
// bgr24
|
||||||
|
for (size_t i = 0; i < tw * th; i++) {
|
||||||
|
u_int32_t r = (data[i] & rmask) << 16;
|
||||||
|
u_int32_t g = (data[i] & gmask);
|
||||||
|
u_int32_t b = (data[i] & bmask) >> 16;
|
||||||
|
data[i] = (r & 0xff0000) | (g & 0x00ff00) | (b & 0x0000ff);
|
||||||
|
}
|
||||||
|
} else if (rmask & 0xff00) {
|
||||||
|
// bgra32
|
||||||
|
for (size_t i = 0; i < tw * th; i++) {
|
||||||
|
u_int32_t r = (data[i] & rmask) << 8;
|
||||||
|
u_int32_t g = (data[i] & gmask) >> 8;
|
||||||
|
u_int32_t b = (data[i] & bmask) >> 24;
|
||||||
|
data[i] = (r & 0xff0000) | (g & 0x00ff00) | (b & 0x0000ff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2nd pass
|
||||||
|
smooth_thumbnail(result);
|
||||||
|
|
||||||
|
if (ximg) {
|
||||||
|
XDestroyImage(ximg);
|
||||||
|
ximg = NULL;
|
||||||
|
}
|
||||||
|
err4:
|
||||||
|
if (use_shm)
|
||||||
|
XShmDetach(server.display, &shminfo);
|
||||||
|
err3:
|
||||||
|
if (use_shm)
|
||||||
|
shmdt(shminfo.shmaddr);
|
||||||
|
err2:
|
||||||
|
if (use_shm)
|
||||||
|
shmctl(shminfo.shmid, IPC_RMID, NULL);
|
||||||
|
err1:
|
||||||
|
if (ximg)
|
||||||
|
XDestroyImage(ximg);
|
||||||
|
err0:
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean cairo_surface_is_blank(cairo_surface_t *image_surface)
|
||||||
|
{
|
||||||
|
uint32_t *pixels = (uint32_t *)cairo_image_surface_get_data(image_surface);
|
||||||
|
gboolean empty = TRUE;
|
||||||
|
int size = cairo_image_surface_get_width(image_surface) * cairo_image_surface_get_height(image_surface);
|
||||||
|
for (int i = 0; empty && i < size; i++) {
|
||||||
|
if (pixels[i] & 0xffFFff)
|
||||||
|
empty = FALSE;
|
||||||
|
}
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
cairo_surface_t *get_window_thumbnail(Window win, int size)
|
||||||
|
{
|
||||||
|
cairo_surface_t *image_surface = NULL;
|
||||||
|
const gboolean shm_allowed = FALSE;
|
||||||
|
if (shm_allowed && server.has_shm && server.composite_manager) {
|
||||||
|
image_surface = get_window_thumbnail_ximage(win, (size_t)size, TRUE);
|
||||||
|
if (image_surface && cairo_surface_is_blank(image_surface)) {
|
||||||
|
cairo_surface_destroy(image_surface);
|
||||||
|
image_surface = NULL;
|
||||||
|
}
|
||||||
|
if (debug_thumbnails) {
|
||||||
|
if (!image_surface)
|
||||||
|
fprintf(stderr, YELLOW "tint2: XShmGetImage failed, trying slower method" RESET "\n");
|
||||||
|
else
|
||||||
|
fprintf(stderr, "tint2: captured window using XShmGetImage\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!image_surface) {
|
||||||
|
image_surface = get_window_thumbnail_ximage(win, (size_t)size, FALSE);
|
||||||
|
if (image_surface && cairo_surface_is_blank(image_surface)) {
|
||||||
|
cairo_surface_destroy(image_surface);
|
||||||
|
image_surface = NULL;
|
||||||
|
}
|
||||||
|
if (debug_thumbnails) {
|
||||||
|
if (!image_surface)
|
||||||
|
fprintf(stderr, YELLOW "tint2: XGetImage failed, trying slower method" RESET "\n");
|
||||||
|
else
|
||||||
|
fprintf(stderr, "tint2: captured window using XGetImage\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!image_surface)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return image_surface;
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ int get_window_monitor(Window win);
|
|||||||
|
|
||||||
void activate_window(Window win);
|
void activate_window(Window win);
|
||||||
void close_window(Window win);
|
void close_window(Window win);
|
||||||
void get_window_coordinates(Window win, int *x, int *y, int *w, int *h);
|
gboolean get_window_coordinates(Window win, int *x, int *y, int *w, int *h);
|
||||||
void toggle_window_maximized(Window win);
|
void toggle_window_maximized(Window win);
|
||||||
void toggle_window_shade(Window win);
|
void toggle_window_shade(Window win);
|
||||||
void change_window_desktop(Window win, int desktop);
|
void change_window_desktop(Window win, int desktop);
|
||||||
@@ -34,5 +34,6 @@ int get_icon_count(gulong *data, int num);
|
|||||||
gulong *get_best_icon(gulong *data, int icon_count, int num, int *iw, int *ih, int best_icon_size);
|
gulong *get_best_icon(gulong *data, int icon_count, int num, int *iw, int *ih, int best_icon_size);
|
||||||
|
|
||||||
char *get_window_name(Window win);
|
char *get_window_name(Window win);
|
||||||
|
cairo_surface_t *get_window_thumbnail(Window win, int size);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
107
test/fabfile.py
vendored
Executable file
107
test/fabfile.py
vendored
Executable file
@@ -0,0 +1,107 @@
|
|||||||
|
#!/usr/bin/env python2
|
||||||
|
|
||||||
|
# Setup: add tint2-runner, tint2-freebsd and tint2-openbsd in /etc/hosts.
|
||||||
|
# Run: pip install fabric; pip install fabtools.
|
||||||
|
|
||||||
|
# TODO: setup bsd workers
|
||||||
|
# TODO: prin ssh public key to be added on gitlab
|
||||||
|
|
||||||
|
from fabric.api import *
|
||||||
|
from fabric.contrib.files import *
|
||||||
|
from fabtools import require
|
||||||
|
import fabtools
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
env.use_ssh_config = True
|
||||||
|
env.user = 'root'
|
||||||
|
env.sudo_prefix += '-H '
|
||||||
|
env.roledefs = {
|
||||||
|
'runner': ['tint2-runner'],
|
||||||
|
'freebsd': ['tint2-freebsd'],
|
||||||
|
'openbsd': ['tint2-openbsd'],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def str2hex(s):
|
||||||
|
return ''.join('{:02x}'.format(ord(c)) for c in s)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_random_password():
|
||||||
|
return str2hex(os.urandom(32))
|
||||||
|
|
||||||
|
|
||||||
|
def read_file(path):
|
||||||
|
with open(path) as f:
|
||||||
|
return f.read()
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
@roles('runner', 'freebsd', 'openbsd')
|
||||||
|
def create_users():
|
||||||
|
require.user('root', password=generate_random_password())
|
||||||
|
require.user('runner', password=generate_random_password())
|
||||||
|
sudo('cd; mkdir -p .ssh; chmod 700 .ssh', user='runner')
|
||||||
|
if not exists('/home/runner/.ssh/id_rsa'):
|
||||||
|
sudo('cd; ssh-keygen -f ~/.ssh/id_rsa -t rsa -N ""', user='runner')
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
@roles('runner')
|
||||||
|
def install_deps():
|
||||||
|
require.deb.packages([
|
||||||
|
# Repo deps
|
||||||
|
'git',
|
||||||
|
# Build deps
|
||||||
|
'build-essential',
|
||||||
|
'cmake',
|
||||||
|
'libglib2.0-dev',
|
||||||
|
'libcairo2-dev',
|
||||||
|
'libglib2.0-dev',
|
||||||
|
'libgtk2.0-dev',
|
||||||
|
'libimlib2-dev',
|
||||||
|
'libpango1.0-dev',
|
||||||
|
'librsvg2-dev',
|
||||||
|
'libstartup-notification0-dev',
|
||||||
|
'libx11-dev',
|
||||||
|
'libxcomposite-dev',
|
||||||
|
'libxdamage-dev',
|
||||||
|
'libxinerama-dev',
|
||||||
|
'libxrandr-dev',
|
||||||
|
'libxrender-dev',
|
||||||
|
# Tester deps
|
||||||
|
'python-minimal',
|
||||||
|
'xvfb',
|
||||||
|
'xsettingsd',
|
||||||
|
'openbox',
|
||||||
|
'compton',
|
||||||
|
'x11-utils',
|
||||||
|
'gnome-calculator'
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
@roles('runner')
|
||||||
|
def pull_code():
|
||||||
|
if not exists('/home/runner/tint2'):
|
||||||
|
sudo('cd; git clone https://gitlab.com/o9000/tint2.git', user='runner')
|
||||||
|
if not exists('/home/runner/tint2.wiki'):
|
||||||
|
sudo('cd; git clone git@gitlab.com:o9000/tint2.wiki.git', user='runner')
|
||||||
|
sudo('cd; git config --global user.name "tint2.runner"', user='runner')
|
||||||
|
sudo('cd; git config --global user.email "tint2.runner@netperf.tools"', user='runner')
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
@roles('runner')
|
||||||
|
def add_cron_jobs():
|
||||||
|
fabtools.cron.add_task('tests', '* * * * *', 'runner', '/home/runner/tint2/test/update_test_status.sh')
|
||||||
|
fabtools.cron.add_task('packaging_check', '10 */2 * * *', 'runner', '/home/runner/tint2/packaging/update_version_status.sh')
|
||||||
|
|
||||||
|
|
||||||
|
@task(default=True)
|
||||||
|
@roles('runner')
|
||||||
|
def full_runner():
|
||||||
|
create_users()
|
||||||
|
install_deps()
|
||||||
|
pull_code()
|
||||||
|
add_cron_jobs()
|
||||||
165
test/memtrace-analyze.py
Executable file
165
test/memtrace-analyze.py
Executable file
@@ -0,0 +1,165 @@
|
|||||||
|
#!/usr/bin/env python2
|
||||||
|
|
||||||
|
import gzip
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def commas(v):
|
||||||
|
return "{:12,}".format(v)
|
||||||
|
|
||||||
|
|
||||||
|
class Event:
|
||||||
|
def __init__(self):
|
||||||
|
self.alloc = False
|
||||||
|
self.free = False
|
||||||
|
self.ts = None
|
||||||
|
self.size = None
|
||||||
|
self.addr = None
|
||||||
|
self.trace_name = None
|
||||||
|
|
||||||
|
|
||||||
|
class Analyzer:
|
||||||
|
def __init__(self):
|
||||||
|
self.traces = {}
|
||||||
|
self.events = []
|
||||||
|
self.all_allocations = {}
|
||||||
|
self.new_allocations = {}
|
||||||
|
self.all_mem = 0
|
||||||
|
self.old_mem = 0
|
||||||
|
|
||||||
|
def read(self, path):
|
||||||
|
with gzip.open(path, "rb") as f:
|
||||||
|
try:
|
||||||
|
for line in f:
|
||||||
|
line = line.strip()
|
||||||
|
if line.startswith("t"):
|
||||||
|
self.add_trace(line)
|
||||||
|
elif line.startswith("["):
|
||||||
|
self.add_call(line)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def add_trace(self, line):
|
||||||
|
t, name, content = line.split(" ", 2)
|
||||||
|
name = int(name)
|
||||||
|
assert(name > 0)
|
||||||
|
assert(name not in self.traces)
|
||||||
|
self.traces[name] = content.split("|")
|
||||||
|
|
||||||
|
def add_call(self, line):
|
||||||
|
first, second = line.split(":", 1)
|
||||||
|
first = first.strip()
|
||||||
|
ts, t, tname = first.split(" ")
|
||||||
|
ts = float(ts.replace("[", "").replace("]", ""))
|
||||||
|
assert(t == "t")
|
||||||
|
tname = int(tname)
|
||||||
|
assert(tname in self.traces)
|
||||||
|
second = second.strip()
|
||||||
|
result, eq, func, params = second.split(" ", 3)
|
||||||
|
assert(eq == "=")
|
||||||
|
params = params.split(" ")
|
||||||
|
e = Event()
|
||||||
|
e.ts = ts
|
||||||
|
e.trace_name = tname
|
||||||
|
if func == "m" and result != "(nil)":
|
||||||
|
e.alloc = True
|
||||||
|
e.addr = int(result, 16)
|
||||||
|
e.size = int(params[0])
|
||||||
|
elif func == "c" and result != "(nil)":
|
||||||
|
e.alloc = True
|
||||||
|
e.addr = int(result, 16)
|
||||||
|
e.size = int(params[0]) * int(params[1])
|
||||||
|
elif func == "r":
|
||||||
|
old_addr = params[0]
|
||||||
|
size = int(params[1])
|
||||||
|
if old_addr == "(nil)":
|
||||||
|
if result != "(nil)":
|
||||||
|
e.alloc = True
|
||||||
|
e.addr = int(result, 16)
|
||||||
|
e.size = size
|
||||||
|
elif old_addr != "(nil)":
|
||||||
|
if result != "(nil)":
|
||||||
|
e.free = True
|
||||||
|
e.addr = int(old_addr, 16)
|
||||||
|
self.events.append(e)
|
||||||
|
e = Event()
|
||||||
|
e.ts = ts
|
||||||
|
e.trace_name = tname
|
||||||
|
e.alloc = True
|
||||||
|
e.addr = int(result, 16)
|
||||||
|
e.size = size
|
||||||
|
elif func == "f":
|
||||||
|
addr = params[0]
|
||||||
|
if addr != "(nil)":
|
||||||
|
e.free = True
|
||||||
|
e.addr = int(addr, 16)
|
||||||
|
if e.alloc or e.free:
|
||||||
|
self.events.append(e)
|
||||||
|
|
||||||
|
|
||||||
|
def analyze(self):
|
||||||
|
self.all_allocations = {}
|
||||||
|
self.new_allocations = {}
|
||||||
|
self.all_mem = 0
|
||||||
|
self.old_mem = 0
|
||||||
|
self.peak_mem = 0
|
||||||
|
period = 1
|
||||||
|
next_ts_print = self.events[0].ts
|
||||||
|
for e in self.events:
|
||||||
|
if e.ts >= next_ts_print:
|
||||||
|
self.print_allocations()
|
||||||
|
next_ts_print += period
|
||||||
|
self.process_event(e)
|
||||||
|
self.print_allocations()
|
||||||
|
self.print_leaks()
|
||||||
|
|
||||||
|
|
||||||
|
def print_allocations(self):
|
||||||
|
print "Memory usage: current:", commas(self.all_mem), " | delta:", commas(self.all_mem - self.old_mem), " | peak:", commas(self.peak_mem)
|
||||||
|
self.old_mem = self.all_mem
|
||||||
|
self.new_alllocations = {}
|
||||||
|
|
||||||
|
|
||||||
|
def print_leaks(self):
|
||||||
|
if not self.all_allocations:
|
||||||
|
return
|
||||||
|
print "Memory leaked:", commas(self.all_mem)
|
||||||
|
leaks = [e for addr, e in self.all_allocations.iteritems()]
|
||||||
|
leaks.sort(key=lambda e: e.size)
|
||||||
|
for e in leaks:
|
||||||
|
print "Leak:", commas(e.size)
|
||||||
|
print "Allocated in:\n ", "\n ".join(self.traces[e.trace_name])
|
||||||
|
|
||||||
|
def process_event(self, e):
|
||||||
|
if e.alloc:
|
||||||
|
assert(e.addr not in self.all_allocations)
|
||||||
|
self.all_allocations[e.addr] = e
|
||||||
|
assert(e.addr not in self.new_allocations)
|
||||||
|
self.new_allocations[e.addr] = e
|
||||||
|
self.all_mem += e.size
|
||||||
|
self.peak_mem = max(self.peak_mem, self.all_mem)
|
||||||
|
else:
|
||||||
|
assert(e.addr in self.all_allocations)
|
||||||
|
e_alloc = self.all_allocations[e.addr]
|
||||||
|
if e.ts - e_alloc.ts > 1. and e_alloc.size > 1e3 and False:
|
||||||
|
print "Long-lived alloc:", commas(e_alloc.size), "freed after", commas(e.ts - e_alloc.ts) + "s"
|
||||||
|
print "Allocated in:\n ", "\n ".join(self.traces[e_alloc.trace_name])
|
||||||
|
print "Freed in:\n ", "\n ".join(self.traces[e.trace_name])
|
||||||
|
if e_alloc.addr in self.new_allocations:
|
||||||
|
if e_alloc.size > 1e7 and False:
|
||||||
|
print "Large alloc:", commas(e_alloc.size), "freed after", commas(e.ts - e_alloc.ts) + "s"
|
||||||
|
print "Allocated in:\n ", "\n ".join(self.traces[e_alloc.trace_name])
|
||||||
|
print "Freed in:\n ", "\n ".join(self.traces[e.trace_name])
|
||||||
|
del self.new_allocations[e_alloc.addr]
|
||||||
|
del self.all_allocations[e_alloc.addr]
|
||||||
|
self.all_mem -= e_alloc.size
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
a = Analyzer()
|
||||||
|
a.read(sys.argv[1])
|
||||||
|
a.analyze()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -160,7 +160,7 @@ def test(tint2path, config, use_asan):
|
|||||||
start_wm()
|
start_wm()
|
||||||
sleep(1)
|
sleep(1)
|
||||||
os.environ["DEBUG_FPS"] = "1"
|
os.environ["DEBUG_FPS"] = "1"
|
||||||
os.environ["ASAN_OPTIONS"] = "detect_leaks=1"
|
os.environ["ASAN_OPTIONS"] = "detect_leaks=1:exitcode=0"
|
||||||
tint2 = run([tint2path, "-c", config], True)
|
tint2 = run([tint2path, "-c", config], True)
|
||||||
if tint2.poll() != None:
|
if tint2.poll() != None:
|
||||||
raise RuntimeError("tint2 failed to start")
|
raise RuntimeError("tint2 failed to start")
|
||||||
@@ -214,7 +214,7 @@ def test(tint2path, config, use_asan):
|
|||||||
if use_asan:
|
if use_asan:
|
||||||
fps_status = ok
|
fps_status = ok
|
||||||
else:
|
else:
|
||||||
fps_status = ok if min_fps > 60 else warning if min_fps > 40 else error
|
fps_status = ok if min_fps > 30 else warning if min_fps > 20 else error
|
||||||
print("FPS:", "min:", min_fps, "median:", med_fps, fps_status)
|
print("FPS:", "min:", min_fps, "median:", med_fps, fps_status)
|
||||||
if mem_status != ok or leak_status != ok or fps_status != ok:
|
if mem_status != ok or leak_status != ok or fps_status != ok:
|
||||||
print("Output:")
|
print("Output:")
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
export PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
set -x
|
set -x
|
||||||
|
|
||||||
@@ -11,7 +13,9 @@ exec 2>&1
|
|||||||
cd ~/tint2
|
cd ~/tint2
|
||||||
git reset --hard
|
git reset --hard
|
||||||
git pull
|
git pull
|
||||||
|
last=$(cat .last-reg-test || true)
|
||||||
|
curr=$(git rev-parse --verify HEAD)
|
||||||
|
[ "$last" == "$curr" ] && exit 0
|
||||||
|
|
||||||
cd ~/tint2.wiki
|
cd ~/tint2.wiki
|
||||||
git reset --hard
|
git reset --hard
|
||||||
@@ -27,3 +31,6 @@ cd ~/tint2.wiki
|
|||||||
git add tests.md
|
git add tests.md
|
||||||
git commit -am 'Update test results'
|
git commit -am 'Update test results'
|
||||||
git push origin master
|
git push origin master
|
||||||
|
|
||||||
|
cd ~/tint2
|
||||||
|
echo "$curr" > .last-reg-test
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#---- Generated by tint2conf 20b6 ----
|
#---- Generated by tint2conf bb4a ----
|
||||||
# See https://gitlab.com/o9000/tint2/wikis/Configure for
|
# See https://gitlab.com/o9000/tint2/wikis/Configure for
|
||||||
# full documentation of the configuration options.
|
# full documentation of the configuration options.
|
||||||
#-------------------------------------
|
#-------------------------------------
|
||||||
@@ -15,6 +15,8 @@ color_stop = 70.000000 #1c1c1c 80
|
|||||||
rounded = 0
|
rounded = 0
|
||||||
border_width = 1
|
border_width = 1
|
||||||
border_sides = T
|
border_sides = T
|
||||||
|
border_content_tint_weight = 0
|
||||||
|
background_content_tint_weight = 0
|
||||||
background_color = #000000 80
|
background_color = #000000 80
|
||||||
border_color = #333333 80
|
border_color = #333333 80
|
||||||
gradient_id = 1
|
gradient_id = 1
|
||||||
@@ -27,28 +29,34 @@ border_color_pressed = #555555 80
|
|||||||
rounded = 0
|
rounded = 0
|
||||||
border_width = 2
|
border_width = 2
|
||||||
border_sides = B
|
border_sides = B
|
||||||
|
border_content_tint_weight = 100
|
||||||
|
background_content_tint_weight = 25
|
||||||
background_color = #777777 0
|
background_color = #777777 0
|
||||||
border_color = #777777 0
|
border_color = #777777 100
|
||||||
background_color_hover = #777777 21
|
background_color_hover = #464646 100
|
||||||
border_color_hover = #cccccc 30
|
border_color_hover = #cccccc 30
|
||||||
background_color_pressed = #5a5a5a 21
|
background_color_pressed = #1e1e1e 100
|
||||||
border_color_pressed = #777777 30
|
border_color_pressed = #777777 30
|
||||||
|
|
||||||
# Background 3: Active task
|
# Background 3: Active task
|
||||||
rounded = 0
|
rounded = 0
|
||||||
border_width = 2
|
border_width = 2
|
||||||
border_sides = B
|
border_sides = B
|
||||||
background_color = #ffffff 0
|
border_content_tint_weight = 100
|
||||||
border_color = #4d75ff 100
|
background_content_tint_weight = 100
|
||||||
background_color_hover = #ffffff 21
|
background_color = #ffffff 100
|
||||||
border_color_hover = #4c73ff 100
|
border_color = #d9d9d9 100
|
||||||
background_color_pressed = #989898 21
|
background_color_hover = #ffffff 73
|
||||||
border_color_pressed = #4c73ff 100
|
border_color_hover = #d9d9d9 100
|
||||||
|
background_color_pressed = #989898 73
|
||||||
|
border_color_pressed = #d9d9d9 100
|
||||||
|
|
||||||
# Background 4: Urgent task
|
# Background 4: Urgent task
|
||||||
rounded = 0
|
rounded = 0
|
||||||
border_width = 0
|
border_width = 0
|
||||||
border_sides = TBLR
|
border_sides = TBLR
|
||||||
|
border_content_tint_weight = 0
|
||||||
|
background_content_tint_weight = 0
|
||||||
background_color = #aa4400 100
|
background_color = #aa4400 100
|
||||||
border_color = #aa7733 100
|
border_color = #aa7733 100
|
||||||
background_color_hover = #aa4400 100
|
background_color_hover = #aa4400 100
|
||||||
@@ -60,6 +68,8 @@ border_color_pressed = #aa7733 100
|
|||||||
rounded = 2
|
rounded = 2
|
||||||
border_width = 1
|
border_width = 1
|
||||||
border_sides = TBLR
|
border_sides = TBLR
|
||||||
|
border_content_tint_weight = 0
|
||||||
|
background_content_tint_weight = 0
|
||||||
background_color = #ffffaa 100
|
background_color = #ffffaa 100
|
||||||
border_color = #999999 100
|
border_color = #999999 100
|
||||||
background_color_hover = #ffffaa 100
|
background_color_hover = #ffffaa 100
|
||||||
@@ -71,6 +81,8 @@ border_color_pressed = #999999 100
|
|||||||
rounded = 0
|
rounded = 0
|
||||||
border_width = 2
|
border_width = 2
|
||||||
border_sides = B
|
border_sides = B
|
||||||
|
border_content_tint_weight = 0
|
||||||
|
background_content_tint_weight = 0
|
||||||
background_color = #777777 0
|
background_color = #777777 0
|
||||||
border_color = #777777 0
|
border_color = #777777 0
|
||||||
background_color_hover = #bdbdbd 21
|
background_color_hover = #bdbdbd 21
|
||||||
@@ -82,12 +94,14 @@ border_color_pressed = #777777 100
|
|||||||
rounded = 0
|
rounded = 0
|
||||||
border_width = 2
|
border_width = 2
|
||||||
border_sides = B
|
border_sides = B
|
||||||
|
border_content_tint_weight = 0
|
||||||
|
background_content_tint_weight = 0
|
||||||
background_color = #ffffff 21
|
background_color = #ffffff 21
|
||||||
border_color = #4c73ff 100
|
border_color = #d9d9d9 100
|
||||||
background_color_hover = #ffffff 21
|
background_color_hover = #ffffff 21
|
||||||
border_color_hover = #4d73ff 100
|
border_color_hover = #d9d9d9 100
|
||||||
background_color_pressed = #a9a9a9 21
|
background_color_pressed = #a9a9a9 21
|
||||||
border_color_pressed = #4d73ff 100
|
border_color_pressed = #d9d9d9 100
|
||||||
|
|
||||||
#-------------------------------------
|
#-------------------------------------
|
||||||
# Panel
|
# Panel
|
||||||
@@ -146,6 +160,8 @@ task_maximum_size = 120 35
|
|||||||
task_padding = 4 3 4
|
task_padding = 4 3 4
|
||||||
task_font = Sans 8
|
task_font = Sans 8
|
||||||
task_tooltip = 1
|
task_tooltip = 1
|
||||||
|
task_thumbnail = 0
|
||||||
|
task_thumbnail_size = 210
|
||||||
task_font_color = #c6c6c6 100
|
task_font_color = #c6c6c6 100
|
||||||
task_active_font_color = #ffffff 100
|
task_active_font_color = #ffffff 100
|
||||||
task_icon_asb = 100 0 0
|
task_icon_asb = 100 0 0
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
#---- Generated by tint2conf 2641 ----
|
#---- Generated by tint2conf aeaf ----
|
||||||
# See https://gitlab.com/o9000/tint2/wikis/Configure for
|
# See https://gitlab.com/o9000/tint2/wikis/Configure for
|
||||||
# full documentation of the configuration options.
|
# full documentation of the configuration options.
|
||||||
#-------------------------------------
|
#-------------------------------------
|
||||||
|
# Gradients
|
||||||
|
#-------------------------------------
|
||||||
# Backgrounds
|
# Backgrounds
|
||||||
# Background 1: Panel
|
# Background 1: Panel
|
||||||
rounded = 0
|
rounded = 0
|
||||||
border_width = 0
|
border_width = 0
|
||||||
|
border_sides = TBLR
|
||||||
background_color = #000000 60
|
background_color = #000000 60
|
||||||
border_color = #000000 30
|
border_color = #000000 30
|
||||||
background_color_hover = #000000 60
|
background_color_hover = #000000 60
|
||||||
@@ -16,6 +19,7 @@ border_color_pressed = #000000 30
|
|||||||
# Background 2: Default task, Iconified task
|
# Background 2: Default task, Iconified task
|
||||||
rounded = 4
|
rounded = 4
|
||||||
border_width = 1
|
border_width = 1
|
||||||
|
border_sides = TBLR
|
||||||
background_color = #777777 20
|
background_color = #777777 20
|
||||||
border_color = #777777 30
|
border_color = #777777 30
|
||||||
background_color_hover = #aaaaaa 22
|
background_color_hover = #aaaaaa 22
|
||||||
@@ -26,6 +30,7 @@ border_color_pressed = #eaeaea 44
|
|||||||
# Background 3: Active task
|
# Background 3: Active task
|
||||||
rounded = 4
|
rounded = 4
|
||||||
border_width = 1
|
border_width = 1
|
||||||
|
border_sides = TBLR
|
||||||
background_color = #777777 20
|
background_color = #777777 20
|
||||||
border_color = #ffffff 40
|
border_color = #ffffff 40
|
||||||
background_color_hover = #aaaaaa 22
|
background_color_hover = #aaaaaa 22
|
||||||
@@ -36,6 +41,7 @@ border_color_pressed = #eaeaea 44
|
|||||||
# Background 4: Urgent task
|
# Background 4: Urgent task
|
||||||
rounded = 4
|
rounded = 4
|
||||||
border_width = 1
|
border_width = 1
|
||||||
|
border_sides = TBLR
|
||||||
background_color = #aa4400 100
|
background_color = #aa4400 100
|
||||||
border_color = #aa7733 100
|
border_color = #aa7733 100
|
||||||
background_color_hover = #cc7700 100
|
background_color_hover = #cc7700 100
|
||||||
@@ -46,8 +52,9 @@ border_color_pressed = #aa7733 100
|
|||||||
# Background 5: Tooltip
|
# Background 5: Tooltip
|
||||||
rounded = 1
|
rounded = 1
|
||||||
border_width = 1
|
border_width = 1
|
||||||
background_color = #ffffaa 100
|
border_sides = TBLR
|
||||||
border_color = #000000 100
|
background_color = #222222 100
|
||||||
|
border_color = #333333 100
|
||||||
background_color_hover = #ffffaa 100
|
background_color_hover = #ffffaa 100
|
||||||
border_color_hover = #000000 100
|
border_color_hover = #000000 100
|
||||||
background_color_pressed = #ffffaa 100
|
background_color_pressed = #ffffaa 100
|
||||||
@@ -65,7 +72,7 @@ panel_dock = 0
|
|||||||
panel_position = bottom center horizontal
|
panel_position = bottom center horizontal
|
||||||
panel_layer = top
|
panel_layer = top
|
||||||
panel_monitor = all
|
panel_monitor = all
|
||||||
primary_monitor_first = 0
|
panel_shrink = 0
|
||||||
autohide = 0
|
autohide = 0
|
||||||
autohide_show_timeout = 0
|
autohide_show_timeout = 0
|
||||||
autohide_hide_timeout = 0.5
|
autohide_hide_timeout = 0.5
|
||||||
@@ -81,12 +88,14 @@ mouse_pressed_icon_asb = 100 0 0
|
|||||||
#-------------------------------------
|
#-------------------------------------
|
||||||
# Taskbar
|
# Taskbar
|
||||||
taskbar_mode = single_desktop
|
taskbar_mode = single_desktop
|
||||||
|
taskbar_hide_if_empty = 0
|
||||||
taskbar_padding = 0 0 2
|
taskbar_padding = 0 0 2
|
||||||
taskbar_background_id = 0
|
taskbar_background_id = 0
|
||||||
taskbar_active_background_id = 0
|
taskbar_active_background_id = 0
|
||||||
taskbar_name = 1
|
taskbar_name = 1
|
||||||
taskbar_hide_inactive_tasks = 0
|
taskbar_hide_inactive_tasks = 0
|
||||||
taskbar_hide_different_monitor = 0
|
taskbar_hide_different_monitor = 0
|
||||||
|
taskbar_hide_different_desktop = 0
|
||||||
taskbar_always_show_all_desktop_tasks = 0
|
taskbar_always_show_all_desktop_tasks = 0
|
||||||
taskbar_name_padding = 4 2
|
taskbar_name_padding = 4 2
|
||||||
taskbar_name_background_id = 0
|
taskbar_name_background_id = 0
|
||||||
@@ -106,6 +115,8 @@ urgent_nb_of_blink = 100000
|
|||||||
task_maximum_size = 150 35
|
task_maximum_size = 150 35
|
||||||
task_padding = 2 2 4
|
task_padding = 2 2 4
|
||||||
task_tooltip = 1
|
task_tooltip = 1
|
||||||
|
task_thumbnail = 0
|
||||||
|
task_thumbnail_size = 210
|
||||||
task_font_color = #ffffff 100
|
task_font_color = #ffffff 100
|
||||||
task_background_id = 2
|
task_background_id = 2
|
||||||
task_active_background_id = 3
|
task_active_background_id = 3
|
||||||
@@ -125,6 +136,7 @@ systray_sort = ascending
|
|||||||
systray_icon_size = 24
|
systray_icon_size = 24
|
||||||
systray_icon_asb = 100 0 0
|
systray_icon_asb = 100 0 0
|
||||||
systray_monitor = 1
|
systray_monitor = 1
|
||||||
|
systray_name_filter =
|
||||||
|
|
||||||
#-------------------------------------
|
#-------------------------------------
|
||||||
# Launcher
|
# Launcher
|
||||||
@@ -164,7 +176,10 @@ clock_dwheel_command =
|
|||||||
battery_tooltip = 1
|
battery_tooltip = 1
|
||||||
battery_low_status = 10
|
battery_low_status = 10
|
||||||
battery_low_cmd = notify-send "battery low"
|
battery_low_cmd = notify-send "battery low"
|
||||||
|
battery_full_cmd =
|
||||||
battery_font_color = #ffffff 100
|
battery_font_color = #ffffff 100
|
||||||
|
bat1_format =
|
||||||
|
bat2_format =
|
||||||
battery_padding = 1 0
|
battery_padding = 1 0
|
||||||
battery_background_id = 0
|
battery_background_id = 0
|
||||||
battery_hide = 101
|
battery_hide = 101
|
||||||
@@ -180,7 +195,7 @@ ac_disconnected_cmd =
|
|||||||
# Tooltip
|
# Tooltip
|
||||||
tooltip_show_timeout = 0.5
|
tooltip_show_timeout = 0.5
|
||||||
tooltip_hide_timeout = 0.1
|
tooltip_hide_timeout = 0.1
|
||||||
tooltip_padding = 2 2
|
tooltip_padding = 4 4
|
||||||
tooltip_background_id = 5
|
tooltip_background_id = 5
|
||||||
tooltip_font_color = #222222 100
|
tooltip_font_color = #dddddd 100
|
||||||
|
|
||||||
|
|||||||
@@ -237,3 +237,9 @@ src/signals.c
|
|||||||
src/signals.h
|
src/signals.h
|
||||||
src/tracing.c
|
src/tracing.c
|
||||||
src/tracing.h
|
src/tracing.h
|
||||||
|
src/util/mem.c
|
||||||
|
src/util/mem.h
|
||||||
|
src/util/addr2line.c
|
||||||
|
src/util/addr2line.h
|
||||||
|
src/util/print.h
|
||||||
|
src/util/print.c
|
||||||
|
|||||||
Reference in New Issue
Block a user