Compare commits
135 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8242b494bc | ||
|
|
1c6377f570 | ||
|
|
dd1fd28114 | ||
|
|
b4610fcb6e | ||
|
|
eb0e6765f9 | ||
|
|
5ee278d3ca | ||
|
|
fb438031c3 | ||
|
|
e5380f8e29 | ||
|
|
c064ec70ed | ||
|
|
a9a9a753bc | ||
|
|
38bee65b58 | ||
|
|
f64cf199e4 | ||
|
|
0911dcaed1 | ||
|
|
c41d75e54e | ||
|
|
8e0bdcaedd | ||
|
|
be4554b89d | ||
|
|
82d7fdc8f9 | ||
|
|
e046cb88ab | ||
|
|
300ef518cb | ||
|
|
457d51e267 | ||
|
|
1b48efe738 | ||
|
|
40e01e2abf | ||
|
|
a7ca1b739b | ||
|
|
750cbd572c | ||
|
|
75c2a2084d | ||
|
|
9b17461f74 | ||
|
|
a185f625f9 | ||
|
|
3a9181eff5 | ||
|
|
5cea67171b | ||
|
|
328a35f949 | ||
|
|
cab9c3bddd | ||
|
|
5dd814773a | ||
|
|
f4384b786c | ||
|
|
5bc83561e0 | ||
|
|
375e965a3a | ||
|
|
67e25b8102 | ||
|
|
c96201930b | ||
|
|
6bf72a030a | ||
|
|
63d0d98a5c | ||
|
|
e739023529 | ||
|
|
a7a9c5cdae | ||
|
|
50822bd2fd | ||
|
|
00c79073f0 | ||
|
|
f5b36b37b6 | ||
|
|
c635f46439 | ||
|
|
16a359f944 | ||
|
|
9a972f4c25 | ||
|
|
9d06ac0157 | ||
|
|
cfac6a645d | ||
|
|
648c7c109f | ||
|
|
8946f93254 | ||
|
|
58e030de5d | ||
|
|
c2f8c210f8 | ||
|
|
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 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,3 +1,7 @@
|
||||
build
|
||||
*.user
|
||||
version.h
|
||||
*.pyc
|
||||
*.todo
|
||||
packaging/make_ubuntu2.sh
|
||||
test_*.log
|
||||
|
||||
3
AUTHORS
3
AUTHORS
@@ -31,6 +31,7 @@ Contributors:
|
||||
Matthew Otnel : config option systray_name_filter
|
||||
Ryan Gray, Jeff Blake (https://gitlab.com/berkley4) : battery format
|
||||
aaaz (https://gitlab.com/aaaz) : clock fixes
|
||||
heisenbug (https://gitlab.com/heisenbugh) : taskbar button tinting with icon color
|
||||
|
||||
Translations:
|
||||
Bosnian:
|
||||
@@ -45,3 +46,5 @@ Translations:
|
||||
Daniel Napora <napcok@gmail.com>
|
||||
Serbian:
|
||||
Dino Duratović <dinomol@mail.com>
|
||||
Spanish:
|
||||
Vic <vicmz@yandex.com>
|
||||
|
||||
@@ -25,7 +25,7 @@ endif()
|
||||
include( FindPkgConfig )
|
||||
include( CheckLibraryExists )
|
||||
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( PANGO REQUIRED pango )
|
||||
pkg_check_modules( CAIRO REQUIRED cairo )
|
||||
@@ -62,6 +62,17 @@ else()
|
||||
set(BACKTRACE_L_FLAGS "")
|
||||
endif()
|
||||
|
||||
check_c_source_compiles(
|
||||
"#define print(x) _Generic((x), default : print_unknown)(x) \n void print_unknown(){} \n int main () { print(0); }"
|
||||
HAS_GENERIC)
|
||||
|
||||
if(HAS_GENERIC)
|
||||
add_definitions(-DHAS_GENERIC)
|
||||
set(CSTD "c11")
|
||||
else()
|
||||
set(CSTD "c99")
|
||||
endif(HAS_GENERIC)
|
||||
|
||||
if( ENABLE_RSVG )
|
||||
pkg_check_modules( RSVG librsvg-2.0>=2.14.0 )
|
||||
endif( ENABLE_RSVG )
|
||||
@@ -116,13 +127,14 @@ include_directories( ${PROJECT_BINARY_DIR}
|
||||
|
||||
set( SOURCES src/config.c
|
||||
src/panel.c
|
||||
src/server.c
|
||||
src/util/server.c
|
||||
src/main.c
|
||||
src/init.c
|
||||
src/signals.c
|
||||
src/tracing.c
|
||||
src/util/signals.c
|
||||
src/util/tracing.c
|
||||
src/mouse_actions.c
|
||||
src/drag_and_drop.c
|
||||
src/default_icon.c
|
||||
src/clock/clock.c
|
||||
src/systray/systraybar.c
|
||||
src/launcher/launcher.c
|
||||
@@ -146,7 +158,10 @@ set( SOURCES src/config.c
|
||||
src/util/timer.c
|
||||
src/util/cache.c
|
||||
src/util/color.c
|
||||
src/util/strlcat.c
|
||||
src/util/print.c
|
||||
src/util/gradient.c
|
||||
src/util/test.c
|
||||
src/util/uevent.c
|
||||
src/util/window.c )
|
||||
|
||||
@@ -233,7 +248,7 @@ else()
|
||||
SET(TRACING_L_FLAGS "")
|
||||
endif()
|
||||
|
||||
add_custom_target( version ALL "${PROJECT_SOURCE_DIR}/get_version.sh" -- "\"${PROJECT_SOURCE_DIR}/\"" )
|
||||
add_custom_target( version ALL "${PROJECT_SOURCE_DIR}/get_version.sh" )
|
||||
|
||||
link_directories( ${X11_LIBRARY_DIRS}
|
||||
${PANGOCAIRO_LIBRARY_DIRS}
|
||||
@@ -267,13 +282,13 @@ endif( RT_LIBRARY )
|
||||
target_link_libraries( tint2 m )
|
||||
|
||||
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=${CSTD} ${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}" )
|
||||
|
||||
install( TARGETS tint2 DESTINATION bin )
|
||||
install( FILES tint2.svg DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps )
|
||||
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 AUTHORS ChangeLog README.md doc/tint2.md DESTINATION ${docdir} )
|
||||
install( FILES doc/manual.html doc/readme.html DESTINATION ${htmldir} )
|
||||
|
||||
26
ChangeLog
26
ChangeLog
@@ -1,3 +1,26 @@
|
||||
2017-12-30 16.1
|
||||
- Fixes:
|
||||
- Fixed several use-after-free errors in the timer code
|
||||
- Merged patches and fixed other warnings on OpenBSD
|
||||
- Task, Button, Executor: add a bit of slack in the pango text layout,
|
||||
to avoid wrapping due to rounding errors
|
||||
|
||||
2017-12-20 16.0
|
||||
- Fixes:
|
||||
- Taskbar: `taskbar_distribute_size = 1` now playes well with `task_align = center` and
|
||||
`task_align = right` (issue #688)
|
||||
- Enhancements:
|
||||
- Added Spanish translation (contributed by Vicmz)
|
||||
- Executor: updated tooltip documentation (issue #676)
|
||||
- Systray: warn on duplicate config option systray_name_filter (issue #652)
|
||||
- Taskbar: thumbnail support in tooltips
|
||||
- Use C11 if possible to support generic printing for unit tests (should fall back to C99)
|
||||
|
||||
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
|
||||
- Fixes:
|
||||
- Battery info is now again displayed even when current sensor is missing (https://github.com/jmc-88/tint3/issues/34)
|
||||
@@ -959,3 +982,6 @@ released tint-0.2
|
||||
.
|
||||
.
|
||||
.
|
||||
.
|
||||
.
|
||||
.
|
||||
|
||||
12
README.md
12
README.md
@@ -1,5 +1,5 @@
|
||||
# Latest stable release: 15.2
|
||||
Changes: https://gitlab.com/o9000/tint2/blob/15.2/ChangeLog
|
||||
# Latest stable release: 16.1
|
||||
Changes: https://gitlab.com/o9000/tint2/blob/16.1/ChangeLog
|
||||
|
||||
Documentation: [doc/tint2.md](doc/tint2.md)
|
||||
|
||||
@@ -8,7 +8,7 @@ Compile it with (after you install the [dependencies](https://gitlab.com/o9000/t
|
||||
```
|
||||
git clone https://gitlab.com/o9000/tint2.git
|
||||
cd tint2
|
||||
git checkout 15.2
|
||||
git checkout 16.1
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
@@ -61,9 +61,9 @@ tint2 is a simple panel/taskbar made for modern X window managers. It was specif
|
||||
|
||||
# Known issues
|
||||
|
||||
* Graphic glitches on Intel graphics cards can be avoided by changing the acceleration method to UXA ([issue 595](https://gitlab.com/o9000/tint2/issues/595))
|
||||
* Window managers that do not follow exactly the EWMH specification might not interact well with tint2 (known issues for [awesome](https://gitlab.com/o9000/tint2/issues/385), [bspwm](https://gitlab.com/o9000/tint2/issues/524). [openbox-multihead](https://gitlab.com/o9000/tint2/issues/456))
|
||||
* Full transparency requires a compositor such as Compton (if not provided already by the window manager, as in Compiz/Unity, KDE or XFCE)
|
||||
* Graphical glitches on Intel graphics cards can be avoided by changing the acceleration method to UXA ([issue 595](https://gitlab.com/o9000/tint2/issues/595))
|
||||
* Window managers that do not follow exactly the EWMH specification might not interact well with tint2 ([issue 627](https://gitlab.com/o9000/tint2/issues/627)).
|
||||
* Full transparency requires a compositor such as Compton (if not provided already by the window manager, as in Compiz/Unity, KDE or XFCE).
|
||||
|
||||
# How can I help out?
|
||||
|
||||
|
||||
@@ -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>opacity</code> varies from (0 to 100), where 0 is fully transparent, 100 is fully opaque</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>
|
||||
<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
|
||||
@@ -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_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_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>
|
||||
<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>
|
||||
@@ -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_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_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_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>
|
||||
|
||||
@@ -199,9 +199,9 @@ pre {
|
||||
</style>
|
||||
</head>
|
||||
<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-16-1"><span class="md2man-title">Latest</span> <span class="md2man-section">stable</span> <span class="md2man-date">release:</span> <span class="md2man-source">16.1</span><a name="latest-stable-release-16-1" href="#latest-stable-release-16-1" class="md2man-permalink" title="permalink"></a></h1><p>Changes: <a href="https://gitlab.com/o9000/tint2/blob/16.1/ChangeLog">https://gitlab.com/o9000/tint2/blob/16.1/ChangeLog</a></p><p>Documentation: <a href="manual.html">manual.html</a></p><p>Compile it with (after you install the <a href="https://gitlab.com/o9000/tint2/wikis/Install#dependencies">dependencies</a>):</p><pre class="highlight plaintext"><code>git clone https://gitlab.com/o9000/tint2.git
|
||||
cd tint2
|
||||
git checkout 15.2
|
||||
git checkout 16.1
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
@@ -239,9 +239,9 @@ update-mime-database /usr/local/share/mime
|
||||
</ul>
|
||||
<h1 id="known-issues">Known issues<a name="known-issues" href="#known-issues" class="md2man-permalink" title="permalink"></a></h1>
|
||||
<ul>
|
||||
<li>Graphic glitches on Intel graphics cards can be avoided by changing the acceleration method to UXA (<a href="https://gitlab.com/o9000/tint2/issues/595">issue 595</a>)</li>
|
||||
<li>Window managers that do not follow exactly the EWMH specification might not interact well with tint2 (known issues for <a href="https://gitlab.com/o9000/tint2/issues/385">awesome</a>, <a href="https://gitlab.com/o9000/tint2/issues/524">bspwm</a>. <a href="https://gitlab.com/o9000/tint2/issues/456">openbox-multihead</a>)</li>
|
||||
<li>Full transparency requires a compositor such as Compton (if not provided already by the window manager, as in Compiz/Unity, KDE or XFCE)</li>
|
||||
<li>Graphical glitches on Intel graphics cards can be avoided by changing the acceleration method to UXA (<a href="https://gitlab.com/o9000/tint2/issues/595">issue 595</a>)</li>
|
||||
<li>Window managers that do not follow exactly the EWMH specification might not interact well with tint2 (<a href="https://gitlab.com/o9000/tint2/issues/627">issue 627</a>).</li>
|
||||
<li>Full transparency requires a compositor such as Compton (if not provided already by the window manager, as in Compiz/Unity, KDE or XFCE).</li>
|
||||
</ul>
|
||||
<h1 id="how-can-i-help-out">How can I help out?<a name="how-can-i-help-out" href="#how-can-i-help-out" class="md2man-permalink" title="permalink"></a></h1>
|
||||
<ul>
|
||||
|
||||
12
doc/tint2.1
12
doc/tint2.1
@@ -1,4 +1,4 @@
|
||||
.TH TINT2 1 "2017\-10\-01" 15.2
|
||||
.TH TINT2 1 "2017\-12\-30" 16.1
|
||||
.SH NAME
|
||||
.PP
|
||||
tint2 \- lightweight panel/taskbar
|
||||
@@ -150,6 +150,10 @@ The tint2 config file starts with the options defining background elements with
|
||||
.IP \(bu 2
|
||||
\fB\fCopacity\fR varies from (0 to 100), where 0 is fully transparent, 100 is fully opaque
|
||||
.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
|
||||
.PP
|
||||
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
|
||||
\fB\fCtask_tooltip = boolean (0 or 1)\fR : Whether to show tooltips for tasks.
|
||||
.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
|
||||
.RS
|
||||
.IP \(bu 2
|
||||
@@ -716,7 +724,7 @@ To hide the clock, comment \fB\fCtime1_format\fR and \fB\fCtime2_format\fR\&.
|
||||
.IP \(bu 2
|
||||
\fB\fCexecp_icon_h = integer\fR : See \fB\fCexecp_icon_w\fR\&. \fI(since 0.12.4)\fP
|
||||
.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
|
||||
\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
|
||||
|
||||
12
doc/tint2.md
12
doc/tint2.md
@@ -1,4 +1,4 @@
|
||||
# TINT2 1 "2017-10-01" 15.2
|
||||
# TINT2 1 "2017-12-30" 16.1
|
||||
|
||||
## NAME
|
||||
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
|
||||
* `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:
|
||||
|
||||
```
|
||||
@@ -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_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`
|
||||
* `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.
|
||||
@@ -591,7 +599,7 @@ The action semantics:
|
||||
|
||||
* `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)*
|
||||
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
#!/bin/sh
|
||||
|
||||
MAJOR=0.14
|
||||
SCRIPT_DIR=$(dirname "$0")
|
||||
DIRTY=""
|
||||
VERSION=""
|
||||
|
||||
if git status 1>/dev/null 2>/dev/null
|
||||
OLD_DIR=$(pwd)
|
||||
cd ${SCRIPT_DIR}
|
||||
|
||||
if [ -d .git ] && git status 1>/dev/null 2>/dev/null
|
||||
then
|
||||
git update-index -q --ignore-submodules --refresh
|
||||
# Disallow unstaged changes in the working tree
|
||||
@@ -31,16 +35,31 @@ then
|
||||
DIRTY="-dirty"
|
||||
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
|
||||
else
|
||||
SCRIPT_DIR=$(dirname "$0")
|
||||
VERSION=$(head -n 1 "${SCRIPT_DIR}/ChangeLog" | cut -d ' ' -f 2)
|
||||
if [ "$VERSION" = "master" ]
|
||||
if git describe 1>/dev/null 2>/dev/null
|
||||
then
|
||||
VERSION=$VERSION-$(head -n 1 "${SCRIPT_DIR}/ChangeLog" | cut -d ' ' -f 1)
|
||||
VERSION=$(git describe 2>/dev/null)$DIRTY
|
||||
elif git log -n 1 1>/dev/null 2>/dev/null
|
||||
then
|
||||
VERSION=$(head -n 1 "ChangeLog" | cut -d ' ' -f 2)
|
||||
if [ "$VERSION" = "master" ]
|
||||
then
|
||||
PREVIOUS=$(grep '^2' "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 "ChangeLog" | cut -d ' ' -f 2)
|
||||
if [ "$VERSION" = "master" ]
|
||||
then
|
||||
VERSION=$VERSION-$(head -n 1 "ChangeLog" | cut -d ' ' -f 1)
|
||||
fi
|
||||
fi
|
||||
|
||||
cd "${OLD_DIR}"
|
||||
|
||||
VERSION=$(echo "$VERSION" | sed 's/^v//')
|
||||
|
||||
|
||||
@@ -190,3 +190,7 @@ if __name__ == '__main__':
|
||||
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)
|
||||
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 $@
|
||||
|
||||
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:
|
||||
dh_auto_install --destdir=$(CURDIR)/debian/tmp
|
||||
|
||||
@@ -21,7 +21,7 @@ then
|
||||
exit 1
|
||||
fi
|
||||
rm -f version.h
|
||||
VERSION=$(git describe --exact-match 2>/dev/null)
|
||||
VERSION=$(false 2>/dev/null)
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
VERSION=$(echo "$VERSION" | sed 's/^v//')
|
||||
@@ -49,7 +49,7 @@ echo "echo \"#define VERSION_STRING \\\"$VERSION\\\"\" > version.h" > $DIR/get_v
|
||||
# Copy the debian files into the source directory
|
||||
cp -r debian $DIR/debian
|
||||
|
||||
for DISTRO in trusty xenial zesty artful
|
||||
for DISTRO in trusty xenial zesty artful bionic
|
||||
do
|
||||
# Cleanup from previous builds
|
||||
rm -rf tint2_$VERSION-*
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
export PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
|
||||
@@ -367,7 +367,7 @@ def get_freebsd_versions():
|
||||
|
||||
def get_openbsd_versions():
|
||||
print >> sys.stderr, "OpenBSD ..."
|
||||
makefile = http_download_txt("http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/ports/x11/tint2/Makefile?rev=1.5&content-type=text/plain")
|
||||
makefile = http_download_txt("http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/ports/x11/tint2/Makefile?content-type=text/plain")
|
||||
versions = []
|
||||
version = None
|
||||
for line in makefile.split("\n"):
|
||||
|
||||
@@ -41,7 +41,7 @@ struct BatteryState battery_state;
|
||||
gboolean battery_enabled;
|
||||
gboolean battery_tooltip_enabled;
|
||||
int percentage_hide;
|
||||
static timeout *battery_timeout;
|
||||
static Timer battery_timer;
|
||||
|
||||
#define BATTERY_BUF_SIZE 256
|
||||
static char buf_bat_line1[BATTERY_BUF_SIZE];
|
||||
@@ -76,7 +76,7 @@ void default_battery()
|
||||
percentage_hide = 101;
|
||||
battery_low_cmd_sent = FALSE;
|
||||
battery_full_cmd_sent = FALSE;
|
||||
battery_timeout = NULL;
|
||||
INIT_TIMER(battery_timer);
|
||||
bat1_has_font = FALSE;
|
||||
bat1_font_desc = NULL;
|
||||
bat1_format = NULL;
|
||||
@@ -127,8 +127,7 @@ void cleanup_battery()
|
||||
ac_connected_cmd = NULL;
|
||||
free(ac_disconnected_cmd);
|
||||
ac_disconnected_cmd = NULL;
|
||||
stop_timeout(battery_timeout);
|
||||
battery_timeout = NULL;
|
||||
destroy_timer(&battery_timer);
|
||||
battery_found = FALSE;
|
||||
|
||||
battery_os_free();
|
||||
@@ -226,7 +225,7 @@ void init_battery()
|
||||
|
||||
battery_found = battery_os_init();
|
||||
|
||||
battery_timeout = add_timeout(10, 30000, update_battery_tick, 0, &battery_timeout);
|
||||
change_timer(&battery_timer, true, 10, 30000, update_battery_tick, 0);
|
||||
|
||||
update_battery();
|
||||
}
|
||||
|
||||
@@ -52,11 +52,9 @@ void destroy_button(void *obj)
|
||||
Button *button = (Button *)obj;
|
||||
if (button->frontend) {
|
||||
// This is a frontend element
|
||||
if (button->frontend->icon) {
|
||||
imlib_context_set_image(button->frontend->icon);
|
||||
imlib_free_image();
|
||||
button->frontend->icon = NULL;
|
||||
}
|
||||
free_icon(button->frontend->icon);
|
||||
free_icon(button->frontend->icon_hover);
|
||||
free_icon(button->frontend->icon_pressed);
|
||||
button->backend->instances = g_list_remove_all(button->backend->instances, button);
|
||||
free_and_null(button->frontend);
|
||||
remove_area(&button->area);
|
||||
@@ -79,7 +77,7 @@ void destroy_button(void *obj)
|
||||
|
||||
if (button->backend->instances) {
|
||||
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);
|
||||
@@ -462,7 +460,7 @@ void draw_button(void *obj, cairo_t *c)
|
||||
PangoLayout *layout = pango_cairo_create_layout(c);
|
||||
|
||||
pango_layout_set_font_description(layout, button->backend->font_desc);
|
||||
pango_layout_set_width(layout, button->frontend->textw * PANGO_SCALE);
|
||||
pango_layout_set_width(layout, (button->frontend->textw + 1) * PANGO_SCALE);
|
||||
pango_layout_set_alignment(layout, button->backend->centered ? PANGO_ALIGN_CENTER : PANGO_ALIGN_LEFT);
|
||||
pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
|
||||
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
|
||||
|
||||
@@ -51,7 +51,7 @@ static char buf_time[256];
|
||||
static char buf_date[256];
|
||||
static char buf_tooltip[512];
|
||||
int clock_enabled;
|
||||
static timeout *clock_timeout;
|
||||
static Timer clock_timer;
|
||||
|
||||
void clock_init_fonts();
|
||||
char *clock_get_tooltip(void *obj);
|
||||
@@ -61,11 +61,11 @@ void clock_dump_geometry(void *obj, int indent);
|
||||
void default_clock()
|
||||
{
|
||||
clock_enabled = 0;
|
||||
clock_timeout = NULL;
|
||||
time1_format = NULL;
|
||||
time1_timezone = NULL;
|
||||
time2_format = NULL;
|
||||
time2_timezone = NULL;
|
||||
INIT_TIMER(clock_timer);
|
||||
time_tooltip_format = NULL;
|
||||
time_tooltip_timezone = NULL;
|
||||
clock_lclick_command = NULL;
|
||||
@@ -110,8 +110,7 @@ void cleanup_clock()
|
||||
clock_uwheel_command = NULL;
|
||||
free(clock_dwheel_command);
|
||||
clock_dwheel_command = NULL;
|
||||
stop_timeout(clock_timeout);
|
||||
clock_timeout = NULL;
|
||||
destroy_timer(&clock_timer);
|
||||
}
|
||||
|
||||
struct tm *clock_gettime_for_tz(const char *timezone)
|
||||
@@ -155,7 +154,7 @@ void update_clocks_sec(void *arg)
|
||||
{
|
||||
gettimeofday(&time_clock, 0);
|
||||
update_clocks();
|
||||
clock_timeout = add_timeout(ms_until_second_change(&time_clock), 0, update_clocks_sec, 0, &clock_timeout);
|
||||
change_timer(&clock_timer, true, ms_until_second_change(&time_clock), 0, update_clocks_sec, 0);
|
||||
}
|
||||
|
||||
void update_clocks_min(void *arg)
|
||||
@@ -167,7 +166,7 @@ void update_clocks_min(void *arg)
|
||||
if (time_clock.tv_sec % 60 == 0 || time_clock.tv_sec - old_sec > 60 || (time1_format && !buf_time[0]) || (time2_format && !buf_date[0]))
|
||||
update_clocks();
|
||||
old_sec = time_clock.tv_sec;
|
||||
clock_timeout = add_timeout(ms_until_second_change(&time_clock), 0, update_clocks_min, 0, &clock_timeout);
|
||||
change_timer(&clock_timer, true, ms_until_second_change(&time_clock), 0, update_clocks_min, 0);
|
||||
}
|
||||
|
||||
gboolean time_format_needs_sec_ticks(char *time_format)
|
||||
@@ -216,7 +215,7 @@ void init_clock_panel(void *p)
|
||||
strftime(buf_tooltip, sizeof(buf_tooltip), time_tooltip_format, clock_gettime_for_tz(time_tooltip_timezone));
|
||||
}
|
||||
|
||||
if (!clock_timeout) {
|
||||
if (!clock_timer.enabled_) {
|
||||
if (time_format_needs_sec_ticks(time1_format) || time_format_needs_sec_ticks(time2_format)) {
|
||||
update_clocks_sec(NULL);
|
||||
} else {
|
||||
|
||||
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;
|
||||
if (id >= 0)
|
||||
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 */
|
||||
@@ -1086,11 +1092,18 @@ void add_entry(char *key, char *value)
|
||||
panel_config.g_task.config_background_mask |= (1 << status);
|
||||
if (status == 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
|
||||
else if (strcmp(key, "task_tooltip") == 0 || strcmp(key, "tooltip") == 0)
|
||||
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 */
|
||||
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) {
|
||||
systray_monitor = MAX(0, config_get_monitor(value));
|
||||
} 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);
|
||||
}
|
||||
systray_hide_name_filter = strdup(value);
|
||||
}
|
||||
|
||||
|
||||
5
src/default_icon.c
Normal file
5
src/default_icon.c
Normal file
File diff suppressed because one or more lines are too long
10
src/default_icon.h
Normal file
10
src/default_icon.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef default_icon_h
|
||||
#define default_icon_h
|
||||
|
||||
#include <Imlib2.h>
|
||||
|
||||
extern int default_icon_width;
|
||||
extern int default_icon_height;
|
||||
extern DATA32 default_icon_data[];
|
||||
|
||||
#endif
|
||||
@@ -41,6 +41,7 @@ Execp *create_execp()
|
||||
execp->backend->cache_icon = TRUE;
|
||||
execp->backend->centered = TRUE;
|
||||
execp->backend->font_color.alpha = 0.5;
|
||||
INIT_TIMER(execp->backend->timer);
|
||||
return execp;
|
||||
}
|
||||
|
||||
@@ -67,14 +68,9 @@ void destroy_execp(void *obj)
|
||||
free_and_null(execp);
|
||||
} else {
|
||||
// This is a backend element
|
||||
stop_timeout(execp->backend->timer);
|
||||
execp->backend->timer = NULL;
|
||||
destroy_timer(&execp->backend->timer);
|
||||
|
||||
if (execp->backend->icon) {
|
||||
imlib_context_set_image(execp->backend->icon);
|
||||
imlib_free_image();
|
||||
execp->backend->icon = NULL;
|
||||
}
|
||||
free_icon(execp->backend->icon);
|
||||
free_and_null(execp->backend->buf_stdout);
|
||||
free_and_null(execp->backend->buf_stderr);
|
||||
free_and_null(execp->backend->text);
|
||||
@@ -109,7 +105,7 @@ void destroy_execp(void *obj)
|
||||
|
||||
if (execp->backend->instances) {
|
||||
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);
|
||||
@@ -196,7 +192,7 @@ void init_execp_panel(void *p)
|
||||
execp->area.on_screen = TRUE;
|
||||
instantiate_area_gradients(&execp->area);
|
||||
|
||||
execp->backend->timer = add_timeout(10, 0, execp_timer_callback, execp, &execp->backend->timer);
|
||||
change_timer(&execp->backend->timer, true, 10, 0, execp_timer_callback, execp);
|
||||
|
||||
execp_update_post_read(execp);
|
||||
}
|
||||
@@ -490,7 +486,7 @@ void draw_execp(void *obj, cairo_t *c)
|
||||
|
||||
// draw layout
|
||||
pango_layout_set_font_description(layout, execp->backend->font_desc);
|
||||
pango_layout_set_width(layout, execp->frontend->textw * PANGO_SCALE);
|
||||
pango_layout_set_width(layout, (execp->frontend->textw + 1) * PANGO_SCALE);
|
||||
pango_layout_set_alignment(layout, execp->backend->centered ? PANGO_ALIGN_CENTER : PANGO_ALIGN_LEFT);
|
||||
pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
|
||||
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
|
||||
@@ -544,10 +540,8 @@ void execp_force_update(Execp *execp)
|
||||
if (execp->backend->child_pipe_stdout > 0) {
|
||||
// Command currently running, nothing to do
|
||||
} else {
|
||||
if (execp->backend->timer)
|
||||
stop_timeout(execp->backend->timer);
|
||||
// Run command right away
|
||||
execp->backend->timer = add_timeout(10, 0, execp_timer_callback, execp, &execp->backend->timer);
|
||||
change_timer(&execp->backend->timer, true, 10, 0, execp_timer_callback, execp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -761,8 +755,7 @@ gboolean read_execp(void *obj)
|
||||
close(execp->backend->child_pipe_stderr);
|
||||
execp->backend->child_pipe_stderr = -1;
|
||||
if (execp->backend->interval)
|
||||
execp->backend->timer =
|
||||
add_timeout(execp->backend->interval * 1000, 0, execp_timer_callback, execp, &execp->backend->timer);
|
||||
change_timer(&execp->backend->timer, true, execp->backend->interval * 1000, 0, execp_timer_callback, execp);
|
||||
}
|
||||
|
||||
char *ansi_clear_screen = (char*)"\x1b[2J";
|
||||
@@ -886,22 +879,22 @@ gboolean read_execp(void *obj)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const char *time_to_string(int seconds, char *buffer)
|
||||
const char *time_to_string(int seconds, char *buffer, size_t buffer_size)
|
||||
{
|
||||
if (seconds < 60) {
|
||||
sprintf(buffer, "%ds", seconds);
|
||||
snprintf(buffer, buffer_size, "%ds", seconds);
|
||||
} else if (seconds < 60 * 60) {
|
||||
int m = seconds / 60;
|
||||
seconds = seconds % 60;
|
||||
int s = seconds;
|
||||
sprintf(buffer, "%d:%ds", m, s);
|
||||
snprintf(buffer, buffer_size, "%d:%ds", m, s);
|
||||
} else {
|
||||
int h = seconds / (60 * 60);
|
||||
seconds = seconds % (60 * 60);
|
||||
int m = seconds / 60;
|
||||
seconds = seconds % 60;
|
||||
int s = seconds;
|
||||
sprintf(buffer, "%d:%d:%ds", h, m, s);
|
||||
snprintf(buffer, buffer_size, "%d:%d:%ds", h, m, s);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
@@ -927,35 +920,39 @@ char *execp_get_tooltip(void *obj)
|
||||
if (execp->backend->last_update_finish_time) {
|
||||
// We updated at least once
|
||||
if (execp->backend->interval > 0) {
|
||||
sprintf(execp->backend->tooltip_text,
|
||||
"Last update finished %s ago (took %s). Next update starting in %s.",
|
||||
time_to_string((int)(now - execp->backend->last_update_finish_time), tmp_buf1),
|
||||
time_to_string((int)execp->backend->last_update_duration, tmp_buf2),
|
||||
time_to_string((int)(execp->backend->interval - (now - execp->backend->last_update_finish_time)),
|
||||
tmp_buf3));
|
||||
snprintf(execp->backend->tooltip_text,
|
||||
sizeof(execp->backend->tooltip_text),
|
||||
"Last update finished %s ago (took %s). Next update starting in %s.",
|
||||
time_to_string((int)(now - execp->backend->last_update_finish_time), tmp_buf1, sizeof(tmp_buf1)),
|
||||
time_to_string((int)execp->backend->last_update_duration, tmp_buf2, sizeof(tmp_buf2)),
|
||||
time_to_string((int)(execp->backend->interval - (now - execp->backend->last_update_finish_time)),
|
||||
tmp_buf3, sizeof(tmp_buf3)));
|
||||
} else {
|
||||
sprintf(execp->backend->tooltip_text,
|
||||
"Last update finished %s ago (took %s).",
|
||||
time_to_string((int)(now - execp->backend->last_update_finish_time), tmp_buf1),
|
||||
time_to_string((int)execp->backend->last_update_duration, tmp_buf2));
|
||||
snprintf(execp->backend->tooltip_text,
|
||||
sizeof(execp->backend->tooltip_text),
|
||||
"Last update finished %s ago (took %s).",
|
||||
time_to_string((int)(now - execp->backend->last_update_finish_time), tmp_buf1, sizeof(tmp_buf1)),
|
||||
time_to_string((int)execp->backend->last_update_duration, tmp_buf2, sizeof(tmp_buf2)));
|
||||
}
|
||||
} else {
|
||||
// we never requested an update
|
||||
sprintf(execp->backend->tooltip_text, "Never updated. No update scheduled.");
|
||||
snprintf(execp->backend->tooltip_text, sizeof(execp->backend->tooltip_text), "Never updated. No update scheduled.");
|
||||
}
|
||||
} else {
|
||||
// Currently executing command
|
||||
if (execp->backend->last_update_finish_time) {
|
||||
// we finished updating at least once
|
||||
sprintf(execp->backend->tooltip_text,
|
||||
"Last update finished %s ago. Update in progress (started %s ago).",
|
||||
time_to_string((int)(now - execp->backend->last_update_finish_time), tmp_buf1),
|
||||
time_to_string((int)(now - execp->backend->last_update_start_time), tmp_buf3));
|
||||
snprintf(execp->backend->tooltip_text,
|
||||
sizeof(execp->backend->tooltip_text),
|
||||
"Last update finished %s ago. Update in progress (started %s ago).",
|
||||
time_to_string((int)(now - execp->backend->last_update_finish_time), tmp_buf1, sizeof(tmp_buf1)),
|
||||
time_to_string((int)(now - execp->backend->last_update_start_time), tmp_buf3, sizeof(tmp_buf3)));
|
||||
} else {
|
||||
// we never finished an update
|
||||
sprintf(execp->backend->tooltip_text,
|
||||
"First update in progress (started %s seconds ago).",
|
||||
time_to_string((int)(now - execp->backend->last_update_start_time), tmp_buf1));
|
||||
snprintf(execp->backend->tooltip_text,
|
||||
sizeof(execp->backend->tooltip_text),
|
||||
"First update in progress (started %s seconds ago).",
|
||||
time_to_string((int)(now - execp->backend->last_update_start_time), tmp_buf1, sizeof(tmp_buf1)));
|
||||
}
|
||||
}
|
||||
return strdup(execp->backend->tooltip_text);
|
||||
|
||||
@@ -46,7 +46,7 @@ typedef struct ExecpBackend {
|
||||
Background *bg;
|
||||
|
||||
// Backend state:
|
||||
timeout *timer;
|
||||
Timer timer;
|
||||
int child_pipe_stdout;
|
||||
int child_pipe_stderr;
|
||||
pid_t child;
|
||||
|
||||
74
src/init.c
74
src/init.c
@@ -6,12 +6,19 @@
|
||||
#include <string.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 "default_icon.h"
|
||||
#include "drag_and_drop.h"
|
||||
#include "fps_distribution.h"
|
||||
#include "panel.h"
|
||||
#include "server.h"
|
||||
#include "signals.h"
|
||||
#include "test.h"
|
||||
#include "tooltip.h"
|
||||
#include "tracing.h"
|
||||
#include "uevent.h"
|
||||
@@ -43,6 +50,15 @@ void handle_cli_arguments(int argc, char **argv)
|
||||
} else if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0) {
|
||||
fprintf(stdout, "tint2 version %s\n", VERSION_STRING);
|
||||
exit(0);
|
||||
} else if (strcmp(argv[i], "--test") == 0) {
|
||||
run_all_tests(false);
|
||||
exit(0);
|
||||
} else if (strcmp(argv[i], "--test-verbose") == 0) {
|
||||
run_all_tests(true);
|
||||
exit(0);
|
||||
} else if (strcmp(argv[i], "--dump-image-data") == 0) {
|
||||
dump_image_data(argv[i+1], argv[i+2]);
|
||||
exit(0);
|
||||
} else if (strcmp(argv[i], "-c") == 0) {
|
||||
if (i + 1 < argc) {
|
||||
i++;
|
||||
@@ -75,7 +91,7 @@ void handle_cli_arguments(int argc, char **argv)
|
||||
}
|
||||
if (error) {
|
||||
print_usage();
|
||||
exit(1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -88,6 +104,8 @@ void handle_env_vars()
|
||||
debug_fps = getenv("DEBUG_FPS") != NULL;
|
||||
debug_frames = getenv("DEBUG_FRAMES") != NULL;
|
||||
debug_dnd = getenv("DEBUG_DND") != NULL;
|
||||
debug_thumbnails = getenv("DEBUG_THUMBNAILS") != NULL;
|
||||
debug_timers = getenv("DEBUG_TIMERS") != NULL;
|
||||
if (debug_fps) {
|
||||
init_fps_distribution();
|
||||
char *s = getenv("TRACING_FPS_THRESHOLD");
|
||||
@@ -97,25 +115,25 @@ void handle_env_vars()
|
||||
}
|
||||
}
|
||||
|
||||
static timeout *detect_compositor_timer = NULL;
|
||||
static Timer detect_compositor_timer = DEFAULT_TIMER;
|
||||
static int detect_compositor_timer_counter = 0;
|
||||
|
||||
void detect_compositor(void *arg)
|
||||
{
|
||||
if (server.composite_manager) {
|
||||
stop_timeout(detect_compositor_timer);
|
||||
stop_timer(&detect_compositor_timer);
|
||||
return;
|
||||
}
|
||||
|
||||
detect_compositor_timer_counter--;
|
||||
if (detect_compositor_timer_counter < 0) {
|
||||
stop_timeout(detect_compositor_timer);
|
||||
stop_timer(&detect_compositor_timer);
|
||||
return;
|
||||
}
|
||||
|
||||
// No compositor, check for one
|
||||
if (XGetSelectionOwner(server.display, server.atom._NET_WM_CM_S0) != None) {
|
||||
stop_timeout(detect_compositor_timer);
|
||||
stop_timer(&detect_compositor_timer);
|
||||
// Restart tint2
|
||||
fprintf(stderr, "tint2: Detected compositor, restarting tint2...\n");
|
||||
kill(getpid(), SIGUSR1);
|
||||
@@ -128,15 +146,15 @@ void start_detect_compositor()
|
||||
if (server.composite_manager)
|
||||
return;
|
||||
|
||||
stop_timeout(detect_compositor_timer);
|
||||
// Check every 0.5 seconds for up to 30 seconds
|
||||
detect_compositor_timer_counter = 60;
|
||||
detect_compositor_timer = add_timeout(500, 500, detect_compositor, 0, &detect_compositor_timer);
|
||||
INIT_TIMER(detect_compositor_timer);
|
||||
change_timer(&detect_compositor_timer, true, 500, 500, detect_compositor, 0);
|
||||
}
|
||||
|
||||
void create_default_elements()
|
||||
{
|
||||
default_timeout();
|
||||
default_timers();
|
||||
default_systray();
|
||||
memset(&server, 0, sizeof(server));
|
||||
#ifdef ENABLE_BATTERY
|
||||
@@ -151,6 +169,22 @@ void create_default_elements()
|
||||
default_panel();
|
||||
}
|
||||
|
||||
void load_default_task_icon()
|
||||
{
|
||||
const gchar *const *data_dirs = g_get_system_data_dirs();
|
||||
for (int i = 0; data_dirs[i] != NULL; i++) {
|
||||
gchar *path = g_build_filename(data_dirs[i], "tint2", "default_icon.png", NULL);
|
||||
if (g_file_test(path, G_FILE_TEST_EXISTS))
|
||||
default_icon = load_image(path, TRUE);
|
||||
g_free(path);
|
||||
}
|
||||
if (!default_icon) {
|
||||
default_icon = imlib_create_image_using_data(default_icon_width,
|
||||
default_icon_height,
|
||||
default_icon_data);
|
||||
}
|
||||
}
|
||||
|
||||
void init_post_config()
|
||||
{
|
||||
server_init_visual();
|
||||
@@ -161,20 +195,7 @@ void init_post_config()
|
||||
imlib_context_set_colormap(server.colormap);
|
||||
|
||||
init_signals_postconfig();
|
||||
|
||||
// load default icon
|
||||
const gchar *const *data_dirs = g_get_system_data_dirs();
|
||||
for (int i = 0; data_dirs[i] != NULL; i++) {
|
||||
gchar *path = g_build_filename(data_dirs[i], "tint2", "default_icon.png", NULL);
|
||||
if (g_file_test(path, G_FILE_TEST_EXISTS))
|
||||
default_icon = load_image(path, TRUE);
|
||||
g_free(path);
|
||||
}
|
||||
if (!default_icon) {
|
||||
fprintf(stderr,
|
||||
RED "Could not load default_icon.png. Please check that tint2 has been installed correctly!" RESET
|
||||
"\n");
|
||||
}
|
||||
load_default_task_icon();
|
||||
|
||||
XSync(server.display, False);
|
||||
}
|
||||
@@ -184,7 +205,7 @@ void init_X11_pre_config()
|
||||
server.display = XOpenDisplay(NULL);
|
||||
if (!server.display) {
|
||||
fprintf(stderr, "tint2: could not open display!\n");
|
||||
exit(1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
server.x11_fd = ConnectionNumber(server.display);
|
||||
XSetErrorHandler((XErrorHandler)server_catch_error);
|
||||
@@ -193,6 +214,7 @@ void init_X11_pre_config()
|
||||
server.screen = DefaultScreen(server.display);
|
||||
server.root_win = RootWindow(server.display, server.screen);
|
||||
server.desktop = get_current_desktop();
|
||||
server.has_shm = XShmQueryExtension(server.display);
|
||||
|
||||
// Needed since the config file uses '.' as decimal separator
|
||||
setlocale(LC_ALL, "");
|
||||
@@ -215,10 +237,10 @@ void init(int argc, char **argv)
|
||||
setlinebuf(stdout);
|
||||
setlinebuf(stderr);
|
||||
default_config();
|
||||
handle_env_vars();
|
||||
handle_cli_arguments(argc, argv);
|
||||
create_default_elements();
|
||||
init_signals();
|
||||
handle_env_vars();
|
||||
|
||||
init_X11_pre_config();
|
||||
if (!config_read()) {
|
||||
@@ -251,6 +273,8 @@ void cleanup()
|
||||
#ifdef ENABLE_BATTERY
|
||||
cleanup_battery();
|
||||
#endif
|
||||
cleanup_separator();
|
||||
cleanup_taskbar();
|
||||
cleanup_panel();
|
||||
cleanup_config();
|
||||
|
||||
@@ -265,7 +289,7 @@ void cleanup()
|
||||
xsettings_client = NULL;
|
||||
|
||||
cleanup_server();
|
||||
cleanup_timeout();
|
||||
cleanup_timers();
|
||||
|
||||
if (server.display)
|
||||
XCloseDisplay(server.display);
|
||||
|
||||
@@ -60,9 +60,9 @@ void expand_exec(DesktopEntry *entry, const char *path)
|
||||
// %c -> Name
|
||||
// %k -> path
|
||||
if (entry->exec) {
|
||||
char *exec2 = calloc(strlen(entry->exec) + (entry->name ? strlen(entry->name) : 1) +
|
||||
(entry->icon ? strlen(entry->icon) : 1) + 100,
|
||||
1);
|
||||
size_t buf_size = strlen(entry->exec) + (entry->name ? strlen(entry->name) : 1) +
|
||||
(entry->icon ? strlen(entry->icon) : 1) + 100;
|
||||
char *exec2 = calloc(buf_size, 1);
|
||||
char *p, *q;
|
||||
// p will never point to an escaped char
|
||||
for (p = entry->exec, q = exec2; *p; p++, q++) {
|
||||
@@ -82,23 +82,30 @@ void expand_exec(DesktopEntry *entry, const char *path)
|
||||
if (!*p)
|
||||
break;
|
||||
if (*p == 'i' && entry->icon != NULL) {
|
||||
sprintf(q, "--icon '%s'", entry->icon);
|
||||
snprintf(q, buf_size, "--icon '%s'", entry->icon);
|
||||
char *old = q;
|
||||
q += strlen("--icon ''");
|
||||
q += strlen(entry->icon);
|
||||
buf_size -= (size_t)(q - old);
|
||||
q--; // To balance the q++ in the for
|
||||
} else if (*p == 'c' && entry->name != NULL) {
|
||||
sprintf(q, "'%s'", entry->name);
|
||||
snprintf(q, buf_size, "'%s'", entry->name);
|
||||
char *old = q;
|
||||
q += strlen("''");
|
||||
q += strlen(entry->name);
|
||||
buf_size -= (size_t)(q - old);
|
||||
q--; // To balance the q++ in the for
|
||||
} else if (*p == 'c') {
|
||||
sprintf(q, "'%s'", path);
|
||||
snprintf(q, buf_size, "'%s'", path);
|
||||
char *old = q;
|
||||
q += strlen("''");
|
||||
q += strlen(path);
|
||||
buf_size -= (size_t)(q - old);
|
||||
q--; // To balance the q++ in the for
|
||||
} else if (*p == 'f' || *p == 'F') {
|
||||
sprintf(q, "%c%c", '%', *p);
|
||||
snprintf(q, buf_size, "%c%c", '%', *p);
|
||||
q += 2;
|
||||
buf_size -= 2;
|
||||
q--; // To balance the q++ in the for
|
||||
} else {
|
||||
// We don't care about other expansions
|
||||
|
||||
@@ -48,7 +48,7 @@ int parse_theme_line(char *line, char **key, char **value)
|
||||
return parse_dektop_line(line, key, value);
|
||||
}
|
||||
|
||||
GSList *icon_locations = NULL;
|
||||
static GSList *icon_locations = NULL;
|
||||
// Do not free the result.
|
||||
const GSList *get_icon_locations()
|
||||
{
|
||||
@@ -74,6 +74,21 @@ const GSList *get_icon_locations()
|
||||
return icon_locations;
|
||||
}
|
||||
|
||||
static GSList *icon_extensions = NULL;
|
||||
const GSList *get_icon_extensions()
|
||||
{
|
||||
if (icon_extensions)
|
||||
return icon_extensions;
|
||||
|
||||
icon_extensions = g_slist_append(icon_extensions, ".png");
|
||||
icon_extensions = g_slist_append(icon_extensions, ".xpm");
|
||||
#ifdef HAVE_RSVG
|
||||
icon_extensions = g_slist_append(icon_extensions, ".svg");
|
||||
#endif
|
||||
icon_extensions = g_slist_append(icon_extensions, "");
|
||||
return icon_extensions;
|
||||
}
|
||||
|
||||
IconTheme *make_theme(const char *name)
|
||||
{
|
||||
IconTheme *theme = calloc(1, sizeof(IconTheme));
|
||||
@@ -535,41 +550,42 @@ gint compare_theme_directories(gconstpointer a, gconstpointer b, gpointer size_q
|
||||
return abs(da->size - size) - abs(db->size - size);
|
||||
}
|
||||
|
||||
Bool is_full_path(const char *s)
|
||||
{
|
||||
if (!s)
|
||||
return FALSE;
|
||||
return s[0] == '/';
|
||||
}
|
||||
|
||||
Bool file_exists(const char *path)
|
||||
{
|
||||
return g_file_test(path, G_FILE_TEST_EXISTS);
|
||||
}
|
||||
|
||||
char *icon_path_from_full_path(const char *s)
|
||||
{
|
||||
if (is_full_path(s) && file_exists(s))
|
||||
return strdup(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *get_icon_path_helper(GSList *themes, const char *icon_name, int size)
|
||||
{
|
||||
if (icon_name == NULL)
|
||||
if (!icon_name)
|
||||
return NULL;
|
||||
|
||||
// If the icon_name is already a path and the file exists, return it
|
||||
if (strstr(icon_name, "/") == icon_name) {
|
||||
if (g_file_test(icon_name, G_FILE_TEST_EXISTS))
|
||||
return strdup(icon_name);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
char *result = icon_path_from_full_path(icon_name);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
const GSList *basenames = get_icon_locations();
|
||||
GSList *extensions = NULL;
|
||||
extensions = g_slist_append(extensions, ".png");
|
||||
extensions = g_slist_append(extensions, ".xpm");
|
||||
#ifdef HAVE_RSVG
|
||||
extensions = g_slist_append(extensions, ".svg");
|
||||
#endif
|
||||
// if the icon name already contains one of the extensions (e.g. vlc.png instead of vlc) add a special entry
|
||||
for (GSList *ext = extensions; ext; ext = g_slist_next(ext)) {
|
||||
char *extension = (char *)ext->data;
|
||||
if (strlen(icon_name) > strlen(extension) &&
|
||||
strcmp(extension, icon_name + strlen(icon_name) - strlen(extension)) == 0) {
|
||||
extensions = g_slist_append(extensions, "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
const GSList *extensions = get_icon_extensions();
|
||||
|
||||
GSList *theme;
|
||||
|
||||
// Best size match
|
||||
// Contrary to the freedesktop spec, we are not choosing the closest icon in size, but the next larger icon
|
||||
// otherwise the quality is usually crap (for size 22, if you can choose 16 or 32, you're better with 32)
|
||||
// otherwise the quality is worse when scaling up (for size 22, if you can choose 16 or 32, you're better with 32)
|
||||
// We do fallback to the closest size if we cannot find a larger or equal icon
|
||||
|
||||
// These 3 variables are used for keeping the closest size match
|
||||
@@ -582,7 +598,7 @@ char *get_icon_path_helper(GSList *themes, const char *icon_name, int size)
|
||||
char *next_larger = NULL;
|
||||
GSList *next_larger_theme = NULL;
|
||||
|
||||
int file_name_size = 4096;
|
||||
size_t file_name_size = 4096;
|
||||
char *file_name = calloc(file_name_size, 1);
|
||||
|
||||
for (theme = themes; theme; theme = g_slist_next(theme)) {
|
||||
@@ -607,7 +623,7 @@ char *get_icon_path_helper(GSList *themes, const char *icon_name, int size)
|
||||
fprintf(stderr, "tint2: Searching directory: %s\n", ((IconThemeDir *)dir->data)->name);
|
||||
const GSList *base;
|
||||
for (base = basenames; base; base = g_slist_next(base)) {
|
||||
for (GSList *ext = extensions; ext; ext = g_slist_next(ext)) {
|
||||
for (const GSList *ext = extensions; ext; ext = g_slist_next(ext)) {
|
||||
char *base_name = (char *)base->data;
|
||||
char *theme_name = ((IconTheme *)theme->data)->name;
|
||||
char *dir_name = ((IconThemeDir *)dir->data)->name;
|
||||
@@ -621,7 +637,7 @@ char *get_icon_path_helper(GSList *themes, const char *icon_name, int size)
|
||||
}
|
||||
file_name[0] = 0;
|
||||
// filename = directory/$(themename)/subdirectory/iconname.extension
|
||||
sprintf(file_name, "%s/%s/%s/%s%s", base_name, theme_name, dir_name, icon_name, extension);
|
||||
snprintf(file_name, (size_t)file_name_size, "%s/%s/%s/%s%s", base_name, theme_name, dir_name, icon_name, extension);
|
||||
if (debug_icons)
|
||||
fprintf(stderr, "tint2: Checking %s\n", file_name);
|
||||
if (g_file_test(file_name, G_FILE_TEST_EXISTS)) {
|
||||
@@ -662,12 +678,10 @@ char *get_icon_path_helper(GSList *themes, const char *icon_name, int size)
|
||||
free(file_name);
|
||||
file_name = NULL;
|
||||
if (next_larger) {
|
||||
g_slist_free(extensions);
|
||||
free(best_file_name);
|
||||
return next_larger;
|
||||
}
|
||||
if (best_file_name) {
|
||||
g_slist_free(extensions);
|
||||
return best_file_name;
|
||||
}
|
||||
|
||||
@@ -676,18 +690,18 @@ char *get_icon_path_helper(GSList *themes, const char *icon_name, int size)
|
||||
if (debug_icons)
|
||||
fprintf(stderr, "tint2: Searching unthemed icons\n");
|
||||
for (const GSList *base = basenames; base; base = g_slist_next(base)) {
|
||||
for (GSList *ext = extensions; ext; ext = g_slist_next(ext)) {
|
||||
for (const GSList *ext = extensions; ext; ext = g_slist_next(ext)) {
|
||||
char *base_name = (char *)base->data;
|
||||
char *extension = (char *)ext->data;
|
||||
file_name = calloc(strlen(base_name) + strlen(icon_name) + strlen(extension) + 100, 1);
|
||||
size_t file_name_size2 = strlen(base_name) + strlen(icon_name) + strlen(extension) + 100;
|
||||
file_name = calloc(file_name_size2, 1);
|
||||
// filename = directory/iconname.extension
|
||||
sprintf(file_name, "%s/%s%s", base_name, icon_name, extension);
|
||||
snprintf(file_name, file_name_size2, "%s/%s%s", base_name, icon_name, extension);
|
||||
if (debug_icons)
|
||||
fprintf(stderr, "tint2: Checking %s\n", file_name);
|
||||
if (g_file_test(file_name, G_FILE_TEST_EXISTS)) {
|
||||
if (debug_icons)
|
||||
fprintf(stderr, "tint2: Found %s\n", file_name);
|
||||
g_slist_free(extensions);
|
||||
return file_name;
|
||||
} else {
|
||||
free(file_name);
|
||||
@@ -697,7 +711,6 @@ char *get_icon_path_helper(GSList *themes, const char *icon_name, int size)
|
||||
}
|
||||
}
|
||||
|
||||
g_slist_free(extensions);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -470,7 +470,7 @@ void launcher_load_icons(Launcher *launcher)
|
||||
launcherIcon->area.size_mode = LAYOUT_FIXED;
|
||||
launcherIcon->area._resize = NULL;
|
||||
launcherIcon->area._compute_desired_size = launcher_icon_compute_desired_size;
|
||||
sprintf(launcherIcon->area.name, "LauncherIcon %d", index);
|
||||
snprintf(launcherIcon->area.name, sizeof(launcherIcon->area.name), "LauncherIcon %d", index);
|
||||
launcherIcon->area.resize_needed = 0;
|
||||
launcherIcon->area.has_mouse_over_effect = panel_config.mouse_effects;
|
||||
launcherIcon->area.has_mouse_press_effect = launcherIcon->area.has_mouse_over_effect;
|
||||
|
||||
@@ -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 (task_update_title(task)) {
|
||||
if (g_tooltip.mapped && (g_tooltip.area == (Area *)task)) {
|
||||
tooltip_copy_text((Area *)task);
|
||||
tooltip_update_contents_for((Area *)task);
|
||||
tooltip_update();
|
||||
}
|
||||
if (taskbar_sort_method == TASKBAR_SORT_TITLE)
|
||||
@@ -723,7 +723,7 @@ void handle_panel_refresh()
|
||||
if (debug_frames) {
|
||||
for (int i = 0; i < num_panels; i++) {
|
||||
char path[256];
|
||||
sprintf(path, "tint2-%d-panel-%d-frame-%d.png", getpid(), i, frame);
|
||||
snprintf(path, sizeof(path), "tint2-%d-panel-%d-frame-%d.png", getpid(), i, frame);
|
||||
save_panel_screenshot(&panels[i], path);
|
||||
}
|
||||
}
|
||||
@@ -748,7 +748,7 @@ void run_tint2_event_loop()
|
||||
|
||||
// Wait for an event and handle it
|
||||
ts_event_read = 0;
|
||||
if (XPending(server.display) > 0 || select(max_fd + 1, &fds, 0, 0, get_next_timeout()) >= 0) {
|
||||
if (XPending(server.display) > 0 || select(max_fd + 1, &fds, 0, 0, get_duration_to_next_timer_expiration()) >= 0) {
|
||||
#ifdef HAVE_TRACING
|
||||
start_tracing((void*)run_tint2_event_loop);
|
||||
#endif
|
||||
|
||||
59
src/panel.c
59
src/panel.c
@@ -58,6 +58,7 @@ char *panel_window_name = NULL;
|
||||
gboolean debug_geometry;
|
||||
gboolean debug_gradients;
|
||||
gboolean startup_notifications;
|
||||
gboolean debug_thumbnails;
|
||||
|
||||
gboolean panel_autohide;
|
||||
int panel_autohide_show_timeout;
|
||||
@@ -129,8 +130,6 @@ void cleanup_panel()
|
||||
if (!panels)
|
||||
return;
|
||||
|
||||
cleanup_taskbar();
|
||||
|
||||
for (int i = 0; i < num_panels; i++) {
|
||||
Panel *p = &panels[i];
|
||||
|
||||
@@ -144,7 +143,7 @@ void cleanup_panel()
|
||||
if (p->main_win)
|
||||
XDestroyWindow(server.display, p->main_win);
|
||||
p->main_win = 0;
|
||||
stop_timeout(p->autohide_timeout);
|
||||
destroy_timer(&p->autohide_timer);
|
||||
cleanup_freespace(p);
|
||||
}
|
||||
|
||||
@@ -206,6 +205,7 @@ void init_panel()
|
||||
panels = calloc(num_panels, sizeof(Panel));
|
||||
for (int i = 0; i < num_panels; i++) {
|
||||
memcpy(&panels[i], &panel_config, sizeof(Panel));
|
||||
INIT_TIMER(panels[i].autohide_timer);
|
||||
}
|
||||
|
||||
fprintf(stderr,
|
||||
@@ -493,9 +493,11 @@ gboolean resize_panel(void *obj)
|
||||
}
|
||||
}
|
||||
|
||||
// Distribute the remaining size between tasks
|
||||
// Distribute the remaining size between taskbars
|
||||
if (num_tasks > 0) {
|
||||
int task_size = total_size / num_tasks;
|
||||
if (taskbar_alignment != ALIGN_LEFT)
|
||||
task_size = MIN(task_size, panel_horizontal ? panel_config.g_task.maximum_width : panel_config.g_task.maximum_height);
|
||||
for (int i = 0; i < panel->num_desktops; i++) {
|
||||
Taskbar *taskbar = &panel->taskbar[i];
|
||||
if (!taskbar->area.on_screen)
|
||||
@@ -512,6 +514,43 @@ gboolean resize_panel(void *obj)
|
||||
taskbar->area.height += task_size;
|
||||
}
|
||||
}
|
||||
int slack = total_size - task_size * num_tasks;
|
||||
if (taskbar_alignment == ALIGN_RIGHT) {
|
||||
for (int i = 0; i < panel->num_desktops; i++) {
|
||||
Taskbar *taskbar = &panel->taskbar[i];
|
||||
if (!taskbar->area.on_screen)
|
||||
continue;
|
||||
if (panel_horizontal)
|
||||
taskbar->area.width += slack;
|
||||
else
|
||||
taskbar->area.height += slack;
|
||||
break;
|
||||
}
|
||||
} else if (taskbar_alignment == ALIGN_CENTER) {
|
||||
slack /= 2;
|
||||
for (int i = 0; i < panel->num_desktops; i++) {
|
||||
Taskbar *taskbar = &panel->taskbar[i];
|
||||
if (!taskbar->area.on_screen)
|
||||
continue;
|
||||
if (panel_horizontal)
|
||||
taskbar->area.width += slack;
|
||||
else
|
||||
taskbar->area.height += slack;
|
||||
taskbar->area.alignment = ALIGN_RIGHT;
|
||||
break;
|
||||
}
|
||||
for (int i = panel->num_desktops - 1; i >= 0; i--) {
|
||||
Taskbar *taskbar = &panel->taskbar[i];
|
||||
if (!taskbar->area.on_screen)
|
||||
continue;
|
||||
if (panel_horizontal)
|
||||
taskbar->area.width += slack;
|
||||
else
|
||||
taskbar->area.height += slack;
|
||||
taskbar->area.alignment = ALIGN_LEFT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No tasks => expand the first visible taskbar
|
||||
for (int i = 0; i < panel->num_desktops; i++) {
|
||||
@@ -1020,15 +1059,15 @@ Button *click_button(Panel *panel, int x, int y)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void stop_autohide_timeout(Panel *p)
|
||||
void stop_autohide_timer(Panel *p)
|
||||
{
|
||||
stop_timeout(p->autohide_timeout);
|
||||
stop_timer(&p->autohide_timer);
|
||||
}
|
||||
|
||||
void autohide_show(void *p)
|
||||
{
|
||||
Panel *panel = (Panel *)p;
|
||||
stop_autohide_timeout(panel);
|
||||
stop_autohide_timer(panel);
|
||||
panel->is_hidden = 0;
|
||||
XMapSubwindows(server.display, panel->main_win); // systray windows
|
||||
set_panel_window_geometry(panel);
|
||||
@@ -1040,7 +1079,7 @@ void autohide_show(void *p)
|
||||
void autohide_hide(void *p)
|
||||
{
|
||||
Panel *panel = (Panel *)p;
|
||||
stop_autohide_timeout(panel);
|
||||
stop_autohide_timer(panel);
|
||||
set_panel_layer(panel, panel_layer);
|
||||
panel->is_hidden = TRUE;
|
||||
XUnmapSubwindows(server.display, panel->main_win); // systray windows
|
||||
@@ -1052,7 +1091,7 @@ void autohide_trigger_show(Panel *p)
|
||||
{
|
||||
if (!p)
|
||||
return;
|
||||
change_timeout(&p->autohide_timeout, panel_autohide_show_timeout, 0, autohide_show, p);
|
||||
change_timer(&p->autohide_timer, true, panel_autohide_show_timeout, 0, autohide_show, p);
|
||||
}
|
||||
|
||||
void autohide_trigger_hide(Panel *p)
|
||||
@@ -1067,7 +1106,7 @@ void autohide_trigger_hide(Panel *p)
|
||||
if (child)
|
||||
return; // mouse over one of the system tray icons
|
||||
|
||||
change_timeout(&p->autohide_timeout, panel_autohide_hide_timeout, 0, autohide_hide, p);
|
||||
change_timer(&p->autohide_timer, true, panel_autohide_hide_timeout, 0, autohide_hide, p);
|
||||
}
|
||||
|
||||
void shrink_panel(Panel *panel)
|
||||
|
||||
@@ -94,6 +94,7 @@ extern gboolean debug_geometry;
|
||||
extern gboolean debug_fps;
|
||||
extern double tracing_fps_threshold;
|
||||
extern gboolean debug_frames;
|
||||
extern gboolean debug_thumbnails;
|
||||
|
||||
typedef struct Panel {
|
||||
Area area;
|
||||
@@ -143,7 +144,7 @@ typedef struct Panel {
|
||||
gboolean is_hidden;
|
||||
int hidden_width, hidden_height;
|
||||
Pixmap hidden_pixmap;
|
||||
timeout *autohide_timeout;
|
||||
Timer autohide_timer;
|
||||
} Panel;
|
||||
|
||||
extern Panel panel_config;
|
||||
|
||||
@@ -543,11 +543,11 @@ static gint compare_traywindows(gconstpointer a, gconstpointer b)
|
||||
const TrayWindow *traywin_b = (const TrayWindow *)b;
|
||||
|
||||
#if 0
|
||||
// This breaks pygtk2 StatusIcon with blinking activated
|
||||
if (traywin_a->empty && !traywin_b->empty)
|
||||
return 1 * (systray.sort == SYSTRAY_SORT_RIGHT2LEFT ? -1 : 1);
|
||||
if (!traywin_a->empty && traywin_b->empty)
|
||||
return -1 * (systray.sort == SYSTRAY_SORT_RIGHT2LEFT ? -1 : 1);
|
||||
// This breaks pygtk2 StatusIcon with blinking activated
|
||||
if (traywin_a->empty && !traywin_b->empty)
|
||||
return 1 * (systray.sort == SYSTRAY_SORT_RIGHT2LEFT ? -1 : 1);
|
||||
if (!traywin_a->empty && traywin_b->empty)
|
||||
return -1 * (systray.sort == SYSTRAY_SORT_RIGHT2LEFT ? -1 : 1);
|
||||
#endif
|
||||
|
||||
if (systray.sort == SYSTRAY_SORT_ASCENDING || systray.sort == SYSTRAY_SORT_DESCENDING) {
|
||||
@@ -730,6 +730,8 @@ gboolean add_icon(Window win)
|
||||
traywin->pid = pid;
|
||||
traywin->name = name;
|
||||
traywin->chrono = chrono;
|
||||
INIT_TIMER(traywin->render_timer);
|
||||
INIT_TIMER(traywin->resize_timer);
|
||||
chrono++;
|
||||
|
||||
show(&systray.area);
|
||||
@@ -940,8 +942,8 @@ void remove_icon(TrayWindow *traywin)
|
||||
XDestroyWindow(server.display, traywin->parent);
|
||||
XSync(server.display, False);
|
||||
XSetErrorHandler(old);
|
||||
stop_timeout(traywin->render_timeout);
|
||||
stop_timeout(traywin->resize_timeout);
|
||||
destroy_timer(&traywin->render_timer);
|
||||
destroy_timer(&traywin->resize_timer);
|
||||
free(traywin->name);
|
||||
if (traywin->image) {
|
||||
imlib_context_set_image(traywin->image);
|
||||
@@ -1055,9 +1057,8 @@ void systray_reconfigure_event(TrayWindow *traywin, XEvent *e)
|
||||
if (traywin->bad_size_counter < min_bad_resize_events) {
|
||||
systray_resize_icon(traywin);
|
||||
} else {
|
||||
if (!traywin->resize_timeout)
|
||||
traywin->resize_timeout =
|
||||
add_timeout(fast_resize_period, 0, systray_resize_icon, traywin, &traywin->resize_timeout);
|
||||
if (!traywin->resize_timer.enabled_)
|
||||
change_timer(&traywin->resize_timer, true, fast_resize_period, 0, systray_resize_icon, traywin);
|
||||
}
|
||||
} else {
|
||||
if (traywin->bad_size_counter == max_bad_resize_events) {
|
||||
@@ -1071,14 +1072,13 @@ void systray_reconfigure_event(TrayWindow *traywin, XEvent *e)
|
||||
// FIXME Normally we should force the icon to resize fill_color to the size we resized it to when we
|
||||
// embedded it.
|
||||
// However this triggers a resize loop in new versions of GTK, which we must avoid.
|
||||
if (!traywin->resize_timeout)
|
||||
traywin->resize_timeout =
|
||||
add_timeout(slow_resize_period, 0, systray_resize_icon, traywin, &traywin->resize_timeout);
|
||||
if (!traywin->resize_timer.enabled_)
|
||||
change_timer(&traywin->resize_timer, true, slow_resize_period, 0, systray_resize_icon, traywin);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Correct size
|
||||
stop_timeout(traywin->resize_timeout);
|
||||
stop_timer(&traywin->resize_timer);
|
||||
}
|
||||
|
||||
// Resize and redraw the systray
|
||||
@@ -1135,9 +1135,8 @@ void systray_resize_request_event(TrayWindow *traywin, XEvent *e)
|
||||
if (traywin->bad_size_counter < min_bad_resize_events) {
|
||||
systray_resize_icon(traywin);
|
||||
} else {
|
||||
if (!traywin->resize_timeout)
|
||||
traywin->resize_timeout =
|
||||
add_timeout(fast_resize_period, 0, systray_resize_icon, traywin, &traywin->resize_timeout);
|
||||
if (!traywin->resize_timer.enabled_)
|
||||
change_timer(&traywin->resize_timer, true, fast_resize_period, 0, systray_resize_icon, traywin);
|
||||
}
|
||||
} else {
|
||||
if (traywin->bad_size_counter == max_bad_resize_events) {
|
||||
@@ -1150,14 +1149,13 @@ void systray_resize_request_event(TrayWindow *traywin, XEvent *e)
|
||||
// Delayed resize
|
||||
// FIXME Normally we should force the icon to resize to the size we resized it to when we embedded it.
|
||||
// However this triggers a resize loop in some versions of GTK, which we must avoid.
|
||||
if (!traywin->resize_timeout)
|
||||
traywin->resize_timeout =
|
||||
add_timeout(slow_resize_period, 0, systray_resize_icon, traywin, &traywin->resize_timeout);
|
||||
if (!traywin->resize_timer.enabled_)
|
||||
change_timer(&traywin->resize_timer, true, slow_resize_period, 0, systray_resize_icon, traywin);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Correct size
|
||||
stop_timeout(traywin->resize_timeout);
|
||||
stop_timer(&traywin->resize_timer);
|
||||
}
|
||||
|
||||
// Resize and redraw the systray
|
||||
@@ -1224,8 +1222,7 @@ void systray_render_icon_composited(void *t)
|
||||
if (compare_timespecs(&earliest_render, &now) > 0) {
|
||||
traywin->num_fast_renders++;
|
||||
if (traywin->num_fast_renders > max_fast_refreshes) {
|
||||
traywin->render_timeout =
|
||||
add_timeout(min_refresh_period, 0, systray_render_icon_composited, traywin, &traywin->render_timeout);
|
||||
change_timer(&traywin->render_timer, true, min_refresh_period, 0, systray_render_icon_composited, traywin);
|
||||
if (systray_profile)
|
||||
fprintf(stderr,
|
||||
YELLOW "[%f] %s:%d win = %lu (%s) delaying rendering" RESET "\n",
|
||||
@@ -1244,8 +1241,7 @@ void systray_render_icon_composited(void *t)
|
||||
|
||||
if (traywin->width == 0 || traywin->height == 0) {
|
||||
// reschedule rendering since the geometry information has not yet been processed (can happen on slow cpu)
|
||||
traywin->render_timeout =
|
||||
add_timeout(min_refresh_period, 0, systray_render_icon_composited, traywin, &traywin->render_timeout);
|
||||
change_timer(&traywin->render_timer, true, min_refresh_period, 0, systray_render_icon_composited, traywin);
|
||||
if (systray_profile)
|
||||
fprintf(stderr,
|
||||
YELLOW "[%f] %s:%d win = %lu (%s) delaying rendering" RESET "\n",
|
||||
@@ -1257,10 +1253,7 @@ void systray_render_icon_composited(void *t)
|
||||
return;
|
||||
}
|
||||
|
||||
if (traywin->render_timeout) {
|
||||
stop_timeout(traywin->render_timeout);
|
||||
traywin->render_timeout = NULL;
|
||||
}
|
||||
stop_timer(&traywin->render_timer);
|
||||
|
||||
// good systray icons support 32 bit depth, but some icons are still 24 bit.
|
||||
// We create a heuristic mask for these icons, i.e. we get the rgb value in the top left corner, and
|
||||
@@ -1423,9 +1416,7 @@ void systray_render_icon(void *t)
|
||||
// __LINE__,
|
||||
// traywin->win,
|
||||
// traywin->name);
|
||||
stop_timeout(traywin->render_timeout);
|
||||
traywin->render_timeout =
|
||||
add_timeout(min_refresh_period, 0, systray_render_icon, traywin, &traywin->render_timeout);
|
||||
change_timer(&traywin->render_timer, true, min_refresh_period, 0, systray_render_icon, traywin);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1448,19 +1439,13 @@ void systray_render_icon(void *t)
|
||||
unsigned int width, height, depth;
|
||||
Window root;
|
||||
if (!XGetGeometry(server.display, traywin->win, &root, &xpos, &ypos, &width, &height, &border_width, &depth)) {
|
||||
stop_timeout(traywin->render_timeout);
|
||||
if (!traywin->render_timeout)
|
||||
traywin->render_timeout =
|
||||
add_timeout(min_refresh_period, 0, systray_render_icon, traywin, &traywin->render_timeout);
|
||||
change_timer(&traywin->render_timer, true, min_refresh_period, 0, systray_render_icon, traywin);
|
||||
systray_render_icon_from_image(traywin);
|
||||
XSetErrorHandler(old);
|
||||
return;
|
||||
} else {
|
||||
if (xpos != 0 || ypos != 0 || width != traywin->width || height != traywin->height) {
|
||||
stop_timeout(traywin->render_timeout);
|
||||
if (!traywin->render_timeout)
|
||||
traywin->render_timeout =
|
||||
add_timeout(min_refresh_period, 0, systray_render_icon, traywin, &traywin->render_timeout);
|
||||
change_timer(&traywin->render_timer, true, min_refresh_period, 0, systray_render_icon, traywin);
|
||||
systray_render_icon_from_image(traywin);
|
||||
if (systray_profile)
|
||||
fprintf(stderr,
|
||||
|
||||
@@ -56,11 +56,11 @@ typedef struct {
|
||||
// Members used for rendering
|
||||
struct timespec time_last_render;
|
||||
int num_fast_renders;
|
||||
timeout *render_timeout;
|
||||
Timer render_timer;
|
||||
// Members used for resizing
|
||||
int bad_size_counter;
|
||||
struct timespec time_last_resize;
|
||||
timeout *resize_timeout;
|
||||
Timer resize_timer;
|
||||
// Icon contents if we are compositing the icon, otherwise null
|
||||
Imlib_Image image;
|
||||
// XDamage
|
||||
|
||||
@@ -35,11 +35,13 @@
|
||||
#include "tooltip.h"
|
||||
#include "window.h"
|
||||
|
||||
timeout *urgent_timeout;
|
||||
Timer urgent_timer;
|
||||
GSList *urgent_list;
|
||||
|
||||
void task_dump_geometry(void *obj, int indent);
|
||||
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)
|
||||
{
|
||||
@@ -47,6 +49,17 @@ char *task_get_tooltip(void *obj)
|
||||
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)
|
||||
{
|
||||
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._dump_geometry = task_dump_geometry;
|
||||
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.desktop = get_window_desktop(win);
|
||||
task_template.area.panel = &panels[monitor];
|
||||
@@ -93,10 +107,6 @@ Task *add_task(Window win)
|
||||
(int)win,
|
||||
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();
|
||||
for (int j = 0; j < panels[monitor].num_desktops; 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._is_under_mouse = full_width_area_is_under_mouse;
|
||||
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->desktop = task_template.desktop;
|
||||
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->current_state = TASK_UNDEFINED; // to update the current state later in set_task_state...
|
||||
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->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_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) {
|
||||
task_instance->icon[k] = task_template.icon[k];
|
||||
task_instance->icon_hover[k] = task_template.icon_hover[k];
|
||||
@@ -186,9 +201,6 @@ void remove_task(Task *task)
|
||||
if (!task)
|
||||
return;
|
||||
|
||||
// fprintf(stderr, "tint2: %s %d: win = %ld, task = %s\n", __func__, __LINE__, task->win, task->title ? task->title :
|
||||
// "??");
|
||||
|
||||
if (taskbar_mode == MULTI_DESKTOP) {
|
||||
Panel *panel = task->area.panel;
|
||||
panel->area.resize_needed = 1;
|
||||
@@ -198,9 +210,10 @@ void remove_task(Task *task)
|
||||
|
||||
// free title and icon just for the first task
|
||||
// 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)
|
||||
free(task->title);
|
||||
if (task->thumbnail)
|
||||
cairo_surface_destroy(task->thumbnail);
|
||||
task_remove_icon(task);
|
||||
|
||||
GPtrArray *task_buttons = g_hash_table_lookup(win_to_task, &win);
|
||||
@@ -212,6 +225,8 @@ void remove_task(Task *task)
|
||||
task_drag = 0;
|
||||
if (g_slist_find(urgent_list, task2))
|
||||
del_urgent(task2);
|
||||
if (g_tooltip.area == &task2->area)
|
||||
tooltip_hide(NULL);
|
||||
remove_area((Area *)task2);
|
||||
free(task2);
|
||||
}
|
||||
@@ -266,36 +281,23 @@ gboolean task_update_title(Task *task)
|
||||
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;
|
||||
|
||||
if (!img) {
|
||||
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 (len > 0) {
|
||||
// get ARGB icon
|
||||
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) {
|
||||
DATA32 icon_data[w * h];
|
||||
for (int j = 0; j < w * h; ++j)
|
||||
icon_data[j] = tmp_data[j];
|
||||
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);
|
||||
@@ -303,7 +305,7 @@ void task_update_icon(Task *task)
|
||||
}
|
||||
|
||||
if (!img) {
|
||||
XWMHints *hints = XGetWMHints(server.display, task->win);
|
||||
XWMHints *hints = XGetWMHints(server.display, win);
|
||||
if (hints) {
|
||||
if (hints->flags & IconPixmapHint && hints->icon_pixmap != 0) {
|
||||
// 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);
|
||||
imlib_context_set_drawable(hints->icon_pixmap);
|
||||
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);
|
||||
}
|
||||
@@ -332,6 +327,44 @@ void task_update_icon(Task *task)
|
||||
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
|
||||
imlib_context_set_image(img);
|
||||
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_height = imlib_image_get_height();
|
||||
for (int k = 0; k < TASK_STATE_COUNT; ++k) {
|
||||
imlib_context_set_image(orig_image);
|
||||
task->icon[k] = imlib_clone_image();
|
||||
imlib_context_set_image(task->icon[k]);
|
||||
DATA32 *data32;
|
||||
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);
|
||||
}
|
||||
task->icon[k] = adjust_icon(orig_image,
|
||||
panel->g_task.alpha[k],
|
||||
panel->g_task.saturation[k],
|
||||
panel->g_task.brightness[k] != 0);
|
||||
if (panel_config.mouse_effects) {
|
||||
task->icon_hover[k] = adjust_icon(task->icon[k],
|
||||
panel_config.mouse_over_alpha,
|
||||
@@ -376,9 +399,12 @@ void task_update_icon(Task *task)
|
||||
GPtrArray *task_buttons = get_task_buttons(task->win);
|
||||
if (task_buttons) {
|
||||
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_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) {
|
||||
task2->icon[k] = task->icon[k];
|
||||
task2->icon_hover[k] = task->icon_hover[k];
|
||||
@@ -437,7 +463,7 @@ void draw_task(void *obj, cairo_t *c)
|
||||
pango_layout_set_font_description(layout, panel->g_task.font_desc);
|
||||
pango_layout_set_text(layout, task->title, -1);
|
||||
|
||||
pango_layout_set_width(layout, ((Taskbar *)task->area.parent)->text_width * PANGO_SCALE);
|
||||
pango_layout_set_width(layout, (((Taskbar *)task->area.parent)->text_width + 1) * PANGO_SCALE);
|
||||
pango_layout_set_height(layout, panel->g_task.text_height * PANGO_SCALE);
|
||||
pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
|
||||
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
|
||||
@@ -484,6 +510,24 @@ void task_dump_geometry(void *obj, int indent)
|
||||
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)
|
||||
{
|
||||
Task *task = (Task *)obj;
|
||||
@@ -591,7 +635,6 @@ void reset_active_task()
|
||||
}
|
||||
|
||||
Window w1 = get_active_window();
|
||||
// fprintf(stderr, "tint2: Change active task %ld\n", w1);
|
||||
|
||||
if (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)
|
||||
{
|
||||
if (!task || state == TASK_UNDEFINED || state >= TASK_STATE_COUNT)
|
||||
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) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &task->last_activation_time);
|
||||
if (taskbar_sort_method == TASKBAR_SORT_LRU || taskbar_sort_method == TASKBAR_SORT_MRU) {
|
||||
@@ -701,8 +782,8 @@ void add_urgent(Task *task)
|
||||
// not yet in the list, so we have to add it
|
||||
urgent_list = g_slist_prepend(urgent_list, task);
|
||||
|
||||
if (!urgent_timeout)
|
||||
urgent_timeout = add_timeout(10, 1000, blink_urgent, 0, &urgent_timeout);
|
||||
if (!urgent_timer.enabled_)
|
||||
change_timer(&urgent_timer, true, 10, 1000, blink_urgent, 0);
|
||||
|
||||
Panel *panel = task->area.panel;
|
||||
if (panel->is_hidden)
|
||||
@@ -712,10 +793,8 @@ void add_urgent(Task *task)
|
||||
void del_urgent(Task *task)
|
||||
{
|
||||
urgent_list = g_slist_remove(urgent_list, task);
|
||||
if (!urgent_list) {
|
||||
stop_timeout(urgent_timeout);
|
||||
urgent_timeout = NULL;
|
||||
}
|
||||
if (!urgent_list)
|
||||
stop_timer(&urgent_timer);
|
||||
}
|
||||
|
||||
void task_handle_mouse_event(Task *task, MouseAction action)
|
||||
@@ -783,7 +862,6 @@ void task_handle_mouse_event(Task *task, MouseAction action)
|
||||
|
||||
void task_update_desktop(Task *task)
|
||||
{
|
||||
// fprintf(stderr, "tint2: %s %d:\n", __func__, __LINE__);
|
||||
Window win = task->win;
|
||||
remove_task(task);
|
||||
task = add_task(win);
|
||||
|
||||
@@ -42,10 +42,13 @@ typedef struct GlobalTask {
|
||||
// starting position for text ~ task_padding + task_border + icon_size
|
||||
double text_posx, text_height;
|
||||
gboolean has_font;
|
||||
gboolean has_content_tint;
|
||||
PangoFontDescription *font_desc;
|
||||
Color font[TASK_STATE_COUNT];
|
||||
int config_font_mask;
|
||||
gboolean tooltip_enabled;
|
||||
gboolean thumbnail_enabled;
|
||||
int thumbnail_width;
|
||||
} GlobalTask;
|
||||
|
||||
// Stores information about a task.
|
||||
@@ -61,6 +64,9 @@ typedef struct Task {
|
||||
Imlib_Image icon_press[TASK_STATE_COUNT];
|
||||
unsigned int icon_width;
|
||||
unsigned int icon_height;
|
||||
Color icon_color;
|
||||
Color icon_color_hover;
|
||||
Color icon_color_press;
|
||||
char *title;
|
||||
int urgent_tick;
|
||||
// These may not be up-to-date
|
||||
@@ -74,9 +80,11 @@ typedef struct Task {
|
||||
double _text_posy;
|
||||
int _icon_x;
|
||||
int _icon_y;
|
||||
cairo_surface_t *thumbnail;
|
||||
double thumbnail_last_update;
|
||||
} Task;
|
||||
|
||||
extern timeout *urgent_timeout;
|
||||
extern Timer urgent_timer;
|
||||
extern GSList *urgent_list;
|
||||
|
||||
Task *add_task(Window win);
|
||||
@@ -91,6 +99,7 @@ gboolean task_update_title(Task *task);
|
||||
void reset_active_task();
|
||||
void set_task_state(Task *task, TaskState state);
|
||||
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),
|
||||
// returns a pointer to the Task for the active window on the same taskbar.
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "window.h"
|
||||
#include "panel.h"
|
||||
#include "strnatcmp.h"
|
||||
#include "tooltip.h"
|
||||
|
||||
GHashTable *win_to_task;
|
||||
|
||||
@@ -46,8 +47,12 @@ gboolean hide_taskbar_if_empty;
|
||||
gboolean always_show_all_desktop_tasks;
|
||||
TaskbarSortMethod taskbar_sort_method;
|
||||
Alignment taskbar_alignment;
|
||||
static Timer thumbnail_update_timer_all;
|
||||
static Timer thumbnail_update_timer_active;
|
||||
static Timer thumbnail_update_timer_tooltip;
|
||||
|
||||
static GList *taskbar_task_orderings = NULL;
|
||||
static GList *taskbar_thumbnail_jobs_done = NULL;
|
||||
|
||||
void taskbar_init_fonts();
|
||||
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.
|
||||
void taskbar_remove_task(Window *win);
|
||||
|
||||
void taskbar_update_thumbnails(void *arg);
|
||||
|
||||
guint win_hash(gconstpointer key)
|
||||
{
|
||||
return *((const Window *)key);
|
||||
@@ -73,7 +80,6 @@ void free_ptr_array(gpointer data)
|
||||
void default_taskbar()
|
||||
{
|
||||
win_to_task = NULL;
|
||||
urgent_timeout = NULL;
|
||||
urgent_list = NULL;
|
||||
taskbar_enabled = FALSE;
|
||||
taskbar_distribute_size = FALSE;
|
||||
@@ -82,6 +88,7 @@ void default_taskbar()
|
||||
hide_task_diff_monitor = FALSE;
|
||||
hide_taskbar_if_empty = FALSE;
|
||||
always_show_all_desktop_tasks = FALSE;
|
||||
taskbar_thumbnail_jobs_done = NULL;
|
||||
taskbar_sort_method = TASKBAR_NOSORT;
|
||||
taskbar_alignment = ALIGN_LEFT;
|
||||
default_taskbarname();
|
||||
@@ -107,7 +114,10 @@ void taskbar_save_orderings()
|
||||
for (int j = 0; j < panel->num_desktops; j++) {
|
||||
Taskbar *taskbar = &panel->taskbar[j];
|
||||
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;
|
||||
Window *window = calloc(1, sizeof(Window));
|
||||
*window = t->win;
|
||||
@@ -120,6 +130,10 @@ void taskbar_save_orderings()
|
||||
|
||||
void cleanup_taskbar()
|
||||
{
|
||||
destroy_timer(&thumbnail_update_timer_all);
|
||||
destroy_timer(&thumbnail_update_timer_active);
|
||||
destroy_timer(&thumbnail_update_timer_tooltip);
|
||||
g_list_free(taskbar_thumbnail_jobs_done);
|
||||
taskbar_save_orderings();
|
||||
if (win_to_task) {
|
||||
while (g_hash_table_size(win_to_task)) {
|
||||
@@ -152,7 +166,7 @@ void cleanup_taskbar()
|
||||
g_slist_free(urgent_list);
|
||||
urgent_list = NULL;
|
||||
|
||||
stop_timeout(urgent_timeout);
|
||||
destroy_timer(&urgent_timer);
|
||||
|
||||
for (int state = 0; state < TASK_STATE_COUNT; state++) {
|
||||
g_list_free(panel_config.g_task.gradient[state]);
|
||||
@@ -166,10 +180,18 @@ void cleanup_taskbar()
|
||||
|
||||
void init_taskbar()
|
||||
{
|
||||
INIT_TIMER(urgent_timer);
|
||||
INIT_TIMER(thumbnail_update_timer_all);
|
||||
INIT_TIMER(thumbnail_update_timer_active);
|
||||
INIT_TIMER(thumbnail_update_timer_tooltip);
|
||||
|
||||
if (!panel_config.g_task.has_text && !panel_config.g_task.has_icon) {
|
||||
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)
|
||||
win_to_task = g_hash_table_new_full(win_hash, win_compare, free, free_ptr_array);
|
||||
|
||||
@@ -301,8 +323,9 @@ void init_taskbar_panel(void *p)
|
||||
if (!panel->g_task.background[j])
|
||||
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) {
|
||||
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_");
|
||||
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_");
|
||||
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]->border.radius = panel->g_task.area.height / 2;
|
||||
@@ -353,6 +376,22 @@ void init_taskbar_panel(void *p)
|
||||
}
|
||||
}
|
||||
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_timer(mode == THUMB_MODE_ALL ? &thumbnail_update_timer_all :
|
||||
mode == THUMB_MODE_ACTIVE_WINDOW ? &thumbnail_update_timer_active : &thumbnail_update_timer_tooltip,
|
||||
true,
|
||||
mode == THUMB_MODE_TOOLTIP_WINDOW ? 1000 : 500,
|
||||
mode == THUMB_MODE_ALL ? 10 * 1000 : 0,
|
||||
taskbar_update_thumbnails,
|
||||
(void *)(long)mode);
|
||||
}
|
||||
|
||||
void taskbar_init_fonts()
|
||||
@@ -422,8 +461,8 @@ int compare_windows(const void *a, const void *b)
|
||||
if (!sort_windows)
|
||||
return 0;
|
||||
|
||||
int ia = *(int*)a;
|
||||
int ib = *(int*)b;
|
||||
int ia = *(int *)a;
|
||||
int ib = *(int *)b;
|
||||
|
||||
Window wina = sort_windows[ia];
|
||||
Window winb = sort_windows[ib];
|
||||
@@ -433,7 +472,7 @@ int compare_windows(const void *a, const void *b)
|
||||
int posb = -1;
|
||||
int pos = 0;
|
||||
for (GList *item = (GList *)order->data; item; item = item->next, pos++) {
|
||||
Window win = *(Window*)item->data;
|
||||
Window win = *(Window *)item->data;
|
||||
if (win == wina)
|
||||
posa = pos;
|
||||
if (win == winb)
|
||||
@@ -467,7 +506,6 @@ void taskbar_refresh_tasklist()
|
||||
{
|
||||
if (!taskbar_enabled)
|
||||
return;
|
||||
// fprintf(stderr, "tint2: %s %d:\n", __func__, __LINE__);
|
||||
|
||||
int num_results;
|
||||
Window *win = server_get_property(server.root_win, server.atom._NET_CLIENT_LIST, XA_WINDOW, &num_results);
|
||||
@@ -521,7 +559,6 @@ gboolean resize_taskbar(void *obj)
|
||||
Taskbar *taskbar = (Taskbar *)obj;
|
||||
Panel *panel = (Panel *)taskbar->area.panel;
|
||||
|
||||
// fprintf(stderr, "tint2: resize_taskbar %d %d\n", taskbar->area.posx, taskbar->area.posy);
|
||||
if (panel_horizontal) {
|
||||
relayout_with_constraint(&taskbar->area, panel->g_task.maximum_width);
|
||||
|
||||
@@ -779,3 +816,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_timer(&thumbnail_update_timer_all, true, 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_timer(&thumbnail_update_timer_all, true, 10 * 1000, 10 * 1000, taskbar_update_thumbnails, arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,12 @@ typedef enum TaskbarSortMethod {
|
||||
TASKBAR_SORT_MRU,
|
||||
} TaskbarSortMethod;
|
||||
|
||||
typedef enum ThumbnailUpdateMode {
|
||||
THUMB_MODE_ACTIVE_WINDOW = 0,
|
||||
THUMB_MODE_TOOLTIP_WINDOW,
|
||||
THUMB_MODE_ALL
|
||||
} ThumbnailUpdateMode;
|
||||
|
||||
typedef struct {
|
||||
Area area;
|
||||
gchar *name;
|
||||
@@ -72,6 +78,7 @@ void init_taskbar_panel(void *p);
|
||||
|
||||
gboolean resize_taskbar(void *obj);
|
||||
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.
|
||||
void taskbar_refresh_tasklist();
|
||||
|
||||
@@ -23,8 +23,12 @@ set(SOURCES ../util/common.c
|
||||
../util/strnatcmp.c
|
||||
../util/cache.c
|
||||
../util/timer.c
|
||||
../util/test.c
|
||||
../util/print.c
|
||||
../util/signals.c
|
||||
../config.c
|
||||
../server.c
|
||||
../util/server.c
|
||||
../util/strlcat.c
|
||||
../launcher/apps-common.c
|
||||
../launcher/icon-theme-common.c
|
||||
md4.c
|
||||
|
||||
@@ -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_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_right;
|
||||
*background_border_sides_right, *background_border_content_tint_weight, *background_fill_content_tint_weight;
|
||||
|
||||
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_DOUBLE,
|
||||
GTK_TYPE_DOUBLE);
|
||||
|
||||
GtkWidget *table, *label, *button;
|
||||
int row, col;
|
||||
@@ -175,6 +177,19 @@ void create_background(GtkWidget *parent)
|
||||
col++;
|
||||
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;
|
||||
label = gtk_label_new(_("Border color"));
|
||||
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
|
||||
@@ -189,6 +204,19 @@ void create_background(GtkWidget *parent)
|
||||
col++;
|
||||
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;
|
||||
label = gtk_label_new(_("Gradient"));
|
||||
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_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_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);
|
||||
}
|
||||
@@ -750,6 +780,9 @@ void background_update(GtkWidget *widget, gpointer data)
|
||||
r = gtk_spin_button_get_value(GTK_SPIN_BUTTON(background_corner_radius));
|
||||
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 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));
|
||||
@@ -836,6 +869,10 @@ void background_update(GtkWidget *widget, gpointer data)
|
||||
sideLeft,
|
||||
bgColBorderSidesRight,
|
||||
sideRight,
|
||||
bgColFillWeight,
|
||||
fill_weight,
|
||||
bgColBorderWeight,
|
||||
border_weight,
|
||||
-1);
|
||||
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_right, 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;
|
||||
|
||||
@@ -875,6 +914,9 @@ void current_background_changed(GtkWidget *widget, gpointer data)
|
||||
int r;
|
||||
int b;
|
||||
|
||||
double fill_weight;
|
||||
double border_weight;
|
||||
|
||||
gboolean sideTop;
|
||||
gboolean sideBottom;
|
||||
gboolean sideLeft;
|
||||
@@ -938,6 +980,10 @@ void current_background_changed(GtkWidget *widget, gpointer data)
|
||||
&sideLeft,
|
||||
bgColBorderSidesRight,
|
||||
&sideRight,
|
||||
bgColFillWeight,
|
||||
&fill_weight,
|
||||
bgColBorderWeight,
|
||||
&border_weight,
|
||||
-1);
|
||||
|
||||
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_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, borderColor);
|
||||
g_boxed_free(GDK_TYPE_COLOR, fillColorOver);
|
||||
|
||||
@@ -100,7 +100,7 @@ char *file_name_from_path(const char *filepath)
|
||||
|
||||
void make_backup(const char *filepath)
|
||||
{
|
||||
gchar *backup_path = g_strdup_printf("%s.backup.%ld", filepath, time(NULL));
|
||||
gchar *backup_path = g_strdup_printf("%s.backup.%lld", filepath, (long long)time(NULL));
|
||||
copy_file(filepath, backup_path);
|
||||
g_free(backup_path);
|
||||
}
|
||||
|
||||
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
|
||||
rm ${lang}.pox
|
||||
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
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "gui.h"
|
||||
#include "background_gui.h"
|
||||
#include "gradient_gui.h"
|
||||
#include "strlcat.h"
|
||||
|
||||
GtkWidget *panel_width, *panel_height, *panel_margin_x, *panel_margin_y, *panel_padding_x, *panel_padding_y,
|
||||
*panel_spacing;
|
||||
@@ -97,7 +98,7 @@ GtkWidget *systray_background, *systray_monitor, *systray_name_filter;
|
||||
|
||||
// tooltip
|
||||
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 *tooltip_background;
|
||||
|
||||
@@ -180,7 +181,7 @@ void applyClicked(GtkWidget *widget, gpointer data)
|
||||
gchar *filepath = get_current_theme_path();
|
||||
if (filepath) {
|
||||
if (config_is_manual(filepath)) {
|
||||
gchar *backup_path = g_strdup_printf("%s.backup.%ld", filepath, time(NULL));
|
||||
gchar *backup_path = g_strdup_printf("%s.backup.%lld", filepath, (long long)time(NULL));
|
||||
copy_file(filepath, backup_path);
|
||||
g_free(backup_path);
|
||||
}
|
||||
@@ -1256,7 +1257,8 @@ gboolean panel_contains(const char *value)
|
||||
|
||||
char *get_panel_items()
|
||||
{
|
||||
char *result = calloc(1, 256 * sizeof(char));
|
||||
size_t buf_size = 256;
|
||||
char *result = calloc(buf_size, 1);
|
||||
GtkTreeModel *model = GTK_TREE_MODEL(panel_items);
|
||||
|
||||
GtkTreeIter i;
|
||||
@@ -1267,7 +1269,7 @@ char *get_panel_items()
|
||||
while (1) {
|
||||
gchar *v;
|
||||
gtk_tree_model_get(model, &i, itemsColValue, &v, -1);
|
||||
strcat(result, v);
|
||||
strlcat(result, v, buf_size);
|
||||
|
||||
if (!gtk_tree_model_iter_next(model, &i)) {
|
||||
break;
|
||||
@@ -1312,19 +1314,19 @@ void set_panel_items(const char *items)
|
||||
} else if (v == ':') {
|
||||
separator_index++;
|
||||
buffer[0] = 0;
|
||||
sprintf(buffer, "%s %d", _("Separator"), separator_index + 1);
|
||||
snprintf(buffer, sizeof(buffer), "%s %d", _("Separator"), separator_index + 1);
|
||||
name = buffer;
|
||||
value = ":";
|
||||
} else if (v == 'E') {
|
||||
execp_index++;
|
||||
buffer[0] = 0;
|
||||
sprintf(buffer, "%s %d", _("Executor"), execp_index + 1);
|
||||
snprintf(buffer, sizeof(buffer), "%s %d", _("Executor"), execp_index + 1);
|
||||
name = buffer;
|
||||
value = "E";
|
||||
} else if (v == 'P') {
|
||||
button_index++;
|
||||
buffer[0] = 0;
|
||||
sprintf(buffer, "%s %d", _("Button"), button_index + 1);
|
||||
snprintf(buffer, sizeof(buffer), "%s %d", _("Button"), button_index + 1);
|
||||
name = buffer;
|
||||
value = "P";
|
||||
} else {
|
||||
@@ -3288,6 +3290,36 @@ void create_task(GtkWidget *parent)
|
||||
"over task buttons."),
|
||||
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;
|
||||
label = gtk_label_new(_("Maximum width"));
|
||||
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
|
||||
@@ -4067,7 +4099,7 @@ void create_separator(GtkWidget *notebook, int i)
|
||||
Separator *separator = &g_array_index(separators, Separator, i);
|
||||
|
||||
separator->name[0] = 0;
|
||||
sprintf(separator->name, "%s %d", _("Separator"), i + 1);
|
||||
snprintf(separator->name, sizeof(separator->name), "%s %d", _("Separator"), i + 1);
|
||||
separator->page_label = gtk_label_new(separator->name);
|
||||
gtk_widget_show(separator->page_label);
|
||||
separator->page_separator = gtk_vbox_new(FALSE, DEFAULT_HOR_SPACING);
|
||||
@@ -4193,7 +4225,7 @@ void create_execp(GtkWidget *notebook, int i)
|
||||
Executor *executor = &g_array_index(executors, Executor, i);
|
||||
|
||||
executor->name[0] = 0;
|
||||
sprintf(executor->name, "%s %d", _("Executor"), i + 1);
|
||||
snprintf(executor->name, sizeof(executor->name), "%s %d", _("Executor"), i + 1);
|
||||
executor->page_label = gtk_label_new(executor->name);
|
||||
gtk_widget_show(executor->page_label);
|
||||
executor->page_execp = gtk_vbox_new(FALSE, DEFAULT_HOR_SPACING);
|
||||
@@ -4614,7 +4646,7 @@ void create_button(GtkWidget *notebook, int i)
|
||||
Button *button = &g_array_index(buttons, Button, i);
|
||||
|
||||
button->name[0] = 0;
|
||||
sprintf(button->name, "%s %d", _("Button"), i + 1);
|
||||
snprintf(button->name, sizeof(button->name), "%s %d", _("Button"), i + 1);
|
||||
button->page_label = gtk_label_new(button->name);
|
||||
gtk_widget_show(button->page_label);
|
||||
button->page_button = gtk_vbox_new(FALSE, DEFAULT_HOR_SPACING);
|
||||
@@ -5003,7 +5035,7 @@ void separator_update_indices()
|
||||
{
|
||||
for (int i = 0; i < separators->len; i++) {
|
||||
Separator *separator = &g_array_index(separators, Separator, i);
|
||||
sprintf(separator->name, "%s %d", _("Separator"), i + 1);
|
||||
snprintf(separator->name, sizeof(separator->name), "%s %d", _("Separator"), i + 1);
|
||||
gtk_label_set_text(GTK_LABEL(separator->page_label), separator->name);
|
||||
}
|
||||
|
||||
@@ -5021,7 +5053,7 @@ void separator_update_indices()
|
||||
separator_index++;
|
||||
char buffer[256];
|
||||
buffer[0] = 0;
|
||||
sprintf(buffer, "%s %d", _("Separator"), separator_index + 1);
|
||||
snprintf(buffer, sizeof(buffer), "%s %d", _("Separator"), separator_index + 1);
|
||||
|
||||
gtk_list_store_set(panel_items, &iter, itemsColName, buffer, -1);
|
||||
}
|
||||
@@ -5035,7 +5067,7 @@ void execp_update_indices()
|
||||
{
|
||||
for (int i = 0; i < executors->len; i++) {
|
||||
Executor *executor = &g_array_index(executors, Executor, i);
|
||||
sprintf(executor->name, "%s %d", _("Executor"), i + 1);
|
||||
snprintf(executor->name, sizeof(executor->name), "%s %d", _("Executor"), i + 1);
|
||||
gtk_label_set_text(GTK_LABEL(executor->page_label), executor->name);
|
||||
}
|
||||
|
||||
@@ -5053,7 +5085,7 @@ void execp_update_indices()
|
||||
execp_index++;
|
||||
char buffer[256];
|
||||
buffer[0] = 0;
|
||||
sprintf(buffer, "%s %d", _("Executor"), execp_index + 1);
|
||||
snprintf(buffer, sizeof(buffer), "%s %d", _("Executor"), execp_index + 1);
|
||||
|
||||
gtk_list_store_set(panel_items, &iter, itemsColName, buffer, -1);
|
||||
}
|
||||
@@ -5067,7 +5099,7 @@ void button_update_indices()
|
||||
{
|
||||
for (int i = 0; i < buttons->len; i++) {
|
||||
Button *button = &g_array_index(buttons, Button, i);
|
||||
sprintf(button->name, "%s %d", _("Button"), i + 1);
|
||||
snprintf(button->name, sizeof(button->name), "%s %d", _("Button"), i + 1);
|
||||
gtk_label_set_text(GTK_LABEL(button->page_label), button->name);
|
||||
}
|
||||
|
||||
@@ -5085,7 +5117,7 @@ void button_update_indices()
|
||||
button_index++;
|
||||
char buffer[256];
|
||||
buffer[0] = 0;
|
||||
sprintf(buffer, "%s %d", _("Button"), button_index + 1);
|
||||
snprintf(buffer, sizeof(buffer), "%s %d", _("Button"), button_index + 1);
|
||||
|
||||
gtk_list_store_set(panel_items, &iter, itemsColName, buffer, -1);
|
||||
}
|
||||
@@ -5136,8 +5168,8 @@ void create_systemtray(GtkWidget *parent)
|
||||
_("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"
|
||||
"'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"
|
||||
"'Right to left' means that icons are always added to the right."),
|
||||
"'Left to right' means that icons are always added to the right. \n"
|
||||
"'Right to left' means that icons are always added to the left."),
|
||||
NULL);
|
||||
|
||||
row++;
|
||||
|
||||
@@ -105,7 +105,7 @@ extern GtkWidget *systray_background, *systray_monitor, *systray_name_filter;
|
||||
|
||||
// tooltip
|
||||
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 *tooltip_background;
|
||||
|
||||
@@ -203,6 +203,8 @@ enum {
|
||||
bgColBorderSidesBottom,
|
||||
bgColBorderSidesLeft,
|
||||
bgColBorderSidesRight,
|
||||
bgColFillWeight,
|
||||
bgColBorderWeight,
|
||||
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_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_corner_radius;
|
||||
*background_corner_radius, *background_border_content_tint_weight, *background_fill_content_tint_weight;
|
||||
|
||||
// gradients
|
||||
enum { grColPixbuf = 0, grColId, grColText, grNumCols };
|
||||
|
||||
@@ -69,23 +69,23 @@ void config_read_file(const char *path)
|
||||
if (!config_has_panel_items) {
|
||||
char panel_items[256];
|
||||
panel_items[0] = 0;
|
||||
strcat(panel_items, "T");
|
||||
strlcat(panel_items, "T", sizeof(panel_items));
|
||||
if (config_has_battery) {
|
||||
if (config_battery_enabled)
|
||||
strcat(panel_items, "B");
|
||||
strlcat(panel_items, "B", sizeof(panel_items));
|
||||
} else {
|
||||
if (no_items_battery_enabled)
|
||||
strcat(panel_items, "B");
|
||||
strlcat(panel_items, "B", sizeof(panel_items));
|
||||
}
|
||||
if (config_has_systray) {
|
||||
if (config_systray_enabled)
|
||||
strcat(panel_items, "S");
|
||||
strlcat(panel_items, "S", sizeof(panel_items));
|
||||
} else {
|
||||
if (no_items_systray_enabled)
|
||||
strcat(panel_items, "S");
|
||||
strlcat(panel_items, "S", sizeof(panel_items));
|
||||
}
|
||||
if (no_items_clock_enabled)
|
||||
strcat(panel_items, "C");
|
||||
strlcat(panel_items, "C", sizeof(panel_items));
|
||||
set_panel_items(panel_items);
|
||||
}
|
||||
}
|
||||
@@ -161,6 +161,8 @@ void config_write_backgrounds(FILE *fp)
|
||||
|
||||
int r;
|
||||
int b;
|
||||
double fill_weight;
|
||||
double border_weight;
|
||||
gboolean sideTop;
|
||||
gboolean sideBottom;
|
||||
gboolean sideLeft;
|
||||
@@ -228,6 +230,10 @@ void config_write_backgrounds(FILE *fp)
|
||||
&sideLeft,
|
||||
bgColBorderSidesRight,
|
||||
&sideRight,
|
||||
bgColFillWeight,
|
||||
&fill_weight,
|
||||
bgColBorderWeight,
|
||||
&border_weight,
|
||||
-1);
|
||||
fprintf(fp, "# Background %d: %s\n", index, text ? text : "");
|
||||
fprintf(fp, "rounded = %d\n", r);
|
||||
@@ -236,15 +242,18 @@ void config_write_backgrounds(FILE *fp)
|
||||
char sides[10];
|
||||
sides[0] = '\0';
|
||||
if (sideTop)
|
||||
strcat(sides, "T");
|
||||
strlcat(sides, "T", sizeof(sides));
|
||||
if (sideBottom)
|
||||
strcat(sides, "B");
|
||||
strlcat(sides, "B", sizeof(sides));
|
||||
if (sideLeft)
|
||||
strcat(sides, "L");
|
||||
strlcat(sides, "L", sizeof(sides));
|
||||
if (sideRight)
|
||||
strcat(sides, "R");
|
||||
strlcat(sides, "R", sizeof(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, "border_color", *borderColor, borderOpacity);
|
||||
if (gradient_id >= 0)
|
||||
@@ -469,7 +478,7 @@ void config_write_task_font_color(FILE *fp, char *name, GtkWidget *task_color)
|
||||
GdkColor color;
|
||||
gtk_color_button_get_color(GTK_COLOR_BUTTON(task_color), &color);
|
||||
char full_name[128];
|
||||
sprintf(full_name, "task%s_font_color", name);
|
||||
snprintf(full_name, sizeof(full_name), "task%s_font_color", name);
|
||||
config_write_color(fp, full_name, color, gtk_color_button_get_alpha(GTK_COLOR_BUTTON(task_color)) * 100 / 0xffff);
|
||||
}
|
||||
|
||||
@@ -480,7 +489,7 @@ void config_write_task_icon_osb(FILE *fp,
|
||||
GtkWidget *widget_brightness)
|
||||
{
|
||||
char full_name[128];
|
||||
sprintf(full_name, "task%s_icon_asb", name);
|
||||
snprintf(full_name, sizeof(full_name), "task%s_icon_asb", name);
|
||||
fprintf(fp,
|
||||
"%s = %d %d %d\n",
|
||||
full_name,
|
||||
@@ -492,7 +501,7 @@ void config_write_task_icon_osb(FILE *fp,
|
||||
void config_write_task_background(FILE *fp, char *name, GtkWidget *task_background)
|
||||
{
|
||||
char full_name[128];
|
||||
sprintf(full_name, "task%s_background_id", name);
|
||||
snprintf(full_name, sizeof(full_name), "task%s_background_id", name);
|
||||
fprintf(fp, "%s = %d\n", full_name, gtk_combo_box_get_active(GTK_COMBO_BOX(task_background)));
|
||||
}
|
||||
|
||||
@@ -517,6 +526,11 @@ void config_write_task(FILE *fp)
|
||||
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_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
|
||||
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));
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(background_gradient_press), id);
|
||||
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 */
|
||||
@@ -1732,6 +1752,10 @@ void add_entry(char *key, char *value)
|
||||
else if (strcmp(key, "task_tooltip") == 0 || strcmp(key, "tooltip") == 0) {
|
||||
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 */
|
||||
else if (strcmp(key, "systray") == 0) {
|
||||
|
||||
@@ -207,7 +207,7 @@ gboolean update_snapshot(gpointer ignored)
|
||||
|
||||
char hash[MD4_HEX_SIZE + 4];
|
||||
md4hexf(path, hash);
|
||||
strcat(hash, ".png");
|
||||
strlcat(hash, ".png", sizeof(hash));
|
||||
|
||||
gchar *snap = g_build_filename(g_get_user_cache_dir(), "tint2", hash, NULL);
|
||||
pixbuf = force_refresh ? NULL : gdk_pixbuf_new_from_file(snap, NULL);
|
||||
|
||||
@@ -31,9 +31,9 @@ static int x, y, width, height;
|
||||
static gboolean just_shown;
|
||||
|
||||
// the next functions are helper functions for tooltip handling
|
||||
void start_show_timeout();
|
||||
void start_hide_timeout();
|
||||
void stop_tooltip_timeout();
|
||||
void start_show_timer();
|
||||
void start_hide_timer();
|
||||
void stop_tooltip_timer();
|
||||
|
||||
void tooltip_init_fonts();
|
||||
|
||||
@@ -44,6 +44,9 @@ void default_tooltip()
|
||||
// give the tooltip some reasonable default values
|
||||
memset(&g_tooltip, 0, sizeof(Tooltip));
|
||||
|
||||
INIT_TIMER(g_tooltip.visibility_timer);
|
||||
INIT_TIMER(g_tooltip.update_timer);
|
||||
|
||||
g_tooltip.font_color.rgb[0] = 1;
|
||||
g_tooltip.font_color.rgb[1] = 1;
|
||||
g_tooltip.font_color.rgb[2] = 1;
|
||||
@@ -53,9 +56,11 @@ void default_tooltip()
|
||||
|
||||
void cleanup_tooltip()
|
||||
{
|
||||
stop_tooltip_timeout();
|
||||
stop_tooltip_timer();
|
||||
destroy_timer(&g_tooltip.visibility_timer);
|
||||
destroy_timer(&g_tooltip.update_timer);
|
||||
tooltip_hide(NULL);
|
||||
tooltip_copy_text(NULL);
|
||||
tooltip_update_contents_for(NULL);
|
||||
if (g_tooltip.window)
|
||||
XDestroyWindow(server.display, g_tooltip.window);
|
||||
g_tooltip.window = 0;
|
||||
@@ -118,11 +123,11 @@ void tooltip_trigger_show(Area *area, Panel *p, XEvent *e)
|
||||
just_shown = TRUE;
|
||||
g_tooltip.panel = p;
|
||||
if (g_tooltip.mapped && g_tooltip.area != area) {
|
||||
tooltip_copy_text(area);
|
||||
tooltip_update_contents_for(area);
|
||||
tooltip_update();
|
||||
stop_tooltip_timeout();
|
||||
stop_tooltip_timer();
|
||||
} else if (!g_tooltip.mapped) {
|
||||
start_show_timeout();
|
||||
start_show_timer();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +138,7 @@ void tooltip_show(void *arg)
|
||||
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);
|
||||
if (!g_tooltip.mapped && area->_get_tooltip_text) {
|
||||
tooltip_copy_text(area);
|
||||
tooltip_update_contents_for(area);
|
||||
g_tooltip.mapped = True;
|
||||
XMapWindow(server.display, g_tooltip.window);
|
||||
tooltip_update();
|
||||
@@ -144,7 +149,7 @@ void tooltip_show(void *arg)
|
||||
void tooltip_update_geometry()
|
||||
{
|
||||
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_t *c = cairo_create(cs);
|
||||
@@ -152,16 +157,25 @@ void tooltip_update_geometry()
|
||||
|
||||
pango_layout_set_font_description(layout, g_tooltip.font_desc);
|
||||
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);
|
||||
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_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_get_pixel_extents(layout, &r1, &r2);
|
||||
width = left_right_bg_border_width(g_tooltip.bg) + 2 * g_tooltip.paddingx + r2.width;
|
||||
height = top_bottom_bg_border_width(g_tooltip.bg) + 2 * g_tooltip.paddingy + r2.height;
|
||||
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)
|
||||
y = panel->posy - height;
|
||||
@@ -278,8 +292,16 @@ void tooltip_update()
|
||||
-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);
|
||||
pango_cairo_show_layout(c, 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_surface_destroy(cs);
|
||||
}
|
||||
@@ -287,11 +309,11 @@ void tooltip_update()
|
||||
void tooltip_trigger_hide()
|
||||
{
|
||||
if (g_tooltip.mapped) {
|
||||
tooltip_copy_text(0);
|
||||
start_hide_timeout();
|
||||
tooltip_update_contents_for(NULL);
|
||||
start_hide_timer();
|
||||
} else {
|
||||
// tooltip not visible yet, but maybe a timeout is still pending
|
||||
stop_tooltip_timeout();
|
||||
// tooltip not visible yet, but maybe a timer is still pending
|
||||
stop_tooltip_timer();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,29 +324,43 @@ void tooltip_hide(void *arg)
|
||||
XUnmapWindow(server.display, g_tooltip.window);
|
||||
XFlush(server.display);
|
||||
}
|
||||
g_tooltip.area = NULL;
|
||||
}
|
||||
|
||||
void start_show_timeout()
|
||||
void start_show_timer()
|
||||
{
|
||||
change_timeout(&g_tooltip.timeout, g_tooltip.show_timeout_msec, 0, tooltip_show, 0);
|
||||
change_timer(&g_tooltip.visibility_timer, true, g_tooltip.show_timeout_msec, 0, tooltip_show, 0);
|
||||
}
|
||||
|
||||
void start_hide_timeout()
|
||||
void start_hide_timer()
|
||||
{
|
||||
change_timeout(&g_tooltip.timeout, g_tooltip.hide_timeout_msec, 0, tooltip_hide, 0);
|
||||
change_timer(&g_tooltip.visibility_timer, true, g_tooltip.hide_timeout_msec, 0, tooltip_hide, 0);
|
||||
}
|
||||
|
||||
void stop_tooltip_timeout()
|
||||
void stop_tooltip_timer()
|
||||
{
|
||||
stop_timeout(g_tooltip.timeout);
|
||||
stop_timer(&g_tooltip.visibility_timer);
|
||||
}
|
||||
|
||||
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)
|
||||
g_tooltip.tooltip_text = area->_get_tooltip_text(area);
|
||||
else
|
||||
g_tooltip.tooltip_text = NULL;
|
||||
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
|
||||
change_timer(&g_tooltip.update_timer, true, 300, 0, tooltip_update_contents_timeout, NULL);
|
||||
}
|
||||
g_tooltip.area = area;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,9 @@ typedef struct {
|
||||
PangoFontDescription *font_desc;
|
||||
Color font_color;
|
||||
Background *bg;
|
||||
timeout *timeout;
|
||||
Timer visibility_timer;
|
||||
Timer update_timer;
|
||||
cairo_surface_t *image;
|
||||
} Tooltip;
|
||||
|
||||
extern Tooltip g_tooltip;
|
||||
@@ -53,7 +55,7 @@ void tooltip_show(void * /*arg*/);
|
||||
void tooltip_update();
|
||||
void tooltip_trigger_hide();
|
||||
void tooltip_hide(void * /*arg*/);
|
||||
void tooltip_copy_text(Area *area);
|
||||
void tooltip_update_contents_for(Area *area);
|
||||
void tooltip_default_font_changed();
|
||||
|
||||
#endif // TOOLTIP_H
|
||||
|
||||
@@ -490,28 +490,59 @@ void draw(Area *a)
|
||||
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)
|
||||
{
|
||||
if ((a->bg->fill_color.alpha > 0.0) ||
|
||||
(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
|
||||
draw_rect(c,
|
||||
left_border_width(a),
|
||||
@@ -519,7 +550,7 @@ void draw_background(Area *a, cairo_t *c)
|
||||
a->width - left_right_border_width(a),
|
||||
a->height - top_bottom_border_width(a),
|
||||
a->bg->border.radius - a->bg->border.width / 1.571);
|
||||
|
||||
set_cairo_source_bg_color(a, c);
|
||||
cairo_fill(c);
|
||||
}
|
||||
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);
|
||||
|
||||
// draw border inside (x, y, width, height)
|
||||
if (a->mouse_state == MOUSE_OVER)
|
||||
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);
|
||||
set_cairo_source_border_color(a, c);
|
||||
draw_rect_on_sides(c,
|
||||
left_border_width(a) / 2.,
|
||||
top_border_width(a) / 2.,
|
||||
|
||||
@@ -154,6 +154,8 @@ typedef struct Background {
|
||||
Color border_color_pressed;
|
||||
// Pointer to a GradientClass or NULL, no ownership
|
||||
GradientClass *gradients[MOUSE_STATE_COUNT];
|
||||
double fill_content_tint_weight;
|
||||
double border_content_tint_weight;
|
||||
} Background;
|
||||
|
||||
typedef enum Layout {
|
||||
@@ -233,6 +235,7 @@ typedef struct Area {
|
||||
// Returns a copy of the tooltip to be displayed for this widget.
|
||||
// The caller takes ownership of the pointer.
|
||||
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.
|
||||
// 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.
|
||||
void (*_dump_geometry)(void *obj, int indent);
|
||||
|
||||
void (*_get_content_color)(void *obj, Color *color);
|
||||
} Area;
|
||||
|
||||
// Initializes the Background member to default values.
|
||||
|
||||
17
src/util/bool.h
Normal file
17
src/util/bool.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef BOOL_H
|
||||
#define BOOL_H
|
||||
|
||||
#ifndef bool
|
||||
#define bool int
|
||||
#define false 0
|
||||
#define true 1
|
||||
#endif
|
||||
|
||||
#define SUCCESS true
|
||||
#define FAILURE false
|
||||
|
||||
#ifndef Status
|
||||
typedef int Status;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
10
src/util/colors.h
Normal file
10
src/util/colors.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef COLORS_H
|
||||
#define COLORS_H
|
||||
|
||||
#define GREEN "\033[1;32m"
|
||||
#define YELLOW "\033[1;33m"
|
||||
#define RED "\033[1;31m"
|
||||
#define BLUE "\033[1;34m"
|
||||
#define RESET "\033[0m"
|
||||
|
||||
#endif
|
||||
@@ -31,7 +31,7 @@
|
||||
#include <glib.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include "common.h"
|
||||
#include "../server.h"
|
||||
#include "server.h"
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
@@ -59,6 +59,7 @@
|
||||
|
||||
#include "../panel.h"
|
||||
#include "timer.h"
|
||||
#include "signals.h"
|
||||
|
||||
void write_string(int fd, const char *s)
|
||||
{
|
||||
@@ -190,7 +191,7 @@ const char *signal_name(int sig)
|
||||
return "SIGSYS: Bad system call.";
|
||||
}
|
||||
static char s[64];
|
||||
sprintf(s, "SIG=%d: Unknown", sig);
|
||||
snprintf(s, sizeof(s), "SIG=%d: Unknown", sig);
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -265,7 +266,7 @@ extern char *config_path;
|
||||
int setenvd(const char *name, const int value)
|
||||
{
|
||||
char buf[256];
|
||||
sprintf(buf, "%d", value);
|
||||
snprintf(buf, sizeof(buf), "%d", value);
|
||||
return setenv(name, buf, 1);
|
||||
}
|
||||
|
||||
@@ -398,18 +399,21 @@ pid_t tint_exec(const char *command,
|
||||
if (dir)
|
||||
chdir(dir);
|
||||
close_all_fds();
|
||||
reset_signals();
|
||||
if (terminal) {
|
||||
#if !defined(__OpenBSD__)
|
||||
fprintf(stderr, "tint2: executing in x-terminal-emulator: %s\n", command);
|
||||
wordexp_t words;
|
||||
words.we_offs = 2;
|
||||
if (wordexp(command, &words, WRDE_DOOFFS | WRDE_SHOWERR) == 0) {
|
||||
words.we_wordv[0] = (char*)"x-terminal-emulator";
|
||||
words.we_wordv[1] = (char*)"-e";
|
||||
words.we_wordv[0] = (char *)"x-terminal-emulator";
|
||||
words.we_wordv[1] = (char *)"-e";
|
||||
execvp("x-terminal-emulator", words.we_wordv);
|
||||
}
|
||||
#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);
|
||||
fprintf(stderr, "tint2: Failed to execute %s\n", command);
|
||||
@@ -457,9 +461,10 @@ char *expand_tilde(const char *s)
|
||||
{
|
||||
const gchar *home = g_get_home_dir();
|
||||
if (home && (strcmp(s, "~") == 0 || strstr(s, "~/") == s)) {
|
||||
char *result = calloc(strlen(home) + strlen(s), 1);
|
||||
strcat(result, home);
|
||||
strcat(result, s + 1);
|
||||
size_t buf_size = strlen(home) + strlen(s);
|
||||
char *result = calloc(buf_size, 1);
|
||||
strlcat(result, home, buf_size);
|
||||
strlcat(result, s + 1, buf_size);
|
||||
return result;
|
||||
} else {
|
||||
return strdup(s);
|
||||
@@ -472,14 +477,16 @@ char *contract_tilde(const char *s)
|
||||
if (!home)
|
||||
return strdup(s);
|
||||
|
||||
char *home_slash = calloc(strlen(home) + 2, 1);
|
||||
strcat(home_slash, home);
|
||||
strcat(home_slash, "/");
|
||||
size_t buf_size = strlen(home) + 2;
|
||||
char *home_slash = calloc(buf_size, 1);
|
||||
strlcat(home_slash, home, buf_size);
|
||||
strlcat(home_slash, "/", buf_size);
|
||||
|
||||
if ((strcmp(s, home) == 0 || strstr(s, home_slash) == s)) {
|
||||
char *result = calloc(strlen(s) - strlen(home) + 2, 1);
|
||||
strcat(result, "~");
|
||||
strcat(result, s + strlen(home));
|
||||
size_t buf_size2 = strlen(s) - strlen(home) + 2;
|
||||
char *result = calloc(buf_size2, 1);
|
||||
strlcat(result, "~", buf_size2);
|
||||
strlcat(result, s + strlen(home), buf_size2);
|
||||
free(home_slash);
|
||||
return result;
|
||||
} else {
|
||||
@@ -789,7 +796,7 @@ Imlib_Image load_image(const char *path, int cached)
|
||||
}
|
||||
if (!image && g_str_has_suffix(path, ".svg")) {
|
||||
char tmp_filename[128];
|
||||
sprintf(tmp_filename, "/tmp/tint2-%d.png", (int)getpid());
|
||||
snprintf(tmp_filename, sizeof(tmp_filename), "/tmp/tint2-%d.png", (int)getpid());
|
||||
int fd = open(tmp_filename, O_CREAT | O_EXCL, 0600);
|
||||
if (fd >= 0) {
|
||||
// We fork here because librsvg allocates memory like crazy
|
||||
@@ -806,7 +813,7 @@ Imlib_Image load_image(const char *path, int cached)
|
||||
GdkPixbuf *pixbuf = rsvg_handle_get_pixbuf(svg);
|
||||
gdk_pixbuf_save(pixbuf, tmp_filename, "png", NULL, NULL);
|
||||
}
|
||||
exit(0);
|
||||
_exit(0);
|
||||
} else {
|
||||
// Parent
|
||||
close(fd);
|
||||
@@ -933,10 +940,9 @@ void get_text_size2(const PangoFontDescription *font,
|
||||
|
||||
available_width = MAX(0, available_width);
|
||||
available_height = MAX(0, available_height);
|
||||
Pixmap pmap = XCreatePixmap(server.display, server.root_win, available_height, available_width, server.depth);
|
||||
|
||||
cairo_surface_t *cs =
|
||||
cairo_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);
|
||||
|
||||
PangoLayout *layout = pango_cairo_create_layout(c);
|
||||
@@ -960,7 +966,6 @@ void get_text_size2(const PangoFontDescription *font,
|
||||
g_object_unref(layout);
|
||||
cairo_destroy(c);
|
||||
cairo_surface_destroy(cs);
|
||||
XFreePixmap(server.display, pmap);
|
||||
}
|
||||
|
||||
#if !GLIB_CHECK_VERSION(2, 34, 0)
|
||||
@@ -1055,3 +1060,117 @@ GString *tint2_g_string_replace(GString *s, const char *from, const char *to)
|
||||
g_string_free(result, TRUE);
|
||||
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.;
|
||||
}
|
||||
|
||||
void dump_image_data(const char *file_name, const char *name)
|
||||
{
|
||||
Imlib_Image image = load_image(file_name, false);
|
||||
if (!image) {
|
||||
fprintf(stderr, "tint2: Could not load image from file\n");
|
||||
return;
|
||||
}
|
||||
|
||||
gchar *header_name = g_strdup_printf("%s.h", name);
|
||||
gchar *guard = g_strdup_printf("%s_h", name);
|
||||
FILE *header = fopen(header_name, "wt");
|
||||
fprintf(header,
|
||||
"#ifndef %s\n"
|
||||
"#define %s\n"
|
||||
"\n"
|
||||
"#include <Imlib2.h>\n"
|
||||
"\n"
|
||||
"extern int %s_width;\n"
|
||||
"extern int %s_height;\n"
|
||||
"extern DATA32 %s_data[];\n"
|
||||
"\n"
|
||||
"#endif\n",
|
||||
guard,
|
||||
guard,
|
||||
name,
|
||||
name,
|
||||
name);
|
||||
fclose(header);
|
||||
g_free(guard);
|
||||
g_free(header_name);
|
||||
|
||||
imlib_context_set_image(image);
|
||||
|
||||
gchar *source_name = g_strdup_printf("%s.c", name);
|
||||
FILE *source = fopen(source_name, "wt");
|
||||
fprintf(source,
|
||||
"#include <%s.h>\n"
|
||||
"\n"
|
||||
"int %s_width = %d;\n"
|
||||
"int %s_height = %d;\n"
|
||||
"DATA32 %s_data[] = {",
|
||||
name,
|
||||
name,
|
||||
imlib_image_get_width(),
|
||||
name,
|
||||
imlib_image_get_height(),
|
||||
name);
|
||||
|
||||
size_t size = (size_t)imlib_image_get_width() * (size_t)imlib_image_get_height();
|
||||
DATA32 *data = imlib_image_get_data_for_reading_only();
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
fprintf(source, "%s%u", i == 0 ? "" : ", ", data[i]);
|
||||
}
|
||||
fprintf(source, "};\n");
|
||||
fclose(source);
|
||||
g_free(source_name);
|
||||
|
||||
imlib_free_image();
|
||||
}
|
||||
|
||||
@@ -12,12 +12,8 @@
|
||||
#include <Imlib2.h>
|
||||
#include <pango/pangocairo.h>
|
||||
#include "area.h"
|
||||
|
||||
#define GREEN "\033[1;32m"
|
||||
#define YELLOW "\033[1;33m"
|
||||
#define RED "\033[1;31m"
|
||||
#define BLUE "\033[1;34m"
|
||||
#define RESET "\033[0m"
|
||||
#include "colors.h"
|
||||
#include "strlcat.h"
|
||||
|
||||
#define MAX3(a, b, c) MAX(MAX(a, b), c)
|
||||
#define MIN3(a, b, c) MIN(MIN(a, b), c)
|
||||
@@ -109,6 +105,7 @@ Imlib_Image load_image(const char *path, int cached);
|
||||
// * 1 = white
|
||||
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);
|
||||
void adjust_color(Color *color, int alpha, int saturation, int brightness);
|
||||
|
||||
void create_heuristic_mask(DATA32 *data, int w, int h);
|
||||
|
||||
@@ -150,6 +147,10 @@ gint cmp_ptr(gconstpointer a, gconstpointer b);
|
||||
|
||||
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);
|
||||
|
||||
void dump_image_data(const char *file_name, const char *name);
|
||||
|
||||
#define free_and_null(p) \
|
||||
{ \
|
||||
free(p); \
|
||||
|
||||
83
src/util/print.c
Normal file
83
src/util/print.c
Normal file
@@ -0,0 +1,83 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "print.h"
|
||||
|
||||
int print_uchar(unsigned char v)
|
||||
{
|
||||
return printf("%u", v);
|
||||
}
|
||||
|
||||
int print_char(char v)
|
||||
{
|
||||
return printf("%c", v);
|
||||
}
|
||||
|
||||
int print_short(short v)
|
||||
{
|
||||
return printf("%d", v);
|
||||
}
|
||||
|
||||
int print_ushort(unsigned short v)
|
||||
{
|
||||
return printf("%u", v);
|
||||
}
|
||||
|
||||
int print_int(int v)
|
||||
{
|
||||
return printf("%d", v);
|
||||
}
|
||||
|
||||
int print_uint(unsigned v)
|
||||
{
|
||||
return printf("%u", v);
|
||||
}
|
||||
|
||||
int print_long(long v)
|
||||
{
|
||||
return printf("%ld", v);
|
||||
}
|
||||
|
||||
int print_ulong(unsigned long v)
|
||||
{
|
||||
return printf("%lu", v);
|
||||
}
|
||||
|
||||
int print_long_long(long long v)
|
||||
{
|
||||
return printf("%lld", v);
|
||||
}
|
||||
|
||||
int print_ulong_long(unsigned long long v)
|
||||
{
|
||||
return printf("%llu", v);
|
||||
}
|
||||
|
||||
int print_float(float v)
|
||||
{
|
||||
return printf("%f", (double)v);
|
||||
}
|
||||
|
||||
int print_double(double v)
|
||||
{
|
||||
return printf("%f", v);
|
||||
}
|
||||
|
||||
int print_long_double(long double v)
|
||||
{
|
||||
return printf("%Lf", v);
|
||||
}
|
||||
|
||||
int print_string(char *s)
|
||||
{
|
||||
return printf("%s", s);
|
||||
}
|
||||
|
||||
int print_pointer(void *v)
|
||||
{
|
||||
return printf("%p", v);
|
||||
}
|
||||
|
||||
int print_unknown()
|
||||
{
|
||||
return printf("(variable of unknown type)");
|
||||
}
|
||||
61
src/util/print.h
Normal file
61
src/util/print.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#ifndef PRINT_H
|
||||
#define PRINT_H
|
||||
|
||||
#ifdef HAS_GENERIC
|
||||
|
||||
int print_uchar(unsigned char v);
|
||||
|
||||
int print_char(char v);
|
||||
|
||||
int print_short(short v);
|
||||
|
||||
int print_ushort(unsigned short v);
|
||||
|
||||
int print_int(int v);
|
||||
|
||||
int print_uint(unsigned v);
|
||||
|
||||
int print_long(long v);
|
||||
|
||||
int print_ulong(unsigned long v);
|
||||
|
||||
int print_long_long(long long v);
|
||||
|
||||
int print_ulong_long(unsigned long long v);
|
||||
|
||||
int print_float(float v);
|
||||
|
||||
int print_double(double v);
|
||||
|
||||
int print_long_double(long double v);
|
||||
|
||||
int print_string(char *s);
|
||||
|
||||
int print_pointer(void *v);
|
||||
|
||||
int print_unknown();
|
||||
|
||||
#define print(x) \
|
||||
_Generic((x), \
|
||||
unsigned char: print_uchar, \
|
||||
char: print_char, \
|
||||
short int: print_short, \
|
||||
unsigned short int: print_ushort, \
|
||||
int: print_int, \
|
||||
unsigned int: print_uint, \
|
||||
long int: print_long, \
|
||||
unsigned long int: print_ulong, \
|
||||
long long int: print_long_long, \
|
||||
unsigned long long int: print_ulong_long, \
|
||||
float: print_float, \
|
||||
double: print_double, \
|
||||
long double: print_long_double, \
|
||||
char *: print_string, \
|
||||
void *: print_pointer, \
|
||||
default : print_unknown)(x)
|
||||
|
||||
#else
|
||||
#define print(...) printf("Omitted, the compiler does not support C11 generics.\n")
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -147,6 +147,7 @@ typedef struct Server {
|
||||
Global_atom atom;
|
||||
int xdamage_event_type;
|
||||
int xdamage_event_error_type;
|
||||
gboolean has_shm;
|
||||
#ifdef HAVE_SN
|
||||
SnDisplay *sn_display;
|
||||
GTree *pids;
|
||||
@@ -1,9 +1,11 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <glib.h>
|
||||
#ifndef TINT2CONF
|
||||
#ifdef HAVE_SN
|
||||
#include <libsn/sn.h>
|
||||
#endif
|
||||
#endif
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -24,11 +26,24 @@ void signal_handler(int 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);
|
||||
}
|
||||
|
||||
#ifndef TINT2CONF
|
||||
void init_signals()
|
||||
{
|
||||
// Set signal handlers
|
||||
signal_pending = 0;
|
||||
|
||||
reset_signals();
|
||||
|
||||
struct sigaction sa_chld = {.sa_handler = SIG_IGN};
|
||||
sigaction(SIGCHLD, &sa_chld, 0);
|
||||
|
||||
@@ -152,3 +167,4 @@ int get_signal_pending()
|
||||
{
|
||||
return signal_pending;
|
||||
}
|
||||
#endif
|
||||
@@ -5,6 +5,7 @@ void init_signals();
|
||||
void init_signals_postconfig();
|
||||
void emit_self_restart(const char *reason);
|
||||
int get_signal_pending();
|
||||
void reset_signals();
|
||||
|
||||
void handle_sigchld_events();
|
||||
|
||||
60
src/util/strlcat.c
Normal file
60
src/util/strlcat.c
Normal file
@@ -0,0 +1,60 @@
|
||||
/* $NetBSD: strlcat.c,v 1.4 2005/05/16 06:55:48 lukem Exp $ */
|
||||
/* from NetBSD: strlcat.c,v 1.16 2003/10/27 00:12:42 lukem Exp */
|
||||
/* from OpenBSD: strlcat.c,v 1.10 2003/04/12 21:56:39 millert Exp */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL
|
||||
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE
|
||||
* FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "strlcat.h"
|
||||
|
||||
/*
|
||||
* Appends src to string dst of size siz (unlike strncat, siz is the
|
||||
* full size of dst, not space left). At most siz-1 characters
|
||||
* will be copied. Always NUL terminates (unless siz <= strlen(dst)).
|
||||
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
|
||||
* If retval >= siz, truncation occurred.
|
||||
*/
|
||||
size_t
|
||||
strlcat(char *dst, const char *src, size_t siz)
|
||||
{
|
||||
char *d = dst;
|
||||
const char *s = src;
|
||||
size_t n = siz;
|
||||
size_t dlen;
|
||||
|
||||
/* Find the end of dst and adjust bytes left but don't go past end */
|
||||
while (n-- != 0 && *d != '\0')
|
||||
d++;
|
||||
dlen = d - dst;
|
||||
n = siz - dlen;
|
||||
|
||||
if (n == 0)
|
||||
return(dlen + strlen(s));
|
||||
while (*s != '\0') {
|
||||
if (n != 1) {
|
||||
*d++ = *s;
|
||||
n--;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
*d = '\0';
|
||||
|
||||
return(dlen + (s - src)); /* count does not include NUL */
|
||||
}
|
||||
16
src/util/strlcat.h
Normal file
16
src/util/strlcat.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef STRLCAT_H
|
||||
#define STRLCAT_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* Appends src to string dst of size siz (unlike strncat, siz is the
|
||||
* full size of dst, not space left). At most siz-1 characters
|
||||
* will be copied. Always NUL terminates (unless siz <= strlen(dst)).
|
||||
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
|
||||
* If retval >= siz, truncation occurred.
|
||||
*/
|
||||
size_t strlcat(char *dst, const char *src, size_t siz);
|
||||
|
||||
#endif
|
||||
183
src/util/test.c
Normal file
183
src/util/test.c
Normal file
@@ -0,0 +1,183 @@
|
||||
#include <fcntl.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "colors.h"
|
||||
#include "signals.h"
|
||||
#include "test.h"
|
||||
|
||||
typedef struct TestListItem {
|
||||
Test *test;
|
||||
const char *name;
|
||||
} TestListItem;
|
||||
|
||||
static GList *all_tests = NULL;
|
||||
|
||||
void register_test_(Test *test, const char *name)
|
||||
{
|
||||
TestListItem *item = (TestListItem *)calloc(sizeof(TestListItem), 1);
|
||||
item->test = test;
|
||||
item->name = name;
|
||||
all_tests = g_list_append(all_tests, item);
|
||||
}
|
||||
|
||||
static char *test_log_name_from_test_name(const char *test_name)
|
||||
{
|
||||
char *output_name = g_strdup_printf("test_%s.log", test_name);
|
||||
char *result = strdup(output_name);
|
||||
g_free(output_name);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void redirect_test_output(const char *test_name)
|
||||
{
|
||||
char *output_name = test_log_name_from_test_name(test_name);
|
||||
int fd = open(output_name, O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
||||
if (fd == -1)
|
||||
goto err;
|
||||
if (dup2(fd, STDOUT_FILENO) == -1)
|
||||
goto err;
|
||||
if (dup2(fd, STDERR_FILENO) == -1)
|
||||
goto err;
|
||||
|
||||
close(fd);
|
||||
free(output_name);
|
||||
return;
|
||||
err:
|
||||
fprintf(stderr, "tint2: Could not redirect test output to file name: %s\n", output_name);
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
free(output_name);
|
||||
}
|
||||
|
||||
static void crash(int sig)
|
||||
{
|
||||
kill(getpid(), SIGSEGV);
|
||||
}
|
||||
|
||||
__attribute__((noreturn))
|
||||
static void run_test_child(TestListItem *item)
|
||||
{
|
||||
reset_signals();
|
||||
struct sigaction sa = {.sa_handler = crash};
|
||||
sigaction(SIGINT, &sa, 0);
|
||||
redirect_test_output(item->name);
|
||||
bool result = true;
|
||||
item->test(&result);
|
||||
exit(result ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static FILE *open_test_log(const char *test_name)
|
||||
{
|
||||
char *output_name = test_log_name_from_test_name(test_name);
|
||||
FILE *log = fopen(output_name, "a");
|
||||
free(output_name);
|
||||
return log;
|
||||
}
|
||||
|
||||
static Status run_test_parent(TestListItem *item, pid_t child)
|
||||
{
|
||||
FILE *log = open_test_log(item->name);
|
||||
if (child == -1) {
|
||||
fprintf(log, "\n" "Test failed, fork failed\n");
|
||||
fclose(log);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
int child_status;
|
||||
pid_t ret_pid = waitpid(child, &child_status, 0);
|
||||
if (ret_pid != child) {
|
||||
fprintf(log, "\n" "Test failed, waitpid failed\n");
|
||||
fclose(log);
|
||||
return FAILURE;
|
||||
}
|
||||
if (WIFEXITED(child_status)) {
|
||||
int exit_status = WEXITSTATUS(child_status);
|
||||
if (exit_status == EXIT_SUCCESS) {
|
||||
fprintf(log, "\n" "Test succeeded.\n");
|
||||
fclose(log);
|
||||
return SUCCESS;
|
||||
} else {
|
||||
fprintf(log, "\n" "Test failed, exit status: %d.\n", exit_status);
|
||||
fclose(log);
|
||||
return FAILURE;
|
||||
}
|
||||
} else if (WIFSIGNALED(child_status)) {
|
||||
int signal = WTERMSIG(child_status);
|
||||
fprintf(log, "\n" "Test failed, child killed by signal: %d.\n", signal);
|
||||
fclose(log);
|
||||
return FAILURE;
|
||||
} else {
|
||||
fprintf(log, "\n" "Test failed, waitpid failed.\n");
|
||||
fclose(log);
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
static Status run_test(TestListItem *item)
|
||||
{
|
||||
pid_t pid = fork();
|
||||
if (pid == 0)
|
||||
run_test_child(item);
|
||||
struct sigaction sa = {.sa_handler = SIG_IGN};
|
||||
sigaction(SIGINT, &sa, 0);
|
||||
return run_test_parent(item, pid);
|
||||
}
|
||||
|
||||
void run_all_tests(bool verbose)
|
||||
{
|
||||
fprintf(stdout, BLUE "tint2: Running %d tests..." RESET "\n", g_list_length(all_tests));
|
||||
size_t count = 0, succeeded = 0, failed = 0;
|
||||
for (GList *l = all_tests; l; l = l->next) {
|
||||
TestListItem *item = (TestListItem *)l->data;
|
||||
Status status = run_test(item);
|
||||
count++;
|
||||
fprintf(stdout, BLUE "tint2: Test " YELLOW "%s" BLUE ": ", item->name);
|
||||
if (status == SUCCESS) {
|
||||
fprintf(stdout, GREEN "succeeded" RESET "\n");
|
||||
succeeded++;
|
||||
} else {
|
||||
fprintf(stdout, RED "failed" RESET "\n");
|
||||
failed++;
|
||||
if (verbose) {
|
||||
char *log_name = test_log_name_from_test_name(item->name);
|
||||
FILE *log = fopen(log_name, "rt");
|
||||
if (log) {
|
||||
char buffer[4096];
|
||||
size_t num_read;
|
||||
while ((num_read = fread(buffer, 1, sizeof(buffer), log)) > 0) {
|
||||
fwrite(buffer, 1, num_read, stdout);
|
||||
}
|
||||
fclose(log);
|
||||
}
|
||||
free(log_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (failed == 0)
|
||||
fprintf(stdout, BLUE "tint2: " GREEN "all %lu tests succeeded." RESET "\n", count);
|
||||
else
|
||||
fprintf(stdout, BLUE "tint2: " RED "%lu" BLUE " out of %lu tests " RED "failed." RESET "\n", failed, count);
|
||||
}
|
||||
|
||||
#if 0
|
||||
TEST(dummy) {
|
||||
int x = 2;
|
||||
int y = 2;
|
||||
ASSERT_EQUAL(x, y);
|
||||
}
|
||||
|
||||
TEST(dummy_bad) {
|
||||
int x = 2;
|
||||
int y = 3;
|
||||
ASSERT_EQUAL(x, y);
|
||||
}
|
||||
#endif
|
||||
72
src/util/test.h
Normal file
72
src/util/test.h
Normal file
@@ -0,0 +1,72 @@
|
||||
#ifndef TEST_H
|
||||
#define TEST_H
|
||||
|
||||
#include "bool.h"
|
||||
#include "print.h"
|
||||
|
||||
typedef void Test(Status *test_result_);
|
||||
|
||||
void register_test_(Test *test, const char *name);
|
||||
|
||||
#define TEST(name) \
|
||||
void test_##name(Status *test_result_); \
|
||||
__attribute__((constructor)) void test_register_##name() \
|
||||
{ \
|
||||
register_test_(test_##name, #name); \
|
||||
} \
|
||||
void test_##name(Status *test_result_)
|
||||
|
||||
void run_all_tests(bool verbose);
|
||||
|
||||
#define FAIL_TEST_ \
|
||||
*test_result_ = FAILURE; \
|
||||
return;
|
||||
|
||||
#define ASSERT(value) \
|
||||
if (!(value)) { \
|
||||
FAIL_TEST_ \
|
||||
}
|
||||
|
||||
#define ASSERT_EQUAL(a, b) \
|
||||
if (!(a == b)) { \
|
||||
printf("%s:%d: Assertion failed: %s == %s: ", __FILE__, __LINE__, #a, #b); \
|
||||
print(a); \
|
||||
printf(" != "); \
|
||||
print(b); \
|
||||
FAIL_TEST_ \
|
||||
}
|
||||
|
||||
#define ASSERT_DIFFERENT(a, b) \
|
||||
if (a == b) { \
|
||||
printf("%s:%d: Assertion failed: %s != %s: ", __FILE__, __LINE__, #a, #b); \
|
||||
print(a); \
|
||||
printf(" == "); \
|
||||
print(b); \
|
||||
FAIL_TEST_ \
|
||||
}
|
||||
|
||||
|
||||
#define ASSERT_STR_EQUAL(a, b) \
|
||||
if (strcmp(a, b) != 0) { \
|
||||
printf("%s:%d: Assertion failed: %s == %s: ", __FILE__, __LINE__, #a, #b); \
|
||||
print(a); \
|
||||
printf(" != "); \
|
||||
print(b); \
|
||||
FAIL_TEST_ \
|
||||
}
|
||||
|
||||
#define ASSERT_STR_DIFFERENT(a, b) \
|
||||
if (strcmp(a, b) == 0) { \
|
||||
printf("%s:%d: Assertion failed: %s != %s: ", __FILE__, __LINE__, #a, #b); \
|
||||
print(a); \
|
||||
printf(" == "); \
|
||||
print(b); \
|
||||
FAIL_TEST_ \
|
||||
}
|
||||
|
||||
#define ASSERT_TRUE(value) ASSERT_EQUAL(value, 1)
|
||||
#define ASSERT_FALSE(value) ASSERT_EQUAL(value, 0)
|
||||
#define ASSERT_NULL(value) ASSERT_EQUAL(value, NULL)
|
||||
#define ASSERT_NON_NULL(value) ASSERT_DIFFERENT(value, NULL)
|
||||
|
||||
#endif
|
||||
1992
src/util/timer.c
1992
src/util/timer.c
File diff suppressed because it is too large
Load Diff
@@ -21,45 +21,52 @@
|
||||
#include <glib.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include "bool.h"
|
||||
|
||||
// Single shot timers (i.e. timers with interval_msec == 0) are deleted automatically as soon as they expire,
|
||||
// i.e. you do not need to stop them, however it is safe to call stop_timeout for these timers.
|
||||
// You can pass the address of the variable storing the pointer to the timer as 'self' in add_timeout, in which
|
||||
// case it is used to clear the pointer if the timer is destroyed automatically. This enforces the timeout pointers
|
||||
// to be either valid or NULL.
|
||||
// Periodic timeouts are aligned to each other whenever possible, i.e. one interval_msec is an
|
||||
// integral multiple of the other.
|
||||
extern bool debug_timers;
|
||||
|
||||
typedef struct _timeout timeout;
|
||||
typedef void TimerCallback(void *arg);
|
||||
|
||||
// Initializes default global data.
|
||||
void default_timeout();
|
||||
typedef struct {
|
||||
char name_[64];
|
||||
bool enabled_;
|
||||
long long expiration_time_ms_;
|
||||
int period_ms_;
|
||||
TimerCallback *callback_;
|
||||
void *arg_;
|
||||
bool handled_;
|
||||
} Timer;
|
||||
|
||||
// Cleans up: stops all timers and frees memory.
|
||||
void cleanup_timeout();
|
||||
#define DEFAULT_TIMER {"", 0, 0, 0, 0, 0, 0}
|
||||
|
||||
// Installs a timer with the first timeout after 'value_msec' and then an optional periodic timeout every
|
||||
// 'interval_msec' (set it to 0 to prevent periodic timeouts).
|
||||
// '_callback' is the function called when the timer reaches the timeout.
|
||||
// 'arg' is the argument passed to the callback function.
|
||||
// 'self' is an optional pointer to a timeout* variable. If non-NULL, the variable is set to NULL when the timer
|
||||
// is destroyed (with stop_timeout, cleanup_timeout or when the timer expires and it is single-shot).
|
||||
// Returns a pointer to the timer, which is needed for stopping/changing it.
|
||||
timeout *add_timeout(int value_msec, int interval_msec, void (*_callback)(void *), void *arg, timeout **self);
|
||||
#define INIT_TIMER(t) init_timer(&t, #t)
|
||||
|
||||
// Changes timer 't'. If it does not exist, a new timer is created, with self set to 't'.
|
||||
void change_timeout(timeout **t, int value_msec, int interval_msec, void (*_callback)(void *), void *arg);
|
||||
// Initialize the timer module.
|
||||
void default_timers();
|
||||
|
||||
// Stops the timer 't'
|
||||
void stop_timeout(timeout *t);
|
||||
// Destroy the timer module.
|
||||
void cleanup_timers();
|
||||
|
||||
// Get the time when the next installed timer will expire, or NULL if there is no timer.
|
||||
// Do not free the pointer; but it is safe to change its contents.
|
||||
struct timeval *get_next_timeout();
|
||||
// Initialize a timer. Caller keeps ownership.
|
||||
void init_timer(Timer *timer, const char *name);
|
||||
|
||||
// Callback of all expired timeouts
|
||||
// Destroy a timer. Does not free() the pointer.
|
||||
void destroy_timer(Timer *timer);
|
||||
|
||||
// Modify a timer.
|
||||
void change_timer(Timer *timer, bool enabled, int delay_ms, int period_ms, TimerCallback *callback, void *arg);
|
||||
|
||||
void stop_timer(Timer *timer);
|
||||
|
||||
// Get the time duration to the next expiration time, or NULL if there is no active timer.
|
||||
// Do not free the pointer; it is harmless to change its contents.
|
||||
struct timeval *get_duration_to_next_timer_expiration();
|
||||
|
||||
// Trigger all expired timers, and reschedule them if they are periodic timers
|
||||
void handle_expired_timers();
|
||||
|
||||
// Time helper functions.
|
||||
|
||||
// Returns -1 if t1 < t2, 0 if t1 == t2, 1 if t1 > t2
|
||||
gint compare_timespecs(const struct timespec *t1, const struct timespec *t2);
|
||||
|
||||
@@ -69,6 +76,7 @@ struct timespec add_msec_to_timespec(struct timespec ts, int msec);
|
||||
// At the first call returns zero.
|
||||
double profiling_get_time();
|
||||
|
||||
// Get current time in seconds, from an unspecified origin.
|
||||
double get_time();
|
||||
|
||||
#endif // TIMER_H
|
||||
|
||||
@@ -49,8 +49,9 @@ char *addr2name(void *func)
|
||||
free(strings);
|
||||
return result;
|
||||
#else
|
||||
char *result = (char*) calloc(32, 1);
|
||||
sprintf(result, "%p", func);
|
||||
const size_t buf_size = 32;
|
||||
char *result = (char*) calloc(buf_size, 1);
|
||||
snprintf(result, buf_size, "%p", func);
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
@@ -24,11 +24,17 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <Imlib2.h>
|
||||
#include <cairo.h>
|
||||
#include <cairo-xlib.h>
|
||||
|
||||
#include <X11/extensions/XShm.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "window.h"
|
||||
#include "server.h"
|
||||
@@ -157,7 +163,8 @@ int get_window_desktop(Window win)
|
||||
|
||||
if (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);
|
||||
return best_match;
|
||||
}
|
||||
@@ -190,15 +197,18 @@ int get_window_monitor(Window win)
|
||||
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;
|
||||
unsigned ww, wh, bw, bh;
|
||||
Window src;
|
||||
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);
|
||||
if (!XTranslateCoordinates(server.display, win, server.root_win, 0, 0, x, y, &src))
|
||||
return FALSE;
|
||||
if (!XGetGeometry(server.display, win, &src, &dummy_int, &dummy_int, &ww, &wh, &bw, &bh))
|
||||
return FALSE;
|
||||
*w = ww + bw;
|
||||
*h = wh + bh;
|
||||
*h = wh + bw;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean window_is_iconified(Window win)
|
||||
@@ -352,3 +362,251 @@ char *get_window_name(Window win)
|
||||
XFree(text_property.value);
|
||||
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 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_shade(Window win);
|
||||
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);
|
||||
|
||||
char *get_window_name(Window win);
|
||||
cairo_surface_t *get_window_thumbnail(Window win, int size);
|
||||
|
||||
#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()
|
||||
@@ -10,6 +10,7 @@ sys.setdefaultencoding('utf8')
|
||||
import argparse
|
||||
import datetime
|
||||
import os
|
||||
import re
|
||||
import signal
|
||||
import subprocess
|
||||
import time
|
||||
@@ -39,6 +40,10 @@ def print_err(*args, **kwargs):
|
||||
print(*args, file=sys.stderr, **kwargs)
|
||||
|
||||
|
||||
def clear_ansi_codes(s):
|
||||
return re.sub(r"\x1B\[[0-9;]*[a-zA-Z]", "", s)
|
||||
|
||||
|
||||
def run(cmd, output=False):
|
||||
return subprocess.Popen(cmd,
|
||||
stdin=devnull,
|
||||
@@ -160,7 +165,7 @@ def test(tint2path, config, use_asan):
|
||||
start_wm()
|
||||
sleep(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)
|
||||
if tint2.poll() != None:
|
||||
raise RuntimeError("tint2 failed to start")
|
||||
@@ -188,6 +193,7 @@ def test(tint2path, config, use_asan):
|
||||
mem, mem_detail = get_mem_usage(tint2.pid)
|
||||
stop(tint2)
|
||||
out, _ = tint2.communicate()
|
||||
out = clear_ansi_codes(out)
|
||||
exitcode = tint2.returncode
|
||||
if exitcode != 0 and exitcode != 23:
|
||||
print("tint2 crashed with exit code {0}!".format(exitcode))
|
||||
@@ -214,7 +220,7 @@ def test(tint2path, config, use_asan):
|
||||
if use_asan:
|
||||
fps_status = ok
|
||||
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)
|
||||
if mem_status != ok or leak_status != ok or fps_status != ok:
|
||||
print("Output:")
|
||||
@@ -222,6 +228,41 @@ def test(tint2path, config, use_asan):
|
||||
stop_xvfb()
|
||||
|
||||
|
||||
def run_unit_tests(tint2path, use_asan):
|
||||
print("# Unit tests", "(ASAN on)" if use_asan else "")
|
||||
start_xvfb()
|
||||
sleep(1)
|
||||
start_xsettings()
|
||||
start_wm()
|
||||
sleep(1)
|
||||
compton = start_compositor()
|
||||
sleep(1)
|
||||
os.environ["DEBUG_FPS"] = "1"
|
||||
os.environ["ASAN_OPTIONS"] = "detect_leaks=1:exitcode=0"
|
||||
tint2 = run([tint2path, "--test-verbose"], True)
|
||||
time_limit = time.time() + 60
|
||||
while tint2.poll() == None:
|
||||
if time.time() < time_limit:
|
||||
time.sleep(1)
|
||||
continue
|
||||
tint2.stop()
|
||||
out, _ = tint2.communicate()
|
||||
out = clear_ansi_codes(out)
|
||||
exitcode = tint2.returncode
|
||||
if exitcode != 0 and exitcode != 23:
|
||||
print("tint2 crashed with exit code {0}!".format(exitcode))
|
||||
print("Output:")
|
||||
print("```\n" + out.strip() + "\n```")
|
||||
return
|
||||
if "tests succeeded" in out:
|
||||
num_tests = [line for line in out.split("\n") if "tint2: Running" in line][0]
|
||||
print("All {0} tests succeeded.".format(num_tests))
|
||||
return
|
||||
if "tests failed" in out:
|
||||
print("```\n" + out.strip() + "\n```")
|
||||
stop_xvfb()
|
||||
|
||||
|
||||
def show_timestamp():
|
||||
utc_datetime = datetime.datetime.utcnow()
|
||||
print("Last updated:", utc_datetime.strftime("%Y-%m-%d %H:%M UTC"))
|
||||
@@ -285,6 +326,29 @@ def compile_and_report(src_dir, use_asan):
|
||||
print("Status: Succeeded in %.1f seconds" % (duration,), ok)
|
||||
|
||||
|
||||
def compile_remotely_and_report(host):
|
||||
print_err("Compiling on {0}...".format(host))
|
||||
print("# Compilation on {0}".format(host))
|
||||
start = time.time()
|
||||
c = run("ssh worker@{0} 'cd tint2 && git pull && mkdir -p build && rm -rf build && mkdir -p build && cd build && cmake .. && make && ./tint2 --version'".format(host), True)
|
||||
out, _ = c.communicate()
|
||||
duration = time.time() - start
|
||||
if c.returncode != 0:
|
||||
print("Status: Failed!", error)
|
||||
print("Output:")
|
||||
print("```\n" + out.strip() + "\n```")
|
||||
warnings = [ line for line in out.split("\n") if "warning:" in line and ".so." not in line.split(":", 1)[0] ]
|
||||
if warnings:
|
||||
print("Status: Succeeded with warnings!", warning)
|
||||
print("Warnings:")
|
||||
print("```", end="")
|
||||
for line in warnings:
|
||||
print(line, end="")
|
||||
print("```", end="")
|
||||
else:
|
||||
print("Status: Succeeded in %.1f seconds" % (duration,), ok)
|
||||
|
||||
|
||||
def run_test(config, index, use_asan):
|
||||
print_err("Running test", index, "for config", config)
|
||||
print("# Test", index, "(ASAN on)" if use_asan else "")
|
||||
@@ -350,8 +414,11 @@ def main():
|
||||
show_timestamp()
|
||||
show_git_info(args.src_dir)
|
||||
show_system_info()
|
||||
compile_remotely_and_report("FreeBSD")
|
||||
compile_remotely_and_report("OpenBSD")
|
||||
for use_asan in [True, False]:
|
||||
compile_and_report(args.src_dir, use_asan)
|
||||
run_unit_tests("./build/tint2", use_asan)
|
||||
run_tests(use_asan)
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
export PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
@@ -11,7 +13,9 @@ exec 2>&1
|
||||
cd ~/tint2
|
||||
git reset --hard
|
||||
git pull
|
||||
|
||||
last=$(cat .last-reg-test || true)
|
||||
curr=$(git rev-parse --verify HEAD)
|
||||
[ "$last" == "$curr" ] && exit 0
|
||||
|
||||
cd ~/tint2.wiki
|
||||
git reset --hard
|
||||
@@ -27,3 +31,6 @@ cd ~/tint2.wiki
|
||||
git add tests.md
|
||||
git commit -am 'Update test results'
|
||||
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
|
||||
# full documentation of the configuration options.
|
||||
#-------------------------------------
|
||||
@@ -15,6 +15,8 @@ color_stop = 70.000000 #1c1c1c 80
|
||||
rounded = 0
|
||||
border_width = 1
|
||||
border_sides = T
|
||||
border_content_tint_weight = 0
|
||||
background_content_tint_weight = 0
|
||||
background_color = #000000 80
|
||||
border_color = #333333 80
|
||||
gradient_id = 1
|
||||
@@ -27,28 +29,34 @@ border_color_pressed = #555555 80
|
||||
rounded = 0
|
||||
border_width = 2
|
||||
border_sides = B
|
||||
border_content_tint_weight = 100
|
||||
background_content_tint_weight = 25
|
||||
background_color = #777777 0
|
||||
border_color = #777777 0
|
||||
background_color_hover = #777777 21
|
||||
border_color = #777777 100
|
||||
background_color_hover = #464646 100
|
||||
border_color_hover = #cccccc 30
|
||||
background_color_pressed = #5a5a5a 21
|
||||
background_color_pressed = #1e1e1e 100
|
||||
border_color_pressed = #777777 30
|
||||
|
||||
# Background 3: Active task
|
||||
rounded = 0
|
||||
border_width = 2
|
||||
border_sides = B
|
||||
background_color = #ffffff 0
|
||||
border_color = #4d75ff 100
|
||||
background_color_hover = #ffffff 21
|
||||
border_color_hover = #4c73ff 100
|
||||
background_color_pressed = #989898 21
|
||||
border_color_pressed = #4c73ff 100
|
||||
border_content_tint_weight = 100
|
||||
background_content_tint_weight = 100
|
||||
background_color = #ffffff 100
|
||||
border_color = #d9d9d9 100
|
||||
background_color_hover = #ffffff 73
|
||||
border_color_hover = #d9d9d9 100
|
||||
background_color_pressed = #989898 73
|
||||
border_color_pressed = #d9d9d9 100
|
||||
|
||||
# Background 4: Urgent task
|
||||
rounded = 0
|
||||
border_width = 0
|
||||
border_sides = TBLR
|
||||
border_content_tint_weight = 0
|
||||
background_content_tint_weight = 0
|
||||
background_color = #aa4400 100
|
||||
border_color = #aa7733 100
|
||||
background_color_hover = #aa4400 100
|
||||
@@ -60,6 +68,8 @@ border_color_pressed = #aa7733 100
|
||||
rounded = 2
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
border_content_tint_weight = 0
|
||||
background_content_tint_weight = 0
|
||||
background_color = #ffffaa 100
|
||||
border_color = #999999 100
|
||||
background_color_hover = #ffffaa 100
|
||||
@@ -71,6 +81,8 @@ border_color_pressed = #999999 100
|
||||
rounded = 0
|
||||
border_width = 2
|
||||
border_sides = B
|
||||
border_content_tint_weight = 0
|
||||
background_content_tint_weight = 0
|
||||
background_color = #777777 0
|
||||
border_color = #777777 0
|
||||
background_color_hover = #bdbdbd 21
|
||||
@@ -82,12 +94,14 @@ border_color_pressed = #777777 100
|
||||
rounded = 0
|
||||
border_width = 2
|
||||
border_sides = B
|
||||
border_content_tint_weight = 0
|
||||
background_content_tint_weight = 0
|
||||
background_color = #ffffff 21
|
||||
border_color = #4c73ff 100
|
||||
border_color = #d9d9d9 100
|
||||
background_color_hover = #ffffff 21
|
||||
border_color_hover = #4d73ff 100
|
||||
border_color_hover = #d9d9d9 100
|
||||
background_color_pressed = #a9a9a9 21
|
||||
border_color_pressed = #4d73ff 100
|
||||
border_color_pressed = #d9d9d9 100
|
||||
|
||||
#-------------------------------------
|
||||
# Panel
|
||||
@@ -146,6 +160,8 @@ task_maximum_size = 120 35
|
||||
task_padding = 4 3 4
|
||||
task_font = Sans 8
|
||||
task_tooltip = 1
|
||||
task_thumbnail = 0
|
||||
task_thumbnail_size = 210
|
||||
task_font_color = #c6c6c6 100
|
||||
task_active_font_color = #ffffff 100
|
||||
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
|
||||
# full documentation of the configuration options.
|
||||
#-------------------------------------
|
||||
# Gradients
|
||||
#-------------------------------------
|
||||
# Backgrounds
|
||||
# Background 1: Panel
|
||||
rounded = 0
|
||||
border_width = 0
|
||||
border_sides = TBLR
|
||||
background_color = #000000 60
|
||||
border_color = #000000 30
|
||||
background_color_hover = #000000 60
|
||||
@@ -16,6 +19,7 @@ border_color_pressed = #000000 30
|
||||
# Background 2: Default task, Iconified task
|
||||
rounded = 4
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #777777 20
|
||||
border_color = #777777 30
|
||||
background_color_hover = #aaaaaa 22
|
||||
@@ -26,6 +30,7 @@ border_color_pressed = #eaeaea 44
|
||||
# Background 3: Active task
|
||||
rounded = 4
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #777777 20
|
||||
border_color = #ffffff 40
|
||||
background_color_hover = #aaaaaa 22
|
||||
@@ -36,6 +41,7 @@ border_color_pressed = #eaeaea 44
|
||||
# Background 4: Urgent task
|
||||
rounded = 4
|
||||
border_width = 1
|
||||
border_sides = TBLR
|
||||
background_color = #aa4400 100
|
||||
border_color = #aa7733 100
|
||||
background_color_hover = #cc7700 100
|
||||
@@ -46,8 +52,9 @@ border_color_pressed = #aa7733 100
|
||||
# Background 5: Tooltip
|
||||
rounded = 1
|
||||
border_width = 1
|
||||
background_color = #ffffaa 100
|
||||
border_color = #000000 100
|
||||
border_sides = TBLR
|
||||
background_color = #222222 100
|
||||
border_color = #333333 100
|
||||
background_color_hover = #ffffaa 100
|
||||
border_color_hover = #000000 100
|
||||
background_color_pressed = #ffffaa 100
|
||||
@@ -65,7 +72,7 @@ panel_dock = 0
|
||||
panel_position = bottom center horizontal
|
||||
panel_layer = top
|
||||
panel_monitor = all
|
||||
primary_monitor_first = 0
|
||||
panel_shrink = 0
|
||||
autohide = 0
|
||||
autohide_show_timeout = 0
|
||||
autohide_hide_timeout = 0.5
|
||||
@@ -81,12 +88,14 @@ mouse_pressed_icon_asb = 100 0 0
|
||||
#-------------------------------------
|
||||
# Taskbar
|
||||
taskbar_mode = single_desktop
|
||||
taskbar_hide_if_empty = 0
|
||||
taskbar_padding = 0 0 2
|
||||
taskbar_background_id = 0
|
||||
taskbar_active_background_id = 0
|
||||
taskbar_name = 1
|
||||
taskbar_hide_inactive_tasks = 0
|
||||
taskbar_hide_different_monitor = 0
|
||||
taskbar_hide_different_desktop = 0
|
||||
taskbar_always_show_all_desktop_tasks = 0
|
||||
taskbar_name_padding = 4 2
|
||||
taskbar_name_background_id = 0
|
||||
@@ -106,6 +115,8 @@ urgent_nb_of_blink = 100000
|
||||
task_maximum_size = 150 35
|
||||
task_padding = 2 2 4
|
||||
task_tooltip = 1
|
||||
task_thumbnail = 0
|
||||
task_thumbnail_size = 210
|
||||
task_font_color = #ffffff 100
|
||||
task_background_id = 2
|
||||
task_active_background_id = 3
|
||||
@@ -125,6 +136,7 @@ systray_sort = ascending
|
||||
systray_icon_size = 24
|
||||
systray_icon_asb = 100 0 0
|
||||
systray_monitor = 1
|
||||
systray_name_filter =
|
||||
|
||||
#-------------------------------------
|
||||
# Launcher
|
||||
@@ -164,7 +176,10 @@ clock_dwheel_command =
|
||||
battery_tooltip = 1
|
||||
battery_low_status = 10
|
||||
battery_low_cmd = notify-send "battery low"
|
||||
battery_full_cmd =
|
||||
battery_font_color = #ffffff 100
|
||||
bat1_format =
|
||||
bat2_format =
|
||||
battery_padding = 1 0
|
||||
battery_background_id = 0
|
||||
battery_hide = 101
|
||||
@@ -180,7 +195,7 @@ ac_disconnected_cmd =
|
||||
# Tooltip
|
||||
tooltip_show_timeout = 0.5
|
||||
tooltip_hide_timeout = 0.1
|
||||
tooltip_padding = 2 2
|
||||
tooltip_padding = 4 4
|
||||
tooltip_background_id = 5
|
||||
tooltip_font_color = #222222 100
|
||||
tooltip_font_color = #dddddd 100
|
||||
|
||||
|
||||
18
tint2.config
18
tint2.config
@@ -1,8 +1,16 @@
|
||||
// ADD PREDEFINED MACROS HERE!
|
||||
#define HAVE_RSVG 1
|
||||
#define HAVE_SN 1
|
||||
#define DISABLE_BACKTRACE 1
|
||||
#define ENABLE_BATTERY 1
|
||||
#define ENABLE_UEVENT 1
|
||||
#define GETTEXT_PACKAGE
|
||||
#define HAVE_TRACING
|
||||
#define ENABLE_EXECINFO
|
||||
#define GETTEXT_PACKAGE "tint2conf"
|
||||
#define HAS_GENERIC 1
|
||||
#define HAVE_RSVG 1
|
||||
#define HAVE_SN 1
|
||||
#define HAVE_VERSION_H 1
|
||||
#define INSTALL_PREFIX "/usr/local"
|
||||
#define LOCALEDIR "/usr/local/share/locale"
|
||||
#define SN_API_NOT_YET_FROZEN
|
||||
#define _BSD_SOURCE
|
||||
#define _DEFAULT_SOURCE
|
||||
#define _POSIX_C_SOURCE=200809L
|
||||
#define _WITH_GETLINE
|
||||
|
||||
17
tint2.files
17
tint2.files
@@ -20,6 +20,9 @@ src/battery/battery.c
|
||||
src/battery/battery.h
|
||||
src/clock/clock.c
|
||||
src/clock/clock.h
|
||||
src/default_icon.c
|
||||
src/default_icon.c
|
||||
src/default_icon.h
|
||||
src/execplugin/execplugin.c
|
||||
src/execplugin/execplugin.h
|
||||
src/launcher/launcher.c
|
||||
@@ -58,6 +61,8 @@ src/util/blur.c
|
||||
src/util/blur.h
|
||||
src/util/common.c
|
||||
src/util/common.h
|
||||
src/util/strlcat.c
|
||||
src/util/strlcat.h
|
||||
src/util/timer.c
|
||||
src/util/timer.h
|
||||
src/util/window.c
|
||||
@@ -237,3 +242,15 @@ src/signals.c
|
||||
src/signals.h
|
||||
src/tracing.c
|
||||
src/tracing.h
|
||||
src/util/test.c
|
||||
src/util/test.h
|
||||
src/util/bool.h
|
||||
src/util/colors.h
|
||||
src/util/print.c
|
||||
src/util/print.h
|
||||
src/util/test.c
|
||||
src/util/test.h
|
||||
src/util/tracing.h
|
||||
src/util/tracing.c
|
||||
src/util/signals.h
|
||||
src/util/signals.c
|
||||
|
||||
@@ -1,22 +1,33 @@
|
||||
.
|
||||
./build
|
||||
./src
|
||||
./src/battery
|
||||
./src/clock
|
||||
./src/execplugin
|
||||
./src/launcher
|
||||
./src/sysmon
|
||||
./src/systray
|
||||
./src/taskbar
|
||||
./src/tint2conf
|
||||
./src/launcher
|
||||
./src/tooltip
|
||||
./src/util
|
||||
/usr/include
|
||||
/usr/include/gtk-2.0
|
||||
/usr/include/glib-2.0
|
||||
/usr/include/gdk-pixbuf-2.0
|
||||
/usr/include/cairo
|
||||
./src/execplugin
|
||||
./src/button
|
||||
./src/freespace
|
||||
./src/separator
|
||||
/usr/include/pango-1.0
|
||||
/usr/include/cairo
|
||||
/usr/include/glib-2.0
|
||||
/usr/lib/x86_64-linux-gnu/glib-2.0/include
|
||||
/usr/include/pixman-1
|
||||
/usr/include/freetype2
|
||||
/usr/include/libpng12
|
||||
/usr/include/librsvg-2.0
|
||||
/usr/include/gdk-pixbuf-2.0
|
||||
/usr/include/startup-notification-1.0
|
||||
/usr/include/gtk-2.0
|
||||
/usr/lib/x86_64-linux-gnu/gtk-2.0/include
|
||||
/usr/include/atk-1.0
|
||||
/usr/include/gio-unix-2.0
|
||||
/usr/include/harfbuzz
|
||||
/usr/include
|
||||
po
|
||||
src/tint2conf/po
|
||||
src/freespace
|
||||
|
||||
Reference in New Issue
Block a user